[google_maps_flutter_web] Make google_maps_flutter_web work with latest plugins  (#3673)

Co-authored-by: David Iglesias Teixeira <ditman@gmail.com>
diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md
index 4277d7b..826f1ea 100644
--- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md
+++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md
@@ -1,3 +1,10 @@
+## 0.2.0
+
+* Make this plugin compatible with the rest of null-safe plugins.
+* Noop tile overlays methods, so they don't crash on web.
+
+**NOTE**: This plugin is **not** null-safe yet!
+
 ## 0.1.2
 
 * Update min Flutter SDK to 1.20.0.
diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart
index 95f481a..5212679 100644
--- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart
+++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart
@@ -11,8 +11,6 @@
 );
 
 // Defaults taken from the Google Maps Platform SDK documentation.
-final _defaultStrokeColor = Colors.black.value;
-final _defaultFillColor = Colors.transparent.value;
 final _defaultCssColor = '#000000';
 final _defaultCssOpacity = 0.0;
 
@@ -59,41 +57,39 @@
 // buildingsEnabled seems to not have an equivalent in web
 // padding seems to behave differently in web than mobile. You can't move UI elements in web.
 gmaps.MapOptions _rawOptionsToGmapsOptions(Map<String, dynamic> rawOptions) {
-  Map<String, dynamic> optionsUpdate = rawOptions['options'] ?? {};
-
   gmaps.MapOptions options = gmaps.MapOptions();
 
-  if (_mapTypeToMapTypeId.containsKey(optionsUpdate['mapType'])) {
-    options.mapTypeId = _mapTypeToMapTypeId[optionsUpdate['mapType']];
+  if (_mapTypeToMapTypeId.containsKey(rawOptions['mapType'])) {
+    options.mapTypeId = _mapTypeToMapTypeId[rawOptions['mapType']];
   }
 
-  if (optionsUpdate['minMaxZoomPreference'] != null) {
+  if (rawOptions['minMaxZoomPreference'] != null) {
     options
-      ..minZoom = optionsUpdate['minMaxZoomPreference'][0]
-      ..maxZoom = optionsUpdate['minMaxZoomPreference'][1];
+      ..minZoom = rawOptions['minMaxZoomPreference'][0]
+      ..maxZoom = rawOptions['minMaxZoomPreference'][1];
   }
 
-  if (optionsUpdate['cameraTargetBounds'] != null) {
+  if (rawOptions['cameraTargetBounds'] != null) {
     // Needs gmaps.MapOptions.restriction and gmaps.MapRestriction
     // see: https://developers.google.com/maps/documentation/javascript/reference/map#MapOptions.restriction
   }
 
-  if (optionsUpdate['zoomControlsEnabled'] != null) {
-    options.zoomControl = optionsUpdate['zoomControlsEnabled'];
+  if (rawOptions['zoomControlsEnabled'] != null) {
+    options.zoomControl = rawOptions['zoomControlsEnabled'];
   }
 
-  if (optionsUpdate['styles'] != null) {
-    options.styles = optionsUpdate['styles'];
+  if (rawOptions['styles'] != null) {
+    options.styles = rawOptions['styles'];
   }
 
-  if (optionsUpdate['scrollGesturesEnabled'] == false ||
-      optionsUpdate['zoomGesturesEnabled'] == false) {
+  if (rawOptions['scrollGesturesEnabled'] == false ||
+      rawOptions['zoomGesturesEnabled'] == false) {
     options.gestureHandling = 'none';
   } else {
     options.gestureHandling = 'auto';
   }
 
-  // These don't have any optionUpdate entry, but they seem to be off in the native maps.
+  // These don't have any rawOptions entry, but they seem to be off in the native maps.
   options.mapTypeControl = false;
   options.fullscreenControl = false;
   options.streetViewControl = false;
@@ -102,26 +98,21 @@
 }
 
 gmaps.MapOptions _applyInitialPosition(
-  Map<String, dynamic> rawOptions,
+  CameraPosition initialPosition,
   gmaps.MapOptions options,
 ) {
   // Adjust the initial position, if passed...
-  Map<String, dynamic> initialPosition = rawOptions['initialCameraPosition'];
   if (initialPosition != null) {
-    final position = CameraPosition.fromMap(initialPosition);
-    options.zoom = position.zoom;
-    options.center =
-        gmaps.LatLng(position.target.latitude, position.target.longitude);
+    options.zoom = initialPosition.zoom;
+    options.center = gmaps.LatLng(
+        initialPosition.target.latitude, initialPosition.target.longitude);
   }
   return options;
 }
 
 // Extracts the status of the traffic layer from the rawOptions map.
 bool _isTrafficLayerEnabled(Map<String, dynamic> rawOptions) {
-  if (rawOptions['options'] == null) {
-    return false;
-  }
-  return rawOptions['options']['trafficEnabled'] ?? false;
+  return rawOptions['trafficEnabled'] ?? false;
 }
 
 // Coverts the incoming JSON object into a List of MapTypeStyler objects.
@@ -257,126 +248,6 @@
   );
 }
 
-Set<Marker> _rawOptionsToInitialMarkers(Map<String, dynamic> rawOptions) {
-  final List<Map<String, dynamic>> list = rawOptions['markersToAdd'];
-  Set<Marker> markers = {};
-  markers.addAll(list?.map((rawMarker) {
-        Offset offset;
-        LatLng position;
-        InfoWindow infoWindow;
-        BitmapDescriptor icon;
-        if (rawMarker['anchor'] != null) {
-          offset = Offset((rawMarker['anchor'][0]), (rawMarker['anchor'][1]));
-        }
-        if (rawMarker['position'] != null) {
-          position = LatLng.fromJson(rawMarker['position']);
-        }
-        if (rawMarker['infoWindow'] != null) {
-          final String title = rawMarker['infoWindow']['title'];
-          final String snippet = rawMarker['infoWindow']['snippet'];
-          if (title != null || snippet != null) {
-            infoWindow = InfoWindow(
-              title: title ?? '',
-              snippet: snippet ?? '',
-            );
-          }
-        }
-        if (rawMarker['icon'] != null) {
-          icon = BitmapDescriptor.fromJson(rawMarker['icon']);
-        }
-        return Marker(
-          markerId: MarkerId(rawMarker['markerId']),
-          alpha: rawMarker['alpha'],
-          anchor: offset,
-          consumeTapEvents: rawMarker['consumeTapEvents'],
-          draggable: rawMarker['draggable'],
-          flat: rawMarker['flat'],
-          icon: icon,
-          infoWindow: infoWindow,
-          position: position ?? _nullLatLng,
-          rotation: rawMarker['rotation'],
-          visible: rawMarker['visible'],
-          zIndex: rawMarker['zIndex'],
-        );
-      }) ??
-      []);
-  return markers;
-}
-
-Set<Circle> _rawOptionsToInitialCircles(Map<String, dynamic> rawOptions) {
-  final List<Map<String, dynamic>> list = rawOptions['circlesToAdd'];
-  Set<Circle> circles = {};
-  circles.addAll(list?.map((rawCircle) {
-        LatLng center;
-        if (rawCircle['center'] != null) {
-          center = LatLng.fromJson(rawCircle['center']);
-        }
-        return Circle(
-          circleId: CircleId(rawCircle['circleId']),
-          consumeTapEvents: rawCircle['consumeTapEvents'],
-          fillColor: Color(rawCircle['fillColor'] ?? _defaultFillColor),
-          center: center ?? _nullLatLng,
-          radius: rawCircle['radius'],
-          strokeColor: Color(rawCircle['strokeColor'] ?? _defaultStrokeColor),
-          strokeWidth: rawCircle['strokeWidth'],
-          visible: rawCircle['visible'],
-          zIndex: rawCircle['zIndex'],
-        );
-      }) ??
-      []);
-  return circles;
-}
-
-// Unsupported on the web: endCap, jointType, patterns and startCap.
-Set<Polyline> _rawOptionsToInitialPolylines(Map<String, dynamic> rawOptions) {
-  final List<Map<String, dynamic>> list = rawOptions['polylinesToAdd'];
-  Set<Polyline> polylines = {};
-  polylines.addAll(list?.map((rawPolyline) {
-        return Polyline(
-          polylineId: PolylineId(rawPolyline['polylineId']),
-          consumeTapEvents: rawPolyline['consumeTapEvents'],
-          color: Color(rawPolyline['color'] ?? _defaultStrokeColor),
-          geodesic: rawPolyline['geodesic'],
-          visible: rawPolyline['visible'],
-          zIndex: rawPolyline['zIndex'],
-          width: rawPolyline['width'],
-          points: rawPolyline['points']
-              ?.map<LatLng>((rawPoint) => LatLng.fromJson(rawPoint))
-              ?.toList(),
-        );
-      }) ??
-      []);
-  return polylines;
-}
-
-Set<Polygon> _rawOptionsToInitialPolygons(Map<String, dynamic> rawOptions) {
-  final List<Map<String, dynamic>> list = rawOptions['polygonsToAdd'];
-  Set<Polygon> polygons = {};
-
-  polygons.addAll(list?.map((rawPolygon) {
-        return Polygon(
-          polygonId: PolygonId(rawPolygon['polygonId']),
-          consumeTapEvents: rawPolygon['consumeTapEvents'],
-          fillColor: Color(rawPolygon['fillColor'] ?? _defaultFillColor),
-          geodesic: rawPolygon['geodesic'],
-          strokeColor: Color(rawPolygon['strokeColor'] ?? _defaultStrokeColor),
-          strokeWidth: rawPolygon['strokeWidth'],
-          visible: rawPolygon['visible'],
-          zIndex: rawPolygon['zIndex'],
-          points: rawPolygon['points']
-              ?.map<LatLng>((rawPoint) => LatLng.fromJson(rawPoint))
-              ?.toList(),
-          holes: rawPolygon['holes']
-              ?.map<List<LatLng>>((List hole) => hole
-                  ?.map<LatLng>((rawPoint) => LatLng.fromJson(rawPoint))
-                  ?.toList())
-              ?.toList(),
-        );
-      }) ??
-      []);
-  return polygons;
-}
-
 // Convert plugin objects to gmaps.Options objects
 // TODO: Move to their appropriate objects, maybe make these copy constructors:
 // Marker.fromMarker(anotherMarker, moreOptions);
@@ -550,7 +421,7 @@
 
 // Translates a [CameraUpdate] into operations on a [gmaps.GMap].
 void _applyCameraUpdate(gmaps.GMap map, CameraUpdate update) {
-  final json = update.toJson();
+  final json = update.toJson() as List<dynamic>;
   switch (json[0]) {
     case 'newCameraPosition':
       map.heading = json[1]['bearing'];
diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart
index 8195473..a119f2a 100644
--- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart
+++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart
@@ -14,11 +14,14 @@
   // The internal ID of the map. Used to broadcast events, DOM IDs and everything where a unique ID is needed.
   final int _mapId;
 
+  final CameraPosition _initialCameraPosition;
+  final Set<Marker> _markers;
+  final Set<Polygon> _polygons;
+  final Set<Polyline> _polylines;
+  final Set<Circle> _circles;
   // The raw options passed by the user, before converting to gmaps.
   // Caching this allows us to re-create the map faithfully when needed.
-  Map<String, dynamic> _rawOptions = {
-    'options': {},
-  };
+  Map<String, dynamic> _rawMapOptions = <String, dynamic>{};
 
   // Creates the 'viewType' for the _widget
   String _getViewType(int mapId) => 'plugins.flutter.io/google_maps_$mapId';
@@ -68,10 +71,23 @@
   GoogleMapController({
     @required int mapId,
     @required StreamController<MapEvent> streamController,
-    @required Map<String, dynamic> rawOptions,
-  })  : this._mapId = mapId,
-        this._streamController = streamController,
-        this._rawOptions = rawOptions {
+    @required CameraPosition initialCameraPosition,
+    Set<Marker> markers = const <Marker>{},
+    Set<Polygon> polygons = const <Polygon>{},
+    Set<Polyline> polylines = const <Polyline>{},
+    Set<Circle> circles = const <Circle>{},
+    Set<TileOverlay> tileOverlays = const <TileOverlay>{},
+    Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers =
+        const <Factory<OneSequenceGestureRecognizer>>{},
+    Map<String, dynamic> mapOptions = const <String, dynamic>{},
+  })  : _mapId = mapId,
+        _streamController = streamController,
+        _initialCameraPosition = initialCameraPosition,
+        _markers = markers,
+        _polygons = polygons,
+        _polylines = polylines,
+        _circles = circles,
+        _rawMapOptions = mapOptions {
     _circlesController = CirclesController(stream: this._streamController);
     _polygonsController = PolygonsController(stream: this._streamController);
     _polylinesController = PolylinesController(stream: this._streamController);
@@ -121,9 +137,9 @@
   /// Failure to call this method would result in the GMap not rendering at all,
   /// and most of the public methods on this class no-op'ing.
   void init() {
-    var options = _rawOptionsToGmapsOptions(_rawOptions);
+    var options = _rawOptionsToGmapsOptions(_rawMapOptions);
     // Initial position can only to be set here!
-    options = _applyInitialPosition(_rawOptions, options);
+    options = _applyInitialPosition(_initialCameraPosition, options);
 
     // Create the map...
     _googleMap = _createMap(_div, options);
@@ -132,13 +148,13 @@
     _attachGeometryControllers(_googleMap);
 
     _renderInitialGeometry(
-      markers: _rawOptionsToInitialMarkers(_rawOptions),
-      circles: _rawOptionsToInitialCircles(_rawOptions),
-      polygons: _rawOptionsToInitialPolygons(_rawOptions),
-      polylines: _rawOptionsToInitialPolylines(_rawOptions),
+      markers: _markers,
+      circles: _circles,
+      polygons: _polygons,
+      polylines: _polylines,
     );
 
-    _setTrafficLayer(_googleMap, _isTrafficLayerEnabled(_rawOptions));
+    _setTrafficLayer(_googleMap, _isTrafficLayerEnabled(_rawMapOptions));
   }
 
   // Funnels map gmap events into the plugin's stream controller.
@@ -196,20 +212,15 @@
     _polylinesController.addPolylines(polylines);
   }
 
-  // Merges new options coming from the plugin into the `key` entry of the _rawOptions map.
+  // Merges new options coming from the plugin into the _rawMapOptions map.
   //
-  // By default: `key` is 'options'.
-  //
-  // Returns the updated _rawOptions object.
-  Map<String, dynamic> _mergeRawOptions(
-    Map<String, dynamic> newOptions, {
-    String key = 'options',
-  }) {
-    _rawOptions[key] = <String, dynamic>{
-      ...(_rawOptions[key] ?? {}),
+  // Returns the updated _rawMapOptions object.
+  Map<String, dynamic> _mergeRawOptions(Map<String, dynamic> newOptions) {
+    _rawMapOptions = <String, dynamic>{
+      ..._rawMapOptions,
       ...newOptions,
     };
-    return _rawOptions;
+    return _rawMapOptions;
   }
 
   /// Updates the map options from a `Map<String, dynamic>`.
diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart
index cf549e8..cb2a8aa 100644
--- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart
+++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart
@@ -86,6 +86,22 @@
     _map(mapId).updateCircles(circleUpdates);
   }
 
+  @override
+  Future<void> updateTileOverlays({
+    @required Set<TileOverlay> newTileOverlays,
+    @required int mapId,
+  }) async {
+    return; // Noop for now!
+  }
+
+  @override
+  Future<void> clearTileCache(
+    TileOverlayId tileOverlayId, {
+    @required int mapId,
+  }) async {
+    return; // Noop for now!
+  }
+
   /// Applies the given `cameraUpdate` to the current viewport (with animation).
   @override
   Future<void> animateCamera(
@@ -260,31 +276,43 @@
 
   @override
   Widget buildView(
-      Map<String, dynamic> creationParams,
-      Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers,
-      PlatformViewCreatedCallback onPlatformViewCreated) {
-    int mapId = creationParams.remove('_webOnlyMapCreationId');
-
-    assert(mapId != null,
+    int creationId,
+    PlatformViewCreatedCallback onPlatformViewCreated, {
+    @required CameraPosition initialCameraPosition,
+    Set<Marker> markers = const <Marker>{},
+    Set<Polygon> polygons = const <Polygon>{},
+    Set<Polyline> polylines = const <Polyline>{},
+    Set<Circle> circles = const <Circle>{},
+    Set<TileOverlay> tileOverlays = const <TileOverlay>{},
+    Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers =
+        const <Factory<OneSequenceGestureRecognizer>>{},
+    Map<String, dynamic> mapOptions = const <String, dynamic>{},
+  }) {
+    assert(creationId != null,
         'buildView needs a `_webOnlyMapCreationId` in its creationParams to prevent widget reloads in web.');
 
-    // Bail fast if we've already rendered this mapId...
-    if (_mapById[mapId]?.widget != null) {
-      return _mapById[mapId].widget;
+    // Bail fast if we've already rendered this map ID...
+    if (_mapById[creationId]?.widget != null) {
+      return _mapById[creationId].widget;
     }
 
     final StreamController<MapEvent> controller =
         StreamController<MapEvent>.broadcast();
 
     final mapController = GoogleMapController(
-      mapId: mapId,
+      initialCameraPosition: initialCameraPosition,
+      mapId: creationId,
       streamController: controller,
-      rawOptions: creationParams,
+      markers: markers,
+      polygons: polygons,
+      polylines: polylines,
+      circles: circles,
+      mapOptions: mapOptions,
     );
 
-    _mapById[mapId] = mapController;
+    _mapById[creationId] = mapController;
 
-    onPlatformViewCreated.call(mapId);
+    onPlatformViewCreated.call(creationId);
 
     return mapController.widget;
   }
diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml
index 595ca20..20d0782 100644
--- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml
+++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml
@@ -1,7 +1,7 @@
 name: google_maps_flutter_web
 description: Web platform implementation of google_maps_flutter
 homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter
-version: 0.1.2
+version: 0.2.0
 
 flutter:
   plugin:
@@ -15,19 +15,19 @@
     sdk: flutter
   flutter_web_plugins:
     sdk: flutter
-  meta: ^1.1.7
-  google_maps_flutter_platform_interface: ^1.1.0
+  meta: ^1.3.0
+  google_maps_flutter_platform_interface: ^2.0.1
   google_maps: ^3.4.5
-  stream_transform: ^1.2.0
-  sanitize_html: ^1.4.1
+  stream_transform: ^2.0.0
+  sanitize_html: ^2.0.0
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
-  http: ^0.12.2
-  url_launcher: ^5.2.5
+  http: ^0.13.0
+  url_launcher: ^6.0.2
   pedantic: ^1.8.0
-  mockito: ^4.1.1
+  mockito: ^5.0.0
   integration_test:
     path: ../../integration_test
 
diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart
index 302057f..0eca5b8 100644
--- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart
+++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart
@@ -50,11 +50,24 @@
     StreamController<MapEvent> stream;
 
     // Creates a controller with the default mapId and stream controller, and any `options` needed.
-    GoogleMapController _createController({Map<String, dynamic> options}) {
+    GoogleMapController _createController({
+      CameraPosition initialCameraPosition =
+          const CameraPosition(target: LatLng(0, 0)),
+      Set<Marker> markers = const <Marker>{},
+      Set<Polygon> polygons = const <Polygon>{},
+      Set<Polyline> polylines = const <Polyline>{},
+      Set<Circle> circles = const <Circle>{},
+      Map<String, dynamic> options,
+    }) {
       return GoogleMapController(
           mapId: mapId,
           streamController: stream,
-          rawOptions: options ?? <String, dynamic>{});
+          initialCameraPosition: initialCameraPosition,
+          markers: markers,
+          polygons: polygons,
+          polylines: polylines,
+          circles: circles,
+          mapOptions: options ?? <String, dynamic>{});
     }
 
     setUp(() {
@@ -143,58 +156,45 @@
       });
 
       testWidgets('renders initial geometry', (WidgetTester tester) async {
-        controller = _createController(options: {
-          'circlesToAdd': [
-            {'circleId': 'circle-1'}
-          ],
-          'markersToAdd': [
-            {
-              'markerId': 'marker-1',
-              'infoWindow': {
-                'title': 'title for test',
-                'snippet': 'snippet for test',
-              },
-            },
-          ],
-          'polygonsToAdd': [
-            {
-              'polygonId': 'polygon-1',
-              'points': [
-                [43.355114, -5.851333],
-                [43.354797, -5.851860],
-                [43.354469, -5.851318],
-                [43.354762, -5.850824],
-              ],
-            },
-            {
-              'polygonId': 'polygon-2-with-holes',
-              'points': [
-                [43.355114, -5.851333],
-                [43.354797, -5.851860],
-                [43.354469, -5.851318],
-                [43.354762, -5.850824],
-              ],
-              'holes': [
-                [
-                  [41.354797, -6.851860],
-                  [41.354469, -6.851318],
-                  [41.354762, -6.850824],
-                ]
+        controller = _createController(circles: <Circle>{
+          Circle(circleId: CircleId('circle-1'))
+        }, markers: <Marker>{
+          Marker(
+              markerId: MarkerId('marker-1'),
+              infoWindow: InfoWindow(
+                  title: 'title for test', snippet: 'snippet for test'))
+        }, polygons: {
+          Polygon(polygonId: PolygonId('polygon-1'), points: [
+            LatLng(43.355114, -5.851333),
+            LatLng(43.354797, -5.851860),
+            LatLng(43.354469, -5.851318),
+            LatLng(43.354762, -5.850824),
+          ]),
+          Polygon(
+            polygonId: PolygonId('polygon-2-with-holes'),
+            points: [
+              LatLng(43.355114, -5.851333),
+              LatLng(43.354797, -5.851860),
+              LatLng(43.354469, -5.851318),
+              LatLng(43.354762, -5.850824),
+            ],
+            holes: [
+              [
+                LatLng(41.354797, -6.851860),
+                LatLng(41.354469, -6.851318),
+                LatLng(41.354762, -6.850824),
               ]
-            },
-          ],
-          'polylinesToAdd': [
-            {
-              'polylineId': 'polyline-1',
-              'points': [
-                [43.355114, -5.851333],
-                [43.354797, -5.851860],
-                [43.354469, -5.851318],
-                [43.354762, -5.850824],
-              ],
-            },
-          ],
+            ],
+          ),
+        }, polylines: {
+          Polyline(polylineId: PolylineId('polyline-1'), points: [
+            LatLng(43.355114, -5.851333),
+            LatLng(43.354797, -5.851860),
+            LatLng(43.354469, -5.851318),
+            LatLng(43.354762, -5.850824),
+          ])
         });
+
         controller.debugSetOverrides(
           circles: circles,
           markers: markers,
@@ -226,14 +226,10 @@
 
       testWidgets('empty infoWindow does not create InfoWindow instance.',
           (WidgetTester tester) async {
-        controller = _createController(options: {
-          'markersToAdd': [
-            {
-              'markerId': 'marker-1',
-              'infoWindow': {},
-            },
-          ],
+        controller = _createController(markers: {
+          Marker(markerId: MarkerId('marker-1'), infoWindow: null),
         });
+
         controller.debugSetOverrides(
           markers: markers,
         );
@@ -253,10 +249,8 @@
         });
         testWidgets('translates initial options', (WidgetTester tester) async {
           controller = _createController(options: {
-            'options': {
-              'mapType': 2,
-              'zoomControlsEnabled': true,
-            }
+            'mapType': 2,
+            'zoomControlsEnabled': true,
           });
           controller.debugSetOverrides(createMap: (_, options) {
             capturedOptions = options;
@@ -276,9 +270,7 @@
         testWidgets('disables gestureHandling with scrollGesturesEnabled false',
             (WidgetTester tester) async {
           controller = _createController(options: {
-            'options': {
-              'scrollGesturesEnabled': false,
-            }
+            'scrollGesturesEnabled': false,
           });
           controller.debugSetOverrides(createMap: (_, options) {
             capturedOptions = options;
@@ -296,9 +288,7 @@
         testWidgets('disables gestureHandling with zoomGesturesEnabled false',
             (WidgetTester tester) async {
           controller = _createController(options: {
-            'options': {
-              'zoomGesturesEnabled': false,
-            }
+            'zoomGesturesEnabled': false,
           });
           controller.debugSetOverrides(createMap: (_, options) {
             capturedOptions = options;
@@ -315,7 +305,10 @@
 
         testWidgets('does not set initial position if absent',
             (WidgetTester tester) async {
-          controller = _createController();
+          controller = _createController(
+            initialCameraPosition: null,
+          );
+
           controller.debugSetOverrides(createMap: (_, options) {
             capturedOptions = options;
             return map;
@@ -330,14 +323,15 @@
 
         testWidgets('sets initial position when passed',
             (WidgetTester tester) async {
-          controller = _createController(options: {
-            'initialCameraPosition': {
-              'target': [43.308, -5.6910],
-              'zoom': 12,
-              'bearing': 0,
-              'tilt': 0,
-            }
-          });
+          controller = _createController(
+            initialCameraPosition: CameraPosition(
+              target: LatLng(43.308, -5.6910),
+              zoom: 12,
+              bearing: 0,
+              tilt: 0,
+            ),
+          );
+
           controller.debugSetOverrides(createMap: (_, options) {
             capturedOptions = options;
             return map;
@@ -361,9 +355,7 @@
         testWidgets('initializes with traffic layer',
             (WidgetTester tester) async {
           controller = _createController(options: {
-            'options': {
-              'trafficEnabled': true,
-            }
+            'trafficEnabled': true,
           });
           controller.debugSetOverrides(createMap: (_, __) => map);
           controller.init();
diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart
index 6276d26..f0cae1d 100644
--- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart
+++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_plugin_integration.dart
@@ -70,11 +70,16 @@
 
     group('buildView', () {
       final testMapId = 33930;
+      final initialCameraPosition = CameraPosition(target: LatLng(0, 0));
 
       testWidgets('throws without _webOnlyMapCreationId',
           (WidgetTester tester) async {
         expect(
-          () => plugin.buildView({}, null, onPlatformViewCreated),
+          () => plugin.buildView(
+            null,
+            onPlatformViewCreated,
+            initialCameraPosition: initialCameraPosition,
+          ),
           throwsAssertionError,
           reason:
               '_webOnlyMapCreationId is mandatory to prevent unnecessary reloads in web.',
@@ -87,9 +92,11 @@
         final Map<int, GoogleMapController> cache = {};
         plugin.debugSetMapById(cache);
 
-        final HtmlElementView widget = plugin.buildView({
-          '_webOnlyMapCreationId': testMapId,
-        }, null, onPlatformViewCreated);
+        final HtmlElementView widget = plugin.buildView(
+          testMapId,
+          onPlatformViewCreated,
+          initialCameraPosition: initialCameraPosition,
+        );
 
         expect(
           widget.viewType,
@@ -116,9 +123,11 @@
         when(controller.widget).thenReturn(expected);
         plugin.debugSetMapById({testMapId: controller});
 
-        final widget = plugin.buildView({
-          '_webOnlyMapCreationId': testMapId,
-        }, null, onPlatformViewCreated);
+        final widget = plugin.buildView(
+          testMapId,
+          onPlatformViewCreated,
+          initialCameraPosition: initialCameraPosition,
+        );
 
         expect(widget, equals(expected));
         expect(
@@ -159,6 +168,24 @@
       });
     });
 
+    group('Noop methods:', () {
+      int mapId = 0;
+      setUp(() {
+        plugin.debugSetMapById({mapId: controller});
+      });
+      // Options
+      testWidgets('updateTileOverlays', (WidgetTester tester) async {
+        final update =
+            plugin.updateTileOverlays(mapId: mapId, newTileOverlays: {});
+        expect(update, completion(null));
+      });
+      testWidgets('updateTileOverlays', (WidgetTester tester) async {
+        final update =
+            plugin.clearTileCache(TileOverlayId('any'), mapId: mapId);
+        expect(update, completion(null));
+      });
+    });
+
     // These methods only pass-through values from the plugin to the controller
     // so we verify them all together here...
     group('Pass-through methods:', () {
@@ -176,28 +203,28 @@
       });
       // Geometry
       testWidgets('updateMarkers', (WidgetTester tester) async {
-        final expectedUpdates = MarkerUpdates.from(null, null);
+        final expectedUpdates = MarkerUpdates.from({}, {});
 
         await plugin.updateMarkers(expectedUpdates, mapId: mapId);
 
         verify(controller.updateMarkers(expectedUpdates));
       });
       testWidgets('updatePolygons', (WidgetTester tester) async {
-        final expectedUpdates = PolygonUpdates.from(null, null);
+        final expectedUpdates = PolygonUpdates.from({}, {});
 
         await plugin.updatePolygons(expectedUpdates, mapId: mapId);
 
         verify(controller.updatePolygons(expectedUpdates));
       });
       testWidgets('updatePolylines', (WidgetTester tester) async {
-        final expectedUpdates = PolylineUpdates.from(null, null);
+        final expectedUpdates = PolylineUpdates.from({}, {});
 
         await plugin.updatePolylines(expectedUpdates, mapId: mapId);
 
         verify(controller.updatePolylines(expectedUpdates));
       });
       testWidgets('updateCircles', (WidgetTester tester) async {
-        final expectedUpdates = CircleUpdates.from(null, null);
+        final expectedUpdates = CircleUpdates.from({}, {});
 
         await plugin.updateCircles(expectedUpdates, mapId: mapId);
 
diff --git a/script/nnbd_plugins.sh b/script/nnbd_plugins.sh
index fb5f8ea..5681775 100644
--- a/script/nnbd_plugins.sh
+++ b/script/nnbd_plugins.sh
@@ -34,6 +34,7 @@
   "webview_flutter"
   "wifi_info_flutter"
   "in_app_purchase"
+  "google_maps_flutter_web" # Not yet migrated, but compatible with others
 )
 
 # This list contains the list of plugins that have *not* been
@@ -41,8 +42,7 @@
 # building the all plugins app. This list should be kept empty.
 
 readonly NON_NNBD_PLUGINS_LIST=(
-  "extension_google_sign_in_as_googleapis_auth"
-  "google_maps_flutter_web" # Not yet migrated.
+  "extension_google_sign_in_as_googleapis_auth" # Some deps are still clashing
 )
 
 export EXCLUDED_PLUGINS_FROM_STABLE=$(IFS=, ; echo "${NNBD_PLUGINS_LIST[*]}")