fluttergoogle-mapsgoogle-maps-flutter

How to make a "WidgetTest" call the "onCameraMove" method?


I would like the onCameraMove method to be called when moveCamera is called.

I tried to mock platform channel without success.

import 'dart:async';

import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  testWidgets('GoogleMaps onCameraMove', (WidgetTester tester) async {
    final Completer<GoogleMapController> controllerCompleter =
        Completer<GoogleMapController>();
    final cameraMoveCompleter = Completer<bool>();

    await tester.pumpWidget(Directionality(
      textDirection: TextDirection.ltr,
      child: GoogleMap(
        initialCameraPosition: const CameraPosition(target: LatLng(1, 2)),
        onMapCreated: (GoogleMapController c) {
          controllerCompleter.complete(c);
        },
        onCameraMove: (position) {
          cameraMoveCompleter.complete(true);
        },
      ),
    ));
    await tester.pumpAndSettle();

    final GoogleMapController controller = await controllerCompleter.future;
    await controller.moveCamera(CameraUpdate.newLatLng(const LatLng(2, 3)));

    await tester.pumpAndSettle();

    expect(cameraMoveCompleter.isCompleted, true);
  });
}

Solution

  • I find the right way for mock EventChannel.

    import 'dart:async';
    
    import 'package:flutter/services.dart';
    import 'package:flutter/widgets.dart';
    import 'package:flutter_test/flutter_test.dart';
    import 'package:google_maps_flutter/google_maps_flutter.dart';
    
    void main() {
      TestWidgetsFlutterBinding.ensureInitialized();
    
      testWidgets('GoogleMaps onCameraMove', (WidgetTester tester) async {
        SystemChannels.platform_views
            .setMockMethodCallHandler((final MethodCall call) {
          switch (call.method) {
            case 'create':
              return Future<int>.sync(() => 1);
            default:
              return Future<void>.sync(() {});
          }
        });
        const channel = 'plugins.flutter.io/google_maps_0';
        const MethodChannel(channel).setMockMethodCallHandler(
          (final MethodCall call) async {
            if (call.method == 'camera#move') {
              final cameraPosition =
                  CameraPosition.fromMap(call.arguments['cameraUpdate'][1])!;
              await TestDefaultBinaryMessengerBinding
                  .instance?.defaultBinaryMessenger
                  .handlePlatformMessage(
                channel,
                const StandardMethodCodec().encodeMethodCall(
                  MethodCall(
                    'camera#onMove',
                    <dynamic, dynamic>{
                      'mapId': 0,
                      'position': cameraPosition.toMap(),
                    },
                  ),
                ),
                null,
              );
            }
          },
        );
        final controllerCompleter = Completer<GoogleMapController>();
        final cameraMoveCompleter = Completer<CameraPosition>();
        await tester.pumpWidget(Directionality(
          textDirection: TextDirection.ltr,
          child: GoogleMap(
            initialCameraPosition: const CameraPosition(target: LatLng(1, 2)),
            onMapCreated: (GoogleMapController c) {
              controllerCompleter.complete(c);
            },
            onCameraMove: (position) {
              cameraMoveCompleter.complete(position);
            },
          ),
        ));
        await tester.pumpAndSettle();
        final GoogleMapController controller = await controllerCompleter.future;
        const position = CameraPosition(target: LatLng(2, 3));
        await controller.moveCamera(CameraUpdate.newCameraPosition(position));
        await tester.pumpAndSettle();
        expect(cameraMoveCompleter.isCompleted, true);
        expect(await cameraMoveCompleter.future, position);
      });
    }