/// GENERATED BY testcase_gen. DO NOT MODIFY BY HAND.

// ignore_for_file: deprecated_member_use,constant_identifier_names

import 'dart:async';
import 'dart:typed_data';

import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:iris_tester/iris_tester.dart';
import 'package:iris_method_channel/iris_method_channel.dart';

import '../testcases/event_ids_mapping.dart';

void generatedTestCases(ValueGetter<IrisTester> irisTester) {
  testWidgets(
    'RtcEngineEventHandler.onJoinChannelSuccess',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onJoinChannelSuccessCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
          onJoinChannelSuccessCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int elapsed = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'elapsed': elapsed,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onJoinChannelSuccess'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onJoinChannelSuccessCompleter.isCompleted) {
              onJoinChannelSuccessCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onJoinChannelSuccessCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRejoinChannelSuccess',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRejoinChannelSuccessCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRejoinChannelSuccess: (RtcConnection connection, int elapsed) {
          onRejoinChannelSuccessCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int elapsed = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'elapsed': elapsed,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onRejoinChannelSuccess'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRejoinChannelSuccessCompleter.isCompleted) {
              onRejoinChannelSuccessCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onRejoinChannelSuccessCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onProxyConnected',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onProxyConnectedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onProxyConnected: (String channel, int uid, ProxyType proxyType,
            String localProxyIp, int elapsed) {
          onProxyConnectedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String channel = "hello";
        int uid = 5;
        ProxyType proxyType = ProxyType.noneProxyType;
        String localProxyIp = "hello";
        int elapsed = 5;

        final eventJson = {
          'channel': channel,
          'uid': uid,
          'proxyType': proxyType.value(),
          'localProxyIp': localProxyIp,
          'elapsed': elapsed,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onProxyConnected'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onProxyConnectedCompleter.isCompleted) {
              onProxyConnectedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onProxyConnectedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onError',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onErrorCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onError: (ErrorCodeType err, String msg) {
          onErrorCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        ErrorCodeType err = ErrorCodeType.errOk;
        String msg = "hello";

        final eventJson = {
          'err': err.value(),
          'msg': msg,
        };

        final eventIds = eventIdsMapping['RtcEngineEventHandler_onError'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onErrorCompleter.isCompleted) {
              onErrorCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onErrorCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onAudioQuality',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onAudioQualityCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onAudioQuality: (RtcConnection connection, int remoteUid,
            QualityType quality, int delay, int lost) {
          onAudioQualityCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        QualityType quality = QualityType.qualityUnknown;
        int delay = 5;
        int lost = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'quality': quality.value(),
          'delay': delay,
          'lost': lost,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onAudioQuality'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onAudioQualityCompleter.isCompleted) {
              onAudioQualityCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onAudioQualityCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onLastmileProbeResult',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onLastmileProbeResultCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onLastmileProbeResult: (LastmileProbeResult result) {
          onLastmileProbeResultCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        LastmileProbeResultState resultState =
            LastmileProbeResultState.lastmileProbeResultComplete;
        int uplinkReportPacketLossRate = 5;
        int uplinkReportJitter = 5;
        int uplinkReportAvailableBandwidth = 5;
        LastmileProbeOneWayResult resultUplinkReport =
            LastmileProbeOneWayResult(
          packetLossRate: uplinkReportPacketLossRate,
          jitter: uplinkReportJitter,
          availableBandwidth: uplinkReportAvailableBandwidth,
        );
        int downlinkReportPacketLossRate = 5;
        int downlinkReportJitter = 5;
        int downlinkReportAvailableBandwidth = 5;
        LastmileProbeOneWayResult resultDownlinkReport =
            LastmileProbeOneWayResult(
          packetLossRate: downlinkReportPacketLossRate,
          jitter: downlinkReportJitter,
          availableBandwidth: downlinkReportAvailableBandwidth,
        );
        int resultRtt = 5;
        LastmileProbeResult result = LastmileProbeResult(
          state: resultState,
          uplinkReport: resultUplinkReport,
          downlinkReport: resultDownlinkReport,
          rtt: resultRtt,
        );

        final eventJson = {
          'result': result.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onLastmileProbeResult'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onLastmileProbeResultCompleter.isCompleted) {
              onLastmileProbeResultCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onLastmileProbeResultCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onAudioVolumeIndication',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onAudioVolumeIndicationCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onAudioVolumeIndication: (RtcConnection connection, List speakers,
            int speakerNumber, int totalVolume) {
          onAudioVolumeIndicationCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        final List<AudioVolumeInfo> speakers = () {
          int speakersItemUid = 5;
          int speakersItemVolume = 5;
          int speakersItemVad = 5;
          double speakersItemVoicePitch = 5.0;
          AudioVolumeInfo speakersItem = AudioVolumeInfo(
            uid: speakersItemUid,
            volume: speakersItemVolume,
            vad: speakersItemVad,
            voicePitch: speakersItemVoicePitch,
          );

          return List.filled(5, speakersItem);
        }();

        int speakerNumber = 5;
        int totalVolume = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'speakers': speakers,
          'speakerNumber': speakerNumber,
          'totalVolume': totalVolume,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onAudioVolumeIndication'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onAudioVolumeIndicationCompleter.isCompleted) {
              onAudioVolumeIndicationCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onAudioVolumeIndicationCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onLeaveChannel',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onLeaveChannelCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onLeaveChannel: (RtcConnection connection, RtcStats stats) {
          onLeaveChannelCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int statsDuration = 5;
        int statsTxBytes = 5;
        int statsRxBytes = 5;
        int statsTxAudioBytes = 5;
        int statsTxVideoBytes = 5;
        int statsRxAudioBytes = 5;
        int statsRxVideoBytes = 5;
        int statsTxKBitRate = 5;
        int statsRxKBitRate = 5;
        int statsRxAudioKBitRate = 5;
        int statsTxAudioKBitRate = 5;
        int statsRxVideoKBitRate = 5;
        int statsTxVideoKBitRate = 5;
        int statsLastmileDelay = 5;
        int statsUserCount = 5;
        double statsCpuAppUsage = 5.0;
        double statsCpuTotalUsage = 5.0;
        int statsGatewayRtt = 5;
        double statsMemoryAppUsageRatio = 5.0;
        double statsMemoryTotalUsageRatio = 5.0;
        int statsMemoryAppUsageInKbytes = 5;
        int statsConnectTimeMs = 5;
        int statsFirstAudioPacketDuration = 5;
        int statsFirstVideoPacketDuration = 5;
        int statsFirstVideoKeyFramePacketDuration = 5;
        int statsPacketsBeforeFirstKeyFramePacket = 5;
        int statsFirstAudioPacketDurationAfterUnmute = 5;
        int statsFirstVideoPacketDurationAfterUnmute = 5;
        int statsFirstVideoKeyFramePacketDurationAfterUnmute = 5;
        int statsFirstVideoKeyFrameDecodedDurationAfterUnmute = 5;
        int statsFirstVideoKeyFrameRenderedDurationAfterUnmute = 5;
        int statsTxPacketLossRate = 5;
        int statsRxPacketLossRate = 5;
        RtcStats stats = RtcStats(
          duration: statsDuration,
          txBytes: statsTxBytes,
          rxBytes: statsRxBytes,
          txAudioBytes: statsTxAudioBytes,
          txVideoBytes: statsTxVideoBytes,
          rxAudioBytes: statsRxAudioBytes,
          rxVideoBytes: statsRxVideoBytes,
          txKBitRate: statsTxKBitRate,
          rxKBitRate: statsRxKBitRate,
          rxAudioKBitRate: statsRxAudioKBitRate,
          txAudioKBitRate: statsTxAudioKBitRate,
          rxVideoKBitRate: statsRxVideoKBitRate,
          txVideoKBitRate: statsTxVideoKBitRate,
          lastmileDelay: statsLastmileDelay,
          userCount: statsUserCount,
          cpuAppUsage: statsCpuAppUsage,
          cpuTotalUsage: statsCpuTotalUsage,
          gatewayRtt: statsGatewayRtt,
          memoryAppUsageRatio: statsMemoryAppUsageRatio,
          memoryTotalUsageRatio: statsMemoryTotalUsageRatio,
          memoryAppUsageInKbytes: statsMemoryAppUsageInKbytes,
          connectTimeMs: statsConnectTimeMs,
          firstAudioPacketDuration: statsFirstAudioPacketDuration,
          firstVideoPacketDuration: statsFirstVideoPacketDuration,
          firstVideoKeyFramePacketDuration:
              statsFirstVideoKeyFramePacketDuration,
          packetsBeforeFirstKeyFramePacket:
              statsPacketsBeforeFirstKeyFramePacket,
          firstAudioPacketDurationAfterUnmute:
              statsFirstAudioPacketDurationAfterUnmute,
          firstVideoPacketDurationAfterUnmute:
              statsFirstVideoPacketDurationAfterUnmute,
          firstVideoKeyFramePacketDurationAfterUnmute:
              statsFirstVideoKeyFramePacketDurationAfterUnmute,
          firstVideoKeyFrameDecodedDurationAfterUnmute:
              statsFirstVideoKeyFrameDecodedDurationAfterUnmute,
          firstVideoKeyFrameRenderedDurationAfterUnmute:
              statsFirstVideoKeyFrameRenderedDurationAfterUnmute,
          txPacketLossRate: statsTxPacketLossRate,
          rxPacketLossRate: statsRxPacketLossRate,
        );

        final eventJson = {
          'connection': connection.toJson(),
          'stats': stats.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onLeaveChannel'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onLeaveChannelCompleter.isCompleted) {
              onLeaveChannelCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onLeaveChannelCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRtcStats',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRtcStatsCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRtcStats: (RtcConnection connection, RtcStats stats) {
          onRtcStatsCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int statsDuration = 5;
        int statsTxBytes = 5;
        int statsRxBytes = 5;
        int statsTxAudioBytes = 5;
        int statsTxVideoBytes = 5;
        int statsRxAudioBytes = 5;
        int statsRxVideoBytes = 5;
        int statsTxKBitRate = 5;
        int statsRxKBitRate = 5;
        int statsRxAudioKBitRate = 5;
        int statsTxAudioKBitRate = 5;
        int statsRxVideoKBitRate = 5;
        int statsTxVideoKBitRate = 5;
        int statsLastmileDelay = 5;
        int statsUserCount = 5;
        double statsCpuAppUsage = 5.0;
        double statsCpuTotalUsage = 5.0;
        int statsGatewayRtt = 5;
        double statsMemoryAppUsageRatio = 5.0;
        double statsMemoryTotalUsageRatio = 5.0;
        int statsMemoryAppUsageInKbytes = 5;
        int statsConnectTimeMs = 5;
        int statsFirstAudioPacketDuration = 5;
        int statsFirstVideoPacketDuration = 5;
        int statsFirstVideoKeyFramePacketDuration = 5;
        int statsPacketsBeforeFirstKeyFramePacket = 5;
        int statsFirstAudioPacketDurationAfterUnmute = 5;
        int statsFirstVideoPacketDurationAfterUnmute = 5;
        int statsFirstVideoKeyFramePacketDurationAfterUnmute = 5;
        int statsFirstVideoKeyFrameDecodedDurationAfterUnmute = 5;
        int statsFirstVideoKeyFrameRenderedDurationAfterUnmute = 5;
        int statsTxPacketLossRate = 5;
        int statsRxPacketLossRate = 5;
        RtcStats stats = RtcStats(
          duration: statsDuration,
          txBytes: statsTxBytes,
          rxBytes: statsRxBytes,
          txAudioBytes: statsTxAudioBytes,
          txVideoBytes: statsTxVideoBytes,
          rxAudioBytes: statsRxAudioBytes,
          rxVideoBytes: statsRxVideoBytes,
          txKBitRate: statsTxKBitRate,
          rxKBitRate: statsRxKBitRate,
          rxAudioKBitRate: statsRxAudioKBitRate,
          txAudioKBitRate: statsTxAudioKBitRate,
          rxVideoKBitRate: statsRxVideoKBitRate,
          txVideoKBitRate: statsTxVideoKBitRate,
          lastmileDelay: statsLastmileDelay,
          userCount: statsUserCount,
          cpuAppUsage: statsCpuAppUsage,
          cpuTotalUsage: statsCpuTotalUsage,
          gatewayRtt: statsGatewayRtt,
          memoryAppUsageRatio: statsMemoryAppUsageRatio,
          memoryTotalUsageRatio: statsMemoryTotalUsageRatio,
          memoryAppUsageInKbytes: statsMemoryAppUsageInKbytes,
          connectTimeMs: statsConnectTimeMs,
          firstAudioPacketDuration: statsFirstAudioPacketDuration,
          firstVideoPacketDuration: statsFirstVideoPacketDuration,
          firstVideoKeyFramePacketDuration:
              statsFirstVideoKeyFramePacketDuration,
          packetsBeforeFirstKeyFramePacket:
              statsPacketsBeforeFirstKeyFramePacket,
          firstAudioPacketDurationAfterUnmute:
              statsFirstAudioPacketDurationAfterUnmute,
          firstVideoPacketDurationAfterUnmute:
              statsFirstVideoPacketDurationAfterUnmute,
          firstVideoKeyFramePacketDurationAfterUnmute:
              statsFirstVideoKeyFramePacketDurationAfterUnmute,
          firstVideoKeyFrameDecodedDurationAfterUnmute:
              statsFirstVideoKeyFrameDecodedDurationAfterUnmute,
          firstVideoKeyFrameRenderedDurationAfterUnmute:
              statsFirstVideoKeyFrameRenderedDurationAfterUnmute,
          txPacketLossRate: statsTxPacketLossRate,
          rxPacketLossRate: statsRxPacketLossRate,
        );

        final eventJson = {
          'connection': connection.toJson(),
          'stats': stats.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onRtcStats'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRtcStatsCompleter.isCompleted) {
              onRtcStatsCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onRtcStatsCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onAudioDeviceStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onAudioDeviceStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onAudioDeviceStateChanged: (String deviceId, MediaDeviceType deviceType,
            MediaDeviceStateType deviceState) {
          onAudioDeviceStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String deviceId = "hello";
        MediaDeviceType deviceType = MediaDeviceType.unknownAudioDevice;
        MediaDeviceStateType deviceState =
            MediaDeviceStateType.mediaDeviceStateIdle;

        final eventJson = {
          'deviceId': deviceId,
          'deviceType': deviceType.value(),
          'deviceState': deviceState.value(),
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onAudioDeviceStateChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onAudioDeviceStateChangedCompleter.isCompleted) {
              onAudioDeviceStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onAudioDeviceStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onAudioMixingPositionChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onAudioMixingPositionChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onAudioMixingPositionChanged: (int position) {
          onAudioMixingPositionChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        int position = 5;

        final eventJson = {
          'position': position,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onAudioMixingPositionChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onAudioMixingPositionChangedCompleter.isCompleted) {
              onAudioMixingPositionChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onAudioMixingPositionChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onAudioMixingFinished',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onAudioMixingFinishedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onAudioMixingFinished: () {
          onAudioMixingFinishedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        final eventJson = {};

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onAudioMixingFinished'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onAudioMixingFinishedCompleter.isCompleted) {
              onAudioMixingFinishedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onAudioMixingFinishedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onAudioEffectFinished',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onAudioEffectFinishedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onAudioEffectFinished: (int soundId) {
          onAudioEffectFinishedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        int soundId = 5;

        final eventJson = {
          'soundId': soundId,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onAudioEffectFinished'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onAudioEffectFinishedCompleter.isCompleted) {
              onAudioEffectFinishedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onAudioEffectFinishedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onVideoDeviceStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onVideoDeviceStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onVideoDeviceStateChanged: (String deviceId, MediaDeviceType deviceType,
            MediaDeviceStateType deviceState) {
          onVideoDeviceStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String deviceId = "hello";
        MediaDeviceType deviceType = MediaDeviceType.unknownAudioDevice;
        MediaDeviceStateType deviceState =
            MediaDeviceStateType.mediaDeviceStateIdle;

        final eventJson = {
          'deviceId': deviceId,
          'deviceType': deviceType.value(),
          'deviceState': deviceState.value(),
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onVideoDeviceStateChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onVideoDeviceStateChangedCompleter.isCompleted) {
              onVideoDeviceStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onVideoDeviceStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onNetworkQuality',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onNetworkQualityCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onNetworkQuality: (RtcConnection connection, int remoteUid,
            QualityType txQuality, QualityType rxQuality) {
          onNetworkQualityCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        QualityType txQuality = QualityType.qualityUnknown;
        QualityType rxQuality = QualityType.qualityUnknown;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'txQuality': txQuality.value(),
          'rxQuality': rxQuality.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onNetworkQuality'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onNetworkQualityCompleter.isCompleted) {
              onNetworkQualityCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onNetworkQualityCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onIntraRequestReceived',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onIntraRequestReceivedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onIntraRequestReceived: (RtcConnection connection) {
          onIntraRequestReceivedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );

        final eventJson = {
          'connection': connection.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onIntraRequestReceived'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onIntraRequestReceivedCompleter.isCompleted) {
              onIntraRequestReceivedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onIntraRequestReceivedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onUplinkNetworkInfoUpdated',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onUplinkNetworkInfoUpdatedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onUplinkNetworkInfoUpdated: (UplinkNetworkInfo info) {
          onUplinkNetworkInfoUpdatedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        int infoVideoEncoderTargetBitrateBps = 5;
        UplinkNetworkInfo info = UplinkNetworkInfo(
          videoEncoderTargetBitrateBps: infoVideoEncoderTargetBitrateBps,
        );

        final eventJson = {
          'info': info.toJson(),
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onUplinkNetworkInfoUpdated'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onUplinkNetworkInfoUpdatedCompleter.isCompleted) {
              onUplinkNetworkInfoUpdatedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onUplinkNetworkInfoUpdatedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onLastmileQuality',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onLastmileQualityCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onLastmileQuality: (QualityType quality) {
          onLastmileQualityCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        QualityType quality = QualityType.qualityUnknown;

        final eventJson = {
          'quality': quality.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onLastmileQuality'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onLastmileQualityCompleter.isCompleted) {
              onLastmileQualityCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onLastmileQualityCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onFirstLocalVideoFrame',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onFirstLocalVideoFrameCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onFirstLocalVideoFrame:
            (VideoSourceType source, int width, int height, int elapsed) {
          onFirstLocalVideoFrameCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        VideoSourceType source = VideoSourceType.videoSourceCameraPrimary;
        int width = 5;
        int height = 5;
        int elapsed = 5;

        final eventJson = {
          'source': source.value(),
          'width': width,
          'height': height,
          'elapsed': elapsed,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onFirstLocalVideoFrame'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onFirstLocalVideoFrameCompleter.isCompleted) {
              onFirstLocalVideoFrameCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onFirstLocalVideoFrameCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onFirstLocalVideoFramePublished',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onFirstLocalVideoFramePublishedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onFirstLocalVideoFramePublished:
            (RtcConnection connection, int elapsed) {
          onFirstLocalVideoFramePublishedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int elapsed = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'elapsed': elapsed,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onFirstLocalVideoFramePublished'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onFirstLocalVideoFramePublishedCompleter.isCompleted) {
              onFirstLocalVideoFramePublishedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onFirstLocalVideoFramePublishedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onFirstRemoteVideoDecoded',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onFirstRemoteVideoDecodedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onFirstRemoteVideoDecoded: (RtcConnection connection, int remoteUid,
            int width, int height, int elapsed) {
          onFirstRemoteVideoDecodedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        int width = 5;
        int height = 5;
        int elapsed = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'width': width,
          'height': height,
          'elapsed': elapsed,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onFirstRemoteVideoDecoded'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onFirstRemoteVideoDecodedCompleter.isCompleted) {
              onFirstRemoteVideoDecodedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onFirstRemoteVideoDecodedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onVideoSizeChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onVideoSizeChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onVideoSizeChanged: (RtcConnection connection,
            VideoSourceType sourceType,
            int uid,
            int width,
            int height,
            int rotation) {
          onVideoSizeChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        VideoSourceType sourceType = VideoSourceType.videoSourceCameraPrimary;
        int uid = 5;
        int width = 5;
        int height = 5;
        int rotation = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'sourceType': sourceType.value(),
          'uid': uid,
          'width': width,
          'height': height,
          'rotation': rotation,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onVideoSizeChanged'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onVideoSizeChangedCompleter.isCompleted) {
              onVideoSizeChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onVideoSizeChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onLocalVideoStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onLocalVideoStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onLocalVideoStateChanged: (VideoSourceType source,
            LocalVideoStreamState state, LocalVideoStreamReason reason) {
          onLocalVideoStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        VideoSourceType source = VideoSourceType.videoSourceCameraPrimary;
        LocalVideoStreamState state =
            LocalVideoStreamState.localVideoStreamStateStopped;
        LocalVideoStreamReason reason =
            LocalVideoStreamReason.localVideoStreamReasonOk;

        final eventJson = {
          'source': source.value(),
          'state': state.value(),
          'reason': reason.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onLocalVideoStateChanged'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onLocalVideoStateChangedCompleter.isCompleted) {
              onLocalVideoStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onLocalVideoStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRemoteVideoStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRemoteVideoStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRemoteVideoStateChanged: (RtcConnection connection,
            int remoteUid,
            RemoteVideoState state,
            RemoteVideoStateReason reason,
            int elapsed) {
          onRemoteVideoStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        RemoteVideoState state = RemoteVideoState.remoteVideoStateStopped;
        RemoteVideoStateReason reason =
            RemoteVideoStateReason.remoteVideoStateReasonInternal;
        int elapsed = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'state': state.value(),
          'reason': reason.value(),
          'elapsed': elapsed,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onRemoteVideoStateChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRemoteVideoStateChangedCompleter.isCompleted) {
              onRemoteVideoStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onRemoteVideoStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onFirstRemoteVideoFrame',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onFirstRemoteVideoFrameCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onFirstRemoteVideoFrame: (RtcConnection connection, int remoteUid,
            int width, int height, int elapsed) {
          onFirstRemoteVideoFrameCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        int width = 5;
        int height = 5;
        int elapsed = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'width': width,
          'height': height,
          'elapsed': elapsed,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onFirstRemoteVideoFrame'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onFirstRemoteVideoFrameCompleter.isCompleted) {
              onFirstRemoteVideoFrameCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onFirstRemoteVideoFrameCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onUserJoined',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onUserJoinedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
          onUserJoinedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        int elapsed = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'elapsed': elapsed,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onUserJoined'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onUserJoinedCompleter.isCompleted) {
              onUserJoinedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onUserJoinedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onUserOffline',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onUserOfflineCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onUserOffline: (RtcConnection connection, int remoteUid,
            UserOfflineReasonType reason) {
          onUserOfflineCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        UserOfflineReasonType reason = UserOfflineReasonType.userOfflineQuit;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'reason': reason.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onUserOffline'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onUserOfflineCompleter.isCompleted) {
              onUserOfflineCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onUserOfflineCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onUserMuteAudio',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onUserMuteAudioCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onUserMuteAudio: (RtcConnection connection, int remoteUid, bool muted) {
          onUserMuteAudioCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        bool muted = true;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'muted': muted,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onUserMuteAudio'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onUserMuteAudioCompleter.isCompleted) {
              onUserMuteAudioCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onUserMuteAudioCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onUserMuteVideo',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onUserMuteVideoCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onUserMuteVideo: (RtcConnection connection, int remoteUid, bool muted) {
          onUserMuteVideoCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        bool muted = true;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'muted': muted,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onUserMuteVideo'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onUserMuteVideoCompleter.isCompleted) {
              onUserMuteVideoCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onUserMuteVideoCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onUserEnableVideo',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onUserEnableVideoCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onUserEnableVideo:
            (RtcConnection connection, int remoteUid, bool enabled) {
          onUserEnableVideoCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        bool enabled = true;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'enabled': enabled,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onUserEnableVideo'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onUserEnableVideoCompleter.isCompleted) {
              onUserEnableVideoCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onUserEnableVideoCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onUserStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onUserStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onUserStateChanged:
            (RtcConnection connection, int remoteUid, int state) {
          onUserStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        int state = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'state': state,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onUserStateChanged'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onUserStateChangedCompleter.isCompleted) {
              onUserStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onUserStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onUserEnableLocalVideo',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onUserEnableLocalVideoCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onUserEnableLocalVideo:
            (RtcConnection connection, int remoteUid, bool enabled) {
          onUserEnableLocalVideoCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        bool enabled = true;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'enabled': enabled,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onUserEnableLocalVideo'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onUserEnableLocalVideoCompleter.isCompleted) {
              onUserEnableLocalVideoCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onUserEnableLocalVideoCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRemoteAudioStats',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRemoteAudioStatsCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRemoteAudioStats: (RtcConnection connection, RemoteAudioStats stats) {
          onRemoteAudioStatsCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int statsUid = 5;
        int statsQuality = 5;
        int statsNetworkTransportDelay = 5;
        int statsJitterBufferDelay = 5;
        int statsAudioLossRate = 5;
        int statsNumChannels = 5;
        int statsReceivedSampleRate = 5;
        int statsReceivedBitrate = 5;
        int statsTotalFrozenTime = 5;
        int statsFrozenRate = 5;
        int statsMosValue = 5;
        int statsFrozenRateByCustomPlcCount = 5;
        int statsPlcCount = 5;
        int statsTotalActiveTime = 5;
        int statsPublishDuration = 5;
        int statsQoeQuality = 5;
        int statsQualityChangedReason = 5;
        int statsRxAudioBytes = 5;
        int statsE2eDelay = 5;
        RemoteAudioStats stats = RemoteAudioStats(
          uid: statsUid,
          quality: statsQuality,
          networkTransportDelay: statsNetworkTransportDelay,
          jitterBufferDelay: statsJitterBufferDelay,
          audioLossRate: statsAudioLossRate,
          numChannels: statsNumChannels,
          receivedSampleRate: statsReceivedSampleRate,
          receivedBitrate: statsReceivedBitrate,
          totalFrozenTime: statsTotalFrozenTime,
          frozenRate: statsFrozenRate,
          mosValue: statsMosValue,
          frozenRateByCustomPlcCount: statsFrozenRateByCustomPlcCount,
          plcCount: statsPlcCount,
          totalActiveTime: statsTotalActiveTime,
          publishDuration: statsPublishDuration,
          qoeQuality: statsQoeQuality,
          qualityChangedReason: statsQualityChangedReason,
          rxAudioBytes: statsRxAudioBytes,
          e2eDelay: statsE2eDelay,
        );

        final eventJson = {
          'connection': connection.toJson(),
          'stats': stats.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onRemoteAudioStats'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRemoteAudioStatsCompleter.isCompleted) {
              onRemoteAudioStatsCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onRemoteAudioStatsCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onLocalAudioStats',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onLocalAudioStatsCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onLocalAudioStats: (RtcConnection connection, LocalAudioStats stats) {
          onLocalAudioStatsCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int statsNumChannels = 5;
        int statsSentSampleRate = 5;
        int statsSentBitrate = 5;
        int statsInternalCodec = 5;
        int statsTxPacketLossRate = 5;
        int statsAudioDeviceDelay = 5;
        int statsAudioPlayoutDelay = 5;
        int statsEarMonitorDelay = 5;
        int statsAecEstimatedDelay = 5;
        LocalAudioStats stats = LocalAudioStats(
          numChannels: statsNumChannels,
          sentSampleRate: statsSentSampleRate,
          sentBitrate: statsSentBitrate,
          internalCodec: statsInternalCodec,
          txPacketLossRate: statsTxPacketLossRate,
          audioDeviceDelay: statsAudioDeviceDelay,
          audioPlayoutDelay: statsAudioPlayoutDelay,
          earMonitorDelay: statsEarMonitorDelay,
          aecEstimatedDelay: statsAecEstimatedDelay,
        );

        final eventJson = {
          'connection': connection.toJson(),
          'stats': stats.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onLocalAudioStats'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onLocalAudioStatsCompleter.isCompleted) {
              onLocalAudioStatsCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onLocalAudioStatsCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onLocalVideoStats',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onLocalVideoStatsCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onLocalVideoStats: (RtcConnection connection, LocalVideoStats stats) {
          onLocalVideoStatsCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        QualityAdaptIndication statsQualityAdaptIndication =
            QualityAdaptIndication.adaptNone;
        VideoCodecType statsCodecType = VideoCodecType.videoCodecNone;
        CaptureBrightnessLevelType statsCaptureBrightnessLevel =
            CaptureBrightnessLevelType.captureBrightnessLevelInvalid;
        int statsUid = 5;
        int statsSentBitrate = 5;
        int statsSentFrameRate = 5;
        int statsCaptureFrameRate = 5;
        int statsCaptureFrameWidth = 5;
        int statsCaptureFrameHeight = 5;
        int statsRegulatedCaptureFrameRate = 5;
        int statsRegulatedCaptureFrameWidth = 5;
        int statsRegulatedCaptureFrameHeight = 5;
        int statsEncoderOutputFrameRate = 5;
        int statsEncodedFrameWidth = 5;
        int statsEncodedFrameHeight = 5;
        int statsRendererOutputFrameRate = 5;
        int statsTargetBitrate = 5;
        int statsTargetFrameRate = 5;
        int statsEncodedBitrate = 5;
        int statsEncodedFrameCount = 5;
        int statsTxPacketLossRate = 5;
        bool statsDualStreamEnabled = true;
        int statsHwEncoderAccelerating = 5;
        List<VideoDimensions> statsSimulcastDimensions = [];
        LocalVideoStats stats = LocalVideoStats(
          uid: statsUid,
          sentBitrate: statsSentBitrate,
          sentFrameRate: statsSentFrameRate,
          captureFrameRate: statsCaptureFrameRate,
          captureFrameWidth: statsCaptureFrameWidth,
          captureFrameHeight: statsCaptureFrameHeight,
          regulatedCaptureFrameRate: statsRegulatedCaptureFrameRate,
          regulatedCaptureFrameWidth: statsRegulatedCaptureFrameWidth,
          regulatedCaptureFrameHeight: statsRegulatedCaptureFrameHeight,
          encoderOutputFrameRate: statsEncoderOutputFrameRate,
          encodedFrameWidth: statsEncodedFrameWidth,
          encodedFrameHeight: statsEncodedFrameHeight,
          rendererOutputFrameRate: statsRendererOutputFrameRate,
          targetBitrate: statsTargetBitrate,
          targetFrameRate: statsTargetFrameRate,
          qualityAdaptIndication: statsQualityAdaptIndication,
          encodedBitrate: statsEncodedBitrate,
          encodedFrameCount: statsEncodedFrameCount,
          codecType: statsCodecType,
          txPacketLossRate: statsTxPacketLossRate,
          captureBrightnessLevel: statsCaptureBrightnessLevel,
          dualStreamEnabled: statsDualStreamEnabled,
          hwEncoderAccelerating: statsHwEncoderAccelerating,
          simulcastDimensions: statsSimulcastDimensions,
        );

        final eventJson = {
          'connection': connection.toJson(),
          'stats': stats.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onLocalVideoStats'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onLocalVideoStatsCompleter.isCompleted) {
              onLocalVideoStatsCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onLocalVideoStatsCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRemoteVideoStats',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRemoteVideoStatsCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRemoteVideoStats: (RtcConnection connection, RemoteVideoStats stats) {
          onRemoteVideoStatsCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        VideoStreamType statsRxStreamType = VideoStreamType.videoStreamHigh;
        int statsUid = 5;
        int statsDelay = 5;
        int statsE2eDelay = 5;
        int statsWidth = 5;
        int statsHeight = 5;
        int statsReceivedBitrate = 5;
        int statsDecoderInputFrameRate = 5;
        int statsDecoderOutputFrameRate = 5;
        int statsRendererOutputFrameRate = 5;
        int statsFrameLossRate = 5;
        int statsPacketLossRate = 5;
        int statsTotalFrozenTime = 5;
        int statsFrozenRate = 5;
        int statsAvSyncTimeMs = 5;
        int statsTotalActiveTime = 5;
        int statsPublishDuration = 5;
        int statsMosValue = 5;
        int statsRxVideoBytes = 5;
        RemoteVideoStats stats = RemoteVideoStats(
          uid: statsUid,
          delay: statsDelay,
          e2eDelay: statsE2eDelay,
          width: statsWidth,
          height: statsHeight,
          receivedBitrate: statsReceivedBitrate,
          decoderInputFrameRate: statsDecoderInputFrameRate,
          decoderOutputFrameRate: statsDecoderOutputFrameRate,
          rendererOutputFrameRate: statsRendererOutputFrameRate,
          frameLossRate: statsFrameLossRate,
          packetLossRate: statsPacketLossRate,
          rxStreamType: statsRxStreamType,
          totalFrozenTime: statsTotalFrozenTime,
          frozenRate: statsFrozenRate,
          avSyncTimeMs: statsAvSyncTimeMs,
          totalActiveTime: statsTotalActiveTime,
          publishDuration: statsPublishDuration,
          mosValue: statsMosValue,
          rxVideoBytes: statsRxVideoBytes,
        );

        final eventJson = {
          'connection': connection.toJson(),
          'stats': stats.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onRemoteVideoStats'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRemoteVideoStatsCompleter.isCompleted) {
              onRemoteVideoStatsCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onRemoteVideoStatsCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onCameraReady',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onCameraReadyCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onCameraReady: () {
          onCameraReadyCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        final eventJson = {};

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onCameraReady'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onCameraReadyCompleter.isCompleted) {
              onCameraReadyCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onCameraReadyCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onCameraFocusAreaChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onCameraFocusAreaChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onCameraFocusAreaChanged: (int x, int y, int width, int height) {
          onCameraFocusAreaChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        int x = 5;
        int y = 5;
        int width = 5;
        int height = 5;

        final eventJson = {
          'x': x,
          'y': y,
          'width': width,
          'height': height,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onCameraFocusAreaChanged'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onCameraFocusAreaChangedCompleter.isCompleted) {
              onCameraFocusAreaChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onCameraFocusAreaChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onCameraExposureAreaChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onCameraExposureAreaChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onCameraExposureAreaChanged: (int x, int y, int width, int height) {
          onCameraExposureAreaChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        int x = 5;
        int y = 5;
        int width = 5;
        int height = 5;

        final eventJson = {
          'x': x,
          'y': y,
          'width': width,
          'height': height,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onCameraExposureAreaChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onCameraExposureAreaChangedCompleter.isCompleted) {
              onCameraExposureAreaChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onCameraExposureAreaChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onVideoStopped',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onVideoStoppedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onVideoStopped: () {
          onVideoStoppedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        final eventJson = {};

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onVideoStopped'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onVideoStoppedCompleter.isCompleted) {
              onVideoStoppedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onVideoStoppedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onAudioMixingStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onAudioMixingStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onAudioMixingStateChanged:
            (AudioMixingStateType state, AudioMixingReasonType reason) {
          onAudioMixingStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        AudioMixingStateType state =
            AudioMixingStateType.audioMixingStatePlaying;
        AudioMixingReasonType reason =
            AudioMixingReasonType.audioMixingReasonCanNotOpen;

        final eventJson = {
          'state': state.value(),
          'reason': reason.value(),
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onAudioMixingStateChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onAudioMixingStateChangedCompleter.isCompleted) {
              onAudioMixingStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onAudioMixingStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRhythmPlayerStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRhythmPlayerStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRhythmPlayerStateChanged:
            (RhythmPlayerStateType state, RhythmPlayerReason reason) {
          onRhythmPlayerStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        RhythmPlayerStateType state =
            RhythmPlayerStateType.rhythmPlayerStateIdle;
        RhythmPlayerReason reason = RhythmPlayerReason.rhythmPlayerReasonOk;

        final eventJson = {
          'state': state.value(),
          'reason': reason.value(),
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onRhythmPlayerStateChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRhythmPlayerStateChangedCompleter.isCompleted) {
              onRhythmPlayerStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onRhythmPlayerStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onConnectionLost',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onConnectionLostCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onConnectionLost: (RtcConnection connection) {
          onConnectionLostCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );

        final eventJson = {
          'connection': connection.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onConnectionLost'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onConnectionLostCompleter.isCompleted) {
              onConnectionLostCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onConnectionLostCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onConnectionInterrupted',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onConnectionInterruptedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onConnectionInterrupted: (RtcConnection connection) {
          onConnectionInterruptedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );

        final eventJson = {
          'connection': connection.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onConnectionInterrupted'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onConnectionInterruptedCompleter.isCompleted) {
              onConnectionInterruptedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onConnectionInterruptedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onConnectionBanned',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onConnectionBannedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onConnectionBanned: (RtcConnection connection) {
          onConnectionBannedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );

        final eventJson = {
          'connection': connection.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onConnectionBanned'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onConnectionBannedCompleter.isCompleted) {
              onConnectionBannedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onConnectionBannedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onStreamMessageError',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onStreamMessageErrorCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onStreamMessageError: (RtcConnection connection, int remoteUid,
            int streamId, ErrorCodeType code, int missed, int cached) {
          onStreamMessageErrorCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        int streamId = 5;
        ErrorCodeType code = ErrorCodeType.errOk;
        int missed = 5;
        int cached = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'streamId': streamId,
          'code': code.value(),
          'missed': missed,
          'cached': cached,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onStreamMessageError'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onStreamMessageErrorCompleter.isCompleted) {
              onStreamMessageErrorCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onStreamMessageErrorCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRequestToken',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRequestTokenCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRequestToken: (RtcConnection connection) {
          onRequestTokenCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );

        final eventJson = {
          'connection': connection.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onRequestToken'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRequestTokenCompleter.isCompleted) {
              onRequestTokenCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onRequestTokenCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onTokenPrivilegeWillExpire',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onTokenPrivilegeWillExpireCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onTokenPrivilegeWillExpire: (RtcConnection connection, String token) {
          onTokenPrivilegeWillExpireCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        String token = "hello";

        final eventJson = {
          'connection': connection.toJson(),
          'token': token,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onTokenPrivilegeWillExpire'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onTokenPrivilegeWillExpireCompleter.isCompleted) {
              onTokenPrivilegeWillExpireCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onTokenPrivilegeWillExpireCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onLicenseValidationFailure',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onLicenseValidationFailureCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onLicenseValidationFailure:
            (RtcConnection connection, LicenseErrorType reason) {
          onLicenseValidationFailureCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        LicenseErrorType reason = LicenseErrorType.licenseErrInvalid;

        final eventJson = {
          'connection': connection.toJson(),
          'reason': reason.value(),
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onLicenseValidationFailure'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onLicenseValidationFailureCompleter.isCompleted) {
              onLicenseValidationFailureCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onLicenseValidationFailureCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onFirstLocalAudioFramePublished',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onFirstLocalAudioFramePublishedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onFirstLocalAudioFramePublished:
            (RtcConnection connection, int elapsed) {
          onFirstLocalAudioFramePublishedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int elapsed = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'elapsed': elapsed,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onFirstLocalAudioFramePublished'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onFirstLocalAudioFramePublishedCompleter.isCompleted) {
              onFirstLocalAudioFramePublishedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onFirstLocalAudioFramePublishedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onFirstRemoteAudioDecoded',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onFirstRemoteAudioDecodedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onFirstRemoteAudioDecoded:
            (RtcConnection connection, int uid, int elapsed) {
          onFirstRemoteAudioDecodedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int uid = 5;
        int elapsed = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'uid': uid,
          'elapsed': elapsed,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onFirstRemoteAudioDecoded'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onFirstRemoteAudioDecodedCompleter.isCompleted) {
              onFirstRemoteAudioDecodedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onFirstRemoteAudioDecodedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onFirstRemoteAudioFrame',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onFirstRemoteAudioFrameCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onFirstRemoteAudioFrame:
            (RtcConnection connection, int userId, int elapsed) {
          onFirstRemoteAudioFrameCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int userId = 5;
        int elapsed = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'userId': userId,
          'elapsed': elapsed,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onFirstRemoteAudioFrame'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onFirstRemoteAudioFrameCompleter.isCompleted) {
              onFirstRemoteAudioFrameCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onFirstRemoteAudioFrameCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onLocalAudioStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onLocalAudioStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onLocalAudioStateChanged: (RtcConnection connection,
            LocalAudioStreamState state, LocalAudioStreamReason reason) {
          onLocalAudioStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        LocalAudioStreamState state =
            LocalAudioStreamState.localAudioStreamStateStopped;
        LocalAudioStreamReason reason =
            LocalAudioStreamReason.localAudioStreamReasonOk;

        final eventJson = {
          'connection': connection.toJson(),
          'state': state.value(),
          'reason': reason.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onLocalAudioStateChanged'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onLocalAudioStateChangedCompleter.isCompleted) {
              onLocalAudioStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onLocalAudioStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRemoteAudioStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRemoteAudioStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRemoteAudioStateChanged: (RtcConnection connection,
            int remoteUid,
            RemoteAudioState state,
            RemoteAudioStateReason reason,
            int elapsed) {
          onRemoteAudioStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        RemoteAudioState state = RemoteAudioState.remoteAudioStateStopped;
        RemoteAudioStateReason reason =
            RemoteAudioStateReason.remoteAudioReasonInternal;
        int elapsed = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'state': state.value(),
          'reason': reason.value(),
          'elapsed': elapsed,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onRemoteAudioStateChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRemoteAudioStateChangedCompleter.isCompleted) {
              onRemoteAudioStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onRemoteAudioStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onActiveSpeaker',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onActiveSpeakerCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onActiveSpeaker: (RtcConnection connection, int uid) {
          onActiveSpeakerCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int uid = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'uid': uid,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onActiveSpeaker'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onActiveSpeakerCompleter.isCompleted) {
              onActiveSpeakerCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onActiveSpeakerCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onContentInspectResult',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onContentInspectResultCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onContentInspectResult: (ContentInspectResult result) {
          onContentInspectResultCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        ContentInspectResult result =
            ContentInspectResult.contentInspectNeutral;

        final eventJson = {
          'result': result.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onContentInspectResult'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onContentInspectResultCompleter.isCompleted) {
              onContentInspectResultCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onContentInspectResultCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onSnapshotTaken',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onSnapshotTakenCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onSnapshotTaken: (RtcConnection connection, int uid, String filePath,
            int width, int height, int errCode) {
          onSnapshotTakenCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int uid = 5;
        String filePath = "hello";
        int width = 5;
        int height = 5;
        int errCode = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'uid': uid,
          'filePath': filePath,
          'width': width,
          'height': height,
          'errCode': errCode,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onSnapshotTaken'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onSnapshotTakenCompleter.isCompleted) {
              onSnapshotTakenCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onSnapshotTakenCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onClientRoleChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onClientRoleChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onClientRoleChanged: (RtcConnection connection, ClientRoleType oldRole,
            ClientRoleType newRole, ClientRoleOptions newRoleOptions) {
          onClientRoleChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        ClientRoleType oldRole = ClientRoleType.clientRoleBroadcaster;
        ClientRoleType newRole = ClientRoleType.clientRoleBroadcaster;
        AudienceLatencyLevelType newRoleOptionsAudienceLatencyLevel =
            AudienceLatencyLevelType.audienceLatencyLevelLowLatency;
        ClientRoleOptions newRoleOptions = ClientRoleOptions(
          audienceLatencyLevel: newRoleOptionsAudienceLatencyLevel,
        );

        final eventJson = {
          'connection': connection.toJson(),
          'oldRole': oldRole.value(),
          'newRole': newRole.value(),
          'newRoleOptions': newRoleOptions.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onClientRoleChanged'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onClientRoleChangedCompleter.isCompleted) {
              onClientRoleChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onClientRoleChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onClientRoleChangeFailed',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onClientRoleChangeFailedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onClientRoleChangeFailed: (RtcConnection connection,
            ClientRoleChangeFailedReason reason, ClientRoleType currentRole) {
          onClientRoleChangeFailedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        ClientRoleChangeFailedReason reason = ClientRoleChangeFailedReason
            .clientRoleChangeFailedTooManyBroadcasters;
        ClientRoleType currentRole = ClientRoleType.clientRoleBroadcaster;

        final eventJson = {
          'connection': connection.toJson(),
          'reason': reason.value(),
          'currentRole': currentRole.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onClientRoleChangeFailed'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onClientRoleChangeFailedCompleter.isCompleted) {
              onClientRoleChangeFailedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onClientRoleChangeFailedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onAudioDeviceVolumeChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onAudioDeviceVolumeChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onAudioDeviceVolumeChanged:
            (MediaDeviceType deviceType, int volume, bool muted) {
          onAudioDeviceVolumeChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        MediaDeviceType deviceType = MediaDeviceType.unknownAudioDevice;
        int volume = 5;
        bool muted = true;

        final eventJson = {
          'deviceType': deviceType.value(),
          'volume': volume,
          'muted': muted,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onAudioDeviceVolumeChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onAudioDeviceVolumeChangedCompleter.isCompleted) {
              onAudioDeviceVolumeChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onAudioDeviceVolumeChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRtmpStreamingStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRtmpStreamingStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRtmpStreamingStateChanged: (String url, RtmpStreamPublishState state,
            RtmpStreamPublishReason reason) {
          onRtmpStreamingStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String url = "hello";
        RtmpStreamPublishState state =
            RtmpStreamPublishState.rtmpStreamPublishStateIdle;
        RtmpStreamPublishReason reason =
            RtmpStreamPublishReason.rtmpStreamPublishReasonOk;

        final eventJson = {
          'url': url,
          'state': state.value(),
          'reason': reason.value(),
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onRtmpStreamingStateChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRtmpStreamingStateChangedCompleter.isCompleted) {
              onRtmpStreamingStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onRtmpStreamingStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRtmpStreamingEvent',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRtmpStreamingEventCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRtmpStreamingEvent: (String url, RtmpStreamingEvent eventCode) {
          onRtmpStreamingEventCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String url = "hello";
        RtmpStreamingEvent eventCode =
            RtmpStreamingEvent.rtmpStreamingEventFailedLoadImage;

        final eventJson = {
          'url': url,
          'eventCode': eventCode.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onRtmpStreamingEvent'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRtmpStreamingEventCompleter.isCompleted) {
              onRtmpStreamingEventCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onRtmpStreamingEventCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onTranscodingUpdated',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onTranscodingUpdatedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onTranscodingUpdated: () {
          onTranscodingUpdatedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        final eventJson = {};

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onTranscodingUpdated'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onTranscodingUpdatedCompleter.isCompleted) {
              onTranscodingUpdatedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onTranscodingUpdatedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onAudioRoutingChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onAudioRoutingChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onAudioRoutingChanged: (int routing) {
          onAudioRoutingChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        int routing = 5;

        final eventJson = {
          'routing': routing,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onAudioRoutingChanged'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onAudioRoutingChangedCompleter.isCompleted) {
              onAudioRoutingChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onAudioRoutingChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onChannelMediaRelayStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onChannelMediaRelayStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onChannelMediaRelayStateChanged:
            (ChannelMediaRelayState state, ChannelMediaRelayError code) {
          onChannelMediaRelayStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        ChannelMediaRelayState state = ChannelMediaRelayState.relayStateIdle;
        ChannelMediaRelayError code = ChannelMediaRelayError.relayOk;

        final eventJson = {
          'state': state.value(),
          'code': code.value(),
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onChannelMediaRelayStateChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onChannelMediaRelayStateChangedCompleter.isCompleted) {
              onChannelMediaRelayStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onChannelMediaRelayStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onLocalPublishFallbackToAudioOnly',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onLocalPublishFallbackToAudioOnlyCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onLocalPublishFallbackToAudioOnly: (bool isFallbackOrRecover) {
          onLocalPublishFallbackToAudioOnlyCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        bool isFallbackOrRecover = true;

        final eventJson = {
          'isFallbackOrRecover': isFallbackOrRecover,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onLocalPublishFallbackToAudioOnly'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onLocalPublishFallbackToAudioOnlyCompleter.isCompleted) {
              onLocalPublishFallbackToAudioOnlyCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled =
          await onLocalPublishFallbackToAudioOnlyCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRemoteSubscribeFallbackToAudioOnly',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRemoteSubscribeFallbackToAudioOnlyCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRemoteSubscribeFallbackToAudioOnly:
            (int uid, bool isFallbackOrRecover) {
          onRemoteSubscribeFallbackToAudioOnlyCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        int uid = 5;
        bool isFallbackOrRecover = true;

        final eventJson = {
          'uid': uid,
          'isFallbackOrRecover': isFallbackOrRecover,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onRemoteSubscribeFallbackToAudioOnly'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRemoteSubscribeFallbackToAudioOnlyCompleter.isCompleted) {
              onRemoteSubscribeFallbackToAudioOnlyCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled =
          await onRemoteSubscribeFallbackToAudioOnlyCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRemoteAudioTransportStats',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRemoteAudioTransportStatsCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRemoteAudioTransportStats: (RtcConnection connection, int remoteUid,
            int delay, int lost, int rxKBitRate) {
          onRemoteAudioTransportStatsCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        int delay = 5;
        int lost = 5;
        int rxKBitRate = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'delay': delay,
          'lost': lost,
          'rxKBitRate': rxKBitRate,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onRemoteAudioTransportStats'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRemoteAudioTransportStatsCompleter.isCompleted) {
              onRemoteAudioTransportStatsCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onRemoteAudioTransportStatsCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onRemoteVideoTransportStats',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onRemoteVideoTransportStatsCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onRemoteVideoTransportStats: (RtcConnection connection, int remoteUid,
            int delay, int lost, int rxKBitRate) {
          onRemoteVideoTransportStatsCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        int delay = 5;
        int lost = 5;
        int rxKBitRate = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'delay': delay,
          'lost': lost,
          'rxKBitRate': rxKBitRate,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onRemoteVideoTransportStats'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onRemoteVideoTransportStatsCompleter.isCompleted) {
              onRemoteVideoTransportStatsCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onRemoteVideoTransportStatsCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onConnectionStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onConnectionStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onConnectionStateChanged: (RtcConnection connection,
            ConnectionStateType state, ConnectionChangedReasonType reason) {
          onConnectionStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        ConnectionStateType state =
            ConnectionStateType.connectionStateDisconnected;
        ConnectionChangedReasonType reason =
            ConnectionChangedReasonType.connectionChangedConnecting;

        final eventJson = {
          'connection': connection.toJson(),
          'state': state.value(),
          'reason': reason.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onConnectionStateChanged'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onConnectionStateChangedCompleter.isCompleted) {
              onConnectionStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onConnectionStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onWlAccMessage',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onWlAccMessageCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onWlAccMessage: (RtcConnection connection, WlaccMessageReason reason,
            WlaccSuggestAction action, String wlAccMsg) {
          onWlAccMessageCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        WlaccMessageReason reason =
            WlaccMessageReason.wlaccMessageReasonWeakSignal;
        WlaccSuggestAction action =
            WlaccSuggestAction.wlaccSuggestActionCloseToWifi;
        String wlAccMsg = "hello";

        final eventJson = {
          'connection': connection.toJson(),
          'reason': reason.value(),
          'action': action.value(),
          'wlAccMsg': wlAccMsg,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onWlAccMessage'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onWlAccMessageCompleter.isCompleted) {
              onWlAccMessageCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onWlAccMessageCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onWlAccStats',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onWlAccStatsCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onWlAccStats: (RtcConnection connection, WlAccStats currentStats,
            WlAccStats averageStats) {
          onWlAccStatsCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int currentStatsE2eDelayPercent = 5;
        int currentStatsFrozenRatioPercent = 5;
        int currentStatsLossRatePercent = 5;
        WlAccStats currentStats = WlAccStats(
          e2eDelayPercent: currentStatsE2eDelayPercent,
          frozenRatioPercent: currentStatsFrozenRatioPercent,
          lossRatePercent: currentStatsLossRatePercent,
        );
        int averageStatsE2eDelayPercent = 5;
        int averageStatsFrozenRatioPercent = 5;
        int averageStatsLossRatePercent = 5;
        WlAccStats averageStats = WlAccStats(
          e2eDelayPercent: averageStatsE2eDelayPercent,
          frozenRatioPercent: averageStatsFrozenRatioPercent,
          lossRatePercent: averageStatsLossRatePercent,
        );

        final eventJson = {
          'connection': connection.toJson(),
          'currentStats': currentStats.toJson(),
          'averageStats': averageStats.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onWlAccStats'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onWlAccStatsCompleter.isCompleted) {
              onWlAccStatsCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onWlAccStatsCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onNetworkTypeChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onNetworkTypeChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onNetworkTypeChanged: (RtcConnection connection, NetworkType type) {
          onNetworkTypeChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        NetworkType type = NetworkType.networkTypeUnknown;

        final eventJson = {
          'connection': connection.toJson(),
          'type': type.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onNetworkTypeChanged'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onNetworkTypeChangedCompleter.isCompleted) {
              onNetworkTypeChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onNetworkTypeChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onEncryptionError',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onEncryptionErrorCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onEncryptionError:
            (RtcConnection connection, EncryptionErrorType errorType) {
          onEncryptionErrorCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        EncryptionErrorType errorType =
            EncryptionErrorType.encryptionErrorInternalFailure;

        final eventJson = {
          'connection': connection.toJson(),
          'errorType': errorType.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onEncryptionError'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onEncryptionErrorCompleter.isCompleted) {
              onEncryptionErrorCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onEncryptionErrorCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onPermissionError',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onPermissionErrorCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onPermissionError: (PermissionType permissionType) {
          onPermissionErrorCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        PermissionType permissionType = PermissionType.recordAudio;

        final eventJson = {
          'permissionType': permissionType.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onPermissionError'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onPermissionErrorCompleter.isCompleted) {
              onPermissionErrorCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onPermissionErrorCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onLocalUserRegistered',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onLocalUserRegisteredCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onLocalUserRegistered: (int uid, String userAccount) {
          onLocalUserRegisteredCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        int uid = 5;
        String userAccount = "hello";

        final eventJson = {
          'uid': uid,
          'userAccount': userAccount,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onLocalUserRegistered'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onLocalUserRegisteredCompleter.isCompleted) {
              onLocalUserRegisteredCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onLocalUserRegisteredCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onUserInfoUpdated',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onUserInfoUpdatedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onUserInfoUpdated: (int uid, UserInfo info) {
          onUserInfoUpdatedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        int uid = 5;
        int infoUid = 5;
        String infoUserAccount = "hello";
        UserInfo info = UserInfo(
          uid: infoUid,
          userAccount: infoUserAccount,
        );

        final eventJson = {
          'uid': uid,
          'info': info.toJson(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onUserInfoUpdated'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onUserInfoUpdatedCompleter.isCompleted) {
              onUserInfoUpdatedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onUserInfoUpdatedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onUserAccountUpdated',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onUserAccountUpdatedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onUserAccountUpdated: (RtcConnection connection, int remoteUid,
            String remoteUserAccount) {
          onUserAccountUpdatedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int remoteUid = 5;
        String remoteUserAccount = "hello";

        final eventJson = {
          'connection': connection.toJson(),
          'remoteUid': remoteUid,
          'remoteUserAccount': remoteUserAccount,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onUserAccountUpdated'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onUserAccountUpdatedCompleter.isCompleted) {
              onUserAccountUpdatedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onUserAccountUpdatedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onVideoRenderingTracingResult',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onVideoRenderingTracingResultCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onVideoRenderingTracingResult: (RtcConnection connection,
            int uid,
            MediaTraceEvent currentEvent,
            VideoRenderingTracingInfo tracingInfo) {
          onVideoRenderingTracingResultCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int uid = 5;
        MediaTraceEvent currentEvent =
            MediaTraceEvent.mediaTraceEventVideoRendered;
        int tracingInfoElapsedTime = 5;
        int tracingInfoStart2JoinChannel = 5;
        int tracingInfoJoin2JoinSuccess = 5;
        int tracingInfoJoinSuccess2RemoteJoined = 5;
        int tracingInfoRemoteJoined2SetView = 5;
        int tracingInfoRemoteJoined2UnmuteVideo = 5;
        int tracingInfoRemoteJoined2PacketReceived = 5;
        VideoRenderingTracingInfo tracingInfo = VideoRenderingTracingInfo(
          elapsedTime: tracingInfoElapsedTime,
          start2JoinChannel: tracingInfoStart2JoinChannel,
          join2JoinSuccess: tracingInfoJoin2JoinSuccess,
          joinSuccess2RemoteJoined: tracingInfoJoinSuccess2RemoteJoined,
          remoteJoined2SetView: tracingInfoRemoteJoined2SetView,
          remoteJoined2UnmuteVideo: tracingInfoRemoteJoined2UnmuteVideo,
          remoteJoined2PacketReceived: tracingInfoRemoteJoined2PacketReceived,
        );

        final eventJson = {
          'connection': connection.toJson(),
          'uid': uid,
          'currentEvent': currentEvent.value(),
          'tracingInfo': tracingInfo.toJson(),
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onVideoRenderingTracingResult'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onVideoRenderingTracingResultCompleter.isCompleted) {
              onVideoRenderingTracingResultCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onVideoRenderingTracingResultCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onLocalVideoTranscoderError',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onLocalVideoTranscoderErrorCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onLocalVideoTranscoderError:
            (TranscodingVideoStream stream, VideoTranscoderError error) {
          onLocalVideoTranscoderErrorCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        VideoSourceType streamSourceType =
            VideoSourceType.videoSourceCameraPrimary;
        int streamRemoteUserUid = 5;
        String streamImageUrl = "hello";
        int streamMediaPlayerId = 5;
        int streamX = 5;
        int streamY = 5;
        int streamWidth = 5;
        int streamHeight = 5;
        int streamZOrder = 5;
        double streamAlpha = 5.0;
        bool streamMirror = true;
        TranscodingVideoStream stream = TranscodingVideoStream(
          sourceType: streamSourceType,
          remoteUserUid: streamRemoteUserUid,
          imageUrl: streamImageUrl,
          mediaPlayerId: streamMediaPlayerId,
          x: streamX,
          y: streamY,
          width: streamWidth,
          height: streamHeight,
          zOrder: streamZOrder,
          alpha: streamAlpha,
          mirror: streamMirror,
        );
        VideoTranscoderError error =
            VideoTranscoderError.vtErrVideoSourceNotReady;

        final eventJson = {
          'stream': stream.toJson(),
          'error': error.value(),
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onLocalVideoTranscoderError'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onLocalVideoTranscoderErrorCompleter.isCompleted) {
              onLocalVideoTranscoderErrorCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onLocalVideoTranscoderErrorCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onUploadLogResult',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onUploadLogResultCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onUploadLogResult: (RtcConnection connection, String requestId,
            bool success, UploadErrorReason reason) {
          onUploadLogResultCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        String requestId = "hello";
        bool success = true;
        UploadErrorReason reason = UploadErrorReason.uploadSuccess;

        final eventJson = {
          'connection': connection.toJson(),
          'requestId': requestId,
          'success': success,
          'reason': reason.value(),
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onUploadLogResult'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onUploadLogResultCompleter.isCompleted) {
              onUploadLogResultCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onUploadLogResultCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onAudioSubscribeStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onAudioSubscribeStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onAudioSubscribeStateChanged: (String channel,
            int uid,
            StreamSubscribeState oldState,
            StreamSubscribeState newState,
            int elapseSinceLastState) {
          onAudioSubscribeStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String channel = "hello";
        int uid = 5;
        StreamSubscribeState oldState = StreamSubscribeState.subStateIdle;
        StreamSubscribeState newState = StreamSubscribeState.subStateIdle;
        int elapseSinceLastState = 5;

        final eventJson = {
          'channel': channel,
          'uid': uid,
          'oldState': oldState.value(),
          'newState': newState.value(),
          'elapseSinceLastState': elapseSinceLastState,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onAudioSubscribeStateChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onAudioSubscribeStateChangedCompleter.isCompleted) {
              onAudioSubscribeStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onAudioSubscribeStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onVideoSubscribeStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onVideoSubscribeStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onVideoSubscribeStateChanged: (String channel,
            int uid,
            StreamSubscribeState oldState,
            StreamSubscribeState newState,
            int elapseSinceLastState) {
          onVideoSubscribeStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String channel = "hello";
        int uid = 5;
        StreamSubscribeState oldState = StreamSubscribeState.subStateIdle;
        StreamSubscribeState newState = StreamSubscribeState.subStateIdle;
        int elapseSinceLastState = 5;

        final eventJson = {
          'channel': channel,
          'uid': uid,
          'oldState': oldState.value(),
          'newState': newState.value(),
          'elapseSinceLastState': elapseSinceLastState,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onVideoSubscribeStateChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onVideoSubscribeStateChangedCompleter.isCompleted) {
              onVideoSubscribeStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onVideoSubscribeStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onAudioPublishStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onAudioPublishStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onAudioPublishStateChanged: (String channel,
            StreamPublishState oldState,
            StreamPublishState newState,
            int elapseSinceLastState) {
          onAudioPublishStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String channel = "hello";
        StreamPublishState oldState = StreamPublishState.pubStateIdle;
        StreamPublishState newState = StreamPublishState.pubStateIdle;
        int elapseSinceLastState = 5;

        final eventJson = {
          'channel': channel,
          'oldState': oldState.value(),
          'newState': newState.value(),
          'elapseSinceLastState': elapseSinceLastState,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onAudioPublishStateChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onAudioPublishStateChangedCompleter.isCompleted) {
              onAudioPublishStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onAudioPublishStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onVideoPublishStateChanged',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onVideoPublishStateChangedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onVideoPublishStateChanged: (VideoSourceType source,
            String channel,
            StreamPublishState oldState,
            StreamPublishState newState,
            int elapseSinceLastState) {
          onVideoPublishStateChangedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        VideoSourceType source = VideoSourceType.videoSourceCameraPrimary;
        String channel = "hello";
        StreamPublishState oldState = StreamPublishState.pubStateIdle;
        StreamPublishState newState = StreamPublishState.pubStateIdle;
        int elapseSinceLastState = 5;

        final eventJson = {
          'source': source.value(),
          'channel': channel,
          'oldState': oldState.value(),
          'newState': newState.value(),
          'elapseSinceLastState': elapseSinceLastState,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onVideoPublishStateChanged'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onVideoPublishStateChangedCompleter.isCompleted) {
              onVideoPublishStateChangedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onVideoPublishStateChangedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onTranscodedStreamLayoutInfo',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onTranscodedStreamLayoutInfoCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onTranscodedStreamLayoutInfo: (RtcConnection connection, int uid,
            int width, int height, int layoutCount, List layoutlist) {
          onTranscodedStreamLayoutInfoCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int uid = 5;
        int width = 5;
        int height = 5;
        int layoutCount = 5;
        final List<VideoLayout> layoutlist = () {
          String layoutlistItemChannelId = "hello";
          int layoutlistItemUid = 5;
          String layoutlistItemStrUid = "hello";
          int layoutlistItemX = 5;
          int layoutlistItemY = 5;
          int layoutlistItemWidth = 5;
          int layoutlistItemHeight = 5;
          int layoutlistItemVideoState = 5;
          VideoLayout layoutlistItem = VideoLayout(
            channelId: layoutlistItemChannelId,
            uid: layoutlistItemUid,
            strUid: layoutlistItemStrUid,
            x: layoutlistItemX,
            y: layoutlistItemY,
            width: layoutlistItemWidth,
            height: layoutlistItemHeight,
            videoState: layoutlistItemVideoState,
          );

          return List.filled(5, layoutlistItem);
        }();

        final eventJson = {
          'connection': connection.toJson(),
          'uid': uid,
          'width': width,
          'height': height,
          'layoutCount': layoutCount,
          'layoutlist': layoutlist,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onTranscodedStreamLayoutInfo'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onTranscodedStreamLayoutInfoCompleter.isCompleted) {
              onTranscodedStreamLayoutInfoCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onTranscodedStreamLayoutInfoCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onAudioMetadataReceived',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onAudioMetadataReceivedCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onAudioMetadataReceived: (RtcConnection connection, int uid,
            Uint8List metadata, int length) {
          onAudioMetadataReceivedCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int uid = 5;
        Uint8List metadata = Uint8List.fromList([1, 1, 1, 1, 1]);
        int length = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'uid': uid,
          'metadata': metadata.toList(),
          'length': length,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onAudioMetadataReceived'] ??
                [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onAudioMetadataReceivedCompleter.isCompleted) {
              onAudioMetadataReceivedCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onAudioMetadataReceivedCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onExtensionEventWithContext',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onExtensionEventWithContextCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onExtensionEventWithContext:
            (ExtensionContext context, String key, String value) {
          onExtensionEventWithContextCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        bool contextIsValid = true;
        int contextUid = 5;
        String contextProviderName = "hello";
        String contextExtensionName = "hello";
        ExtensionContext context = ExtensionContext(
          isValid: contextIsValid,
          uid: contextUid,
          providerName: contextProviderName,
          extensionName: contextExtensionName,
        );
        String key = "hello";
        String value = "hello";

        final eventJson = {
          'context': context.toJson(),
          'key': key,
          'value': value,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onExtensionEventWithContext'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onExtensionEventWithContextCompleter.isCompleted) {
              onExtensionEventWithContextCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onExtensionEventWithContextCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onExtensionStartedWithContext',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onExtensionStartedWithContextCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onExtensionStartedWithContext: (ExtensionContext context) {
          onExtensionStartedWithContextCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        bool contextIsValid = true;
        int contextUid = 5;
        String contextProviderName = "hello";
        String contextExtensionName = "hello";
        ExtensionContext context = ExtensionContext(
          isValid: contextIsValid,
          uid: contextUid,
          providerName: contextProviderName,
          extensionName: contextExtensionName,
        );

        final eventJson = {
          'context': context.toJson(),
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onExtensionStartedWithContext'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onExtensionStartedWithContextCompleter.isCompleted) {
              onExtensionStartedWithContextCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onExtensionStartedWithContextCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onExtensionStoppedWithContext',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onExtensionStoppedWithContextCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onExtensionStoppedWithContext: (ExtensionContext context) {
          onExtensionStoppedWithContextCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        bool contextIsValid = true;
        int contextUid = 5;
        String contextProviderName = "hello";
        String contextExtensionName = "hello";
        ExtensionContext context = ExtensionContext(
          isValid: contextIsValid,
          uid: contextUid,
          providerName: contextProviderName,
          extensionName: contextExtensionName,
        );

        final eventJson = {
          'context': context.toJson(),
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onExtensionStoppedWithContext'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onExtensionStoppedWithContextCompleter.isCompleted) {
              onExtensionStoppedWithContextCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onExtensionStoppedWithContextCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onExtensionErrorWithContext',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onExtensionErrorWithContextCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onExtensionErrorWithContext:
            (ExtensionContext context, int error, String message) {
          onExtensionErrorWithContextCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        bool contextIsValid = true;
        int contextUid = 5;
        String contextProviderName = "hello";
        String contextExtensionName = "hello";
        ExtensionContext context = ExtensionContext(
          isValid: contextIsValid,
          uid: contextUid,
          providerName: contextProviderName,
          extensionName: contextExtensionName,
        );
        int error = 5;
        String message = "hello";

        final eventJson = {
          'context': context.toJson(),
          'error': error,
          'message': message,
        };

        final eventIds = eventIdsMapping[
                'RtcEngineEventHandler_onExtensionErrorWithContext'] ??
            [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onExtensionErrorWithContextCompleter.isCompleted) {
              onExtensionErrorWithContextCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onExtensionErrorWithContextCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );

  testWidgets(
    'RtcEngineEventHandler.onSetRtmFlagResult',
    (WidgetTester tester) async {
      RtcEngine rtcEngine = createAgoraRtcEngine();
      await rtcEngine.initialize(RtcEngineContext(
        appId: 'app_id',
        areaCode: AreaCode.areaCodeGlob.value(),
      ));
      await rtcEngine.setParameters('{"rtc.enable_debug_log": true}');

      final onSetRtmFlagResultCompleter = Completer<bool>();
      final theRtcEngineEventHandler = RtcEngineEventHandler(
        onSetRtmFlagResult: (RtcConnection connection, int code) {
          onSetRtmFlagResultCompleter.complete(true);
        },
      );

      rtcEngine.registerEventHandler(
        theRtcEngineEventHandler,
      );

// Delay 500 milliseconds to ensure the registerEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      {
        String connectionChannelId = "hello";
        int connectionLocalUid = 5;
        RtcConnection connection = RtcConnection(
          channelId: connectionChannelId,
          localUid: connectionLocalUid,
        );
        int code = 5;

        final eventJson = {
          'connection': connection.toJson(),
          'code': code,
        };

        final eventIds =
            eventIdsMapping['RtcEngineEventHandler_onSetRtmFlagResult'] ?? [];
        for (final event in eventIds) {
          final ret = irisTester().fireEvent(event, params: eventJson);
          // Delay 200 milliseconds to ensure the callback is called.
          await Future.delayed(const Duration(milliseconds: 200));
          // TODO(littlegnal): Most of callbacks on web are not implemented, we're temporarily skip these callbacks at this time.
          if (kIsWeb && ret) {
            if (!onSetRtmFlagResultCompleter.isCompleted) {
              onSetRtmFlagResultCompleter.complete(true);
            }
          }
        }
      }

      final eventCalled = await onSetRtmFlagResultCompleter.future;
      expect(eventCalled, isTrue);

      {
        rtcEngine.unregisterEventHandler(
          theRtcEngineEventHandler,
        );
      }
// Delay 500 milliseconds to ensure the unregisterEventHandler call completed.
      await Future.delayed(const Duration(milliseconds: 500));

      await rtcEngine.release();
    },
    timeout: const Timeout(Duration(minutes: 2)),
  );
}
