Skip to content

[google_maps] Prepares packages to endorse web. #4064

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
May 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ac818b0
[google_maps] Split integration_test in 3 smaller files.
ditman May 20, 2023
924153d
Add inspector to tiles_test.dart.
ditman May 20, 2023
c0eeaa0
Rename tests
ditman May 20, 2023
1c56de2
Fix maps_inspector_test.dart (only map rendering)
ditman May 20, 2023
df24182
Make maps_controller_test run on web.
ditman May 23, 2023
c3b1a79
[maps_platform] Move mipmap unit test from core plugin to here.
ditman May 23, 2023
f45f3bd
dart format .
ditman May 23, 2023
e0b0586
[maps_web] Expose map and options getters.
ditman May 23, 2023
958b142
[maps_web] Add a Google Maps Inspector (and connect it).
ditman May 23, 2023
33fab46
[maps_web] Fire MapStyleException when receiving invalid style JSON.
ditman May 23, 2023
e21a047
[maps_web] Update CHANGELOG and pubspec.
ditman May 23, 2023
20749f4
[maps_platform] Remove unnecessary imports.
ditman May 23, 2023
a170ed6
Last attempt for test.
ditman May 23, 2023
e41c042
Remove deprecated API use.
ditman May 23, 2023
618ae0c
Revert test so it passes in Android
ditman May 23, 2023
33d5ca4
Address some PR comments:
ditman May 25, 2023
ebdf7e6
Version _web update as MAJOR.
ditman May 25, 2023
1d1cfe6
Update mocks.
ditman May 25, 2023
8436be4
Updates http dev_dependency.
ditman May 26, 2023
6a8da78
Update mockito mocks.
ditman May 26, 2023
ceb4e19
Recombine integration_tests in a single one.
ditman May 31, 2023
10160c0
Clarify configuration accessor on a GoogleMapsController.
ditman May 31, 2023
9cde458
Add run_test.sh for web convenience.
ditman May 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file contains shared definitions used across multiple test scenarios.

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

/// Initial map center
const LatLng kInitialMapCenter = LatLng(0, 0);

/// Initial zoom level
const double kInitialZoomLevel = 5;

/// Initial camera position
const CameraPosition kInitialCameraPosition =
CameraPosition(target: kInitialMapCenter, zoom: kInitialZoomLevel);

/// True if the test is running in an iOS device
final bool isIOS = defaultTargetPlatform == TargetPlatform.iOS;

/// True if the test is running in an Android device
final bool isAndroid =
defaultTargetPlatform == TargetPlatform.android && !kIsWeb;

/// True if the test is running in a web browser.
const bool isWeb = kIsWeb;

/// Pumps a [map] widget in [tester] of a certain [size], then waits until it settles.
Future<void> pumpMap(WidgetTester tester, GoogleMap map,
[Size size = const Size.square(200)]) async {
await tester.pumpWidget(wrapMap(map, size));
await tester.pumpAndSettle();
}

/// Wraps a [map] in a bunch of widgets so it renders in all platforms.
///
/// An optional [size] can be passed.
Widget wrapMap(GoogleMap map, [Size size = const Size.square(200)]) {
return MaterialApp(
home: Scaffold(
body: Center(
child: SizedBox.fromSize(
size: size,
child: map,
),
),
),
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
import 'dart:ui' as ui;

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
import 'package:integration_test/integration_test.dart';

import 'shared.dart';

/// Integration Tests for the Tiles feature. These also use the [GoogleMapsInspectorPlatform].
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
runTests();
}

void runTests() {
GoogleMapsFlutterPlatform.instance.enableDebugInspection();

final GoogleMapsInspectorPlatform inspector =
GoogleMapsInspectorPlatform.instance!;

group('Tiles', () {
testWidgets(
'set tileOverlay correctly',
(WidgetTester tester) async {
final Completer<int> mapIdCompleter = Completer<int>();
final TileOverlay tileOverlay1 = TileOverlay(
tileOverlayId: const TileOverlayId('tile_overlay_1'),
tileProvider: _DebugTileProvider(),
zIndex: 2,
transparency: 0.2,
);

final TileOverlay tileOverlay2 = TileOverlay(
tileOverlayId: const TileOverlayId('tile_overlay_2'),
tileProvider: _DebugTileProvider(),
zIndex: 1,
visible: false,
transparency: 0.3,
fadeIn: false,
);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: GoogleMap(
initialCameraPosition: kInitialCameraPosition,
tileOverlays: <TileOverlay>{tileOverlay1, tileOverlay2},
onMapCreated: (GoogleMapController controller) {
mapIdCompleter.complete(controller.mapId);
},
),
),
);
await tester.pumpAndSettle(const Duration(seconds: 3));

final int mapId = await mapIdCompleter.future;

final TileOverlay tileOverlayInfo1 = (await inspector
.getTileOverlayInfo(tileOverlay1.mapsId, mapId: mapId))!;
final TileOverlay tileOverlayInfo2 = (await inspector
.getTileOverlayInfo(tileOverlay2.mapsId, mapId: mapId))!;

expect(tileOverlayInfo1.visible, isTrue);
expect(tileOverlayInfo1.fadeIn, isTrue);
expect(tileOverlayInfo1.transparency,
moreOrLessEquals(0.2, epsilon: 0.001));
expect(tileOverlayInfo1.zIndex, 2);

expect(tileOverlayInfo2.visible, isFalse);
expect(tileOverlayInfo2.fadeIn, isFalse);
expect(tileOverlayInfo2.transparency,
moreOrLessEquals(0.3, epsilon: 0.001));
expect(tileOverlayInfo2.zIndex, 1);
},
);

testWidgets(
'update tileOverlays correctly',
(WidgetTester tester) async {
final Completer<int> mapIdCompleter = Completer<int>();
final Key key = GlobalKey();
final TileOverlay tileOverlay1 = TileOverlay(
tileOverlayId: const TileOverlayId('tile_overlay_1'),
tileProvider: _DebugTileProvider(),
zIndex: 2,
transparency: 0.2,
);

final TileOverlay tileOverlay2 = TileOverlay(
tileOverlayId: const TileOverlayId('tile_overlay_2'),
tileProvider: _DebugTileProvider(),
zIndex: 3,
transparency: 0.5,
);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: GoogleMap(
key: key,
initialCameraPosition: kInitialCameraPosition,
tileOverlays: <TileOverlay>{tileOverlay1, tileOverlay2},
onMapCreated: (GoogleMapController controller) {
mapIdCompleter.complete(controller.mapId);
},
),
),
);

final int mapId = await mapIdCompleter.future;

final TileOverlay tileOverlay1New = TileOverlay(
tileOverlayId: const TileOverlayId('tile_overlay_1'),
tileProvider: _DebugTileProvider(),
zIndex: 1,
visible: false,
transparency: 0.3,
fadeIn: false,
);

await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: GoogleMap(
key: key,
initialCameraPosition: kInitialCameraPosition,
tileOverlays: <TileOverlay>{tileOverlay1New},
onMapCreated: (GoogleMapController controller) {
fail('update: OnMapCreated should get called only once.');
},
),
),
);

await tester.pumpAndSettle(const Duration(seconds: 3));

final TileOverlay tileOverlayInfo1 = (await inspector
.getTileOverlayInfo(tileOverlay1.mapsId, mapId: mapId))!;
final TileOverlay? tileOverlayInfo2 = await inspector
.getTileOverlayInfo(tileOverlay2.mapsId, mapId: mapId);

expect(tileOverlayInfo1.visible, isFalse);
expect(tileOverlayInfo1.fadeIn, isFalse);
expect(tileOverlayInfo1.transparency,
moreOrLessEquals(0.3, epsilon: 0.001));
expect(tileOverlayInfo1.zIndex, 1);

expect(tileOverlayInfo2, isNull);
},
);

testWidgets(
'remove tileOverlays correctly',
(WidgetTester tester) async {
final Completer<int> mapIdCompleter = Completer<int>();
final Key key = GlobalKey();
final TileOverlay tileOverlay1 = TileOverlay(
tileOverlayId: const TileOverlayId('tile_overlay_1'),
tileProvider: _DebugTileProvider(),
zIndex: 2,
transparency: 0.2,
);

await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: GoogleMap(
key: key,
initialCameraPosition: kInitialCameraPosition,
tileOverlays: <TileOverlay>{tileOverlay1},
onMapCreated: (GoogleMapController controller) {
mapIdCompleter.complete(controller.mapId);
},
),
),
);

final int mapId = await mapIdCompleter.future;

await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: GoogleMap(
key: key,
initialCameraPosition: kInitialCameraPosition,
onMapCreated: (GoogleMapController controller) {
fail('OnMapCreated should get called only once.');
},
),
),
);

await tester.pumpAndSettle(const Duration(seconds: 3));
final TileOverlay? tileOverlayInfo1 = await inspector
.getTileOverlayInfo(tileOverlay1.mapsId, mapId: mapId);

expect(tileOverlayInfo1, isNull);
},
);
}, skip: isWeb /* Tiles not supported on the web */);
}

class _DebugTileProvider implements TileProvider {
_DebugTileProvider() {
boxPaint.isAntiAlias = true;
boxPaint.color = Colors.blue;
boxPaint.strokeWidth = 2.0;
boxPaint.style = PaintingStyle.stroke;
}

static const int width = 100;
static const int height = 100;
static final Paint boxPaint = Paint();
static const TextStyle textStyle = TextStyle(
color: Colors.red,
fontSize: 20,
);

@override
Future<Tile> getTile(int x, int y, int? zoom) async {
final ui.PictureRecorder recorder = ui.PictureRecorder();
final Canvas canvas = Canvas(recorder);
final TextSpan textSpan = TextSpan(
text: '$x,$y',
style: textStyle,
);
final TextPainter textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
);
textPainter.layout(
maxWidth: width.toDouble(),
);
textPainter.paint(canvas, Offset.zero);
canvas.drawRect(
Rect.fromLTRB(0, 0, width.toDouble(), width.toDouble()), boxPaint);
final ui.Picture picture = recorder.endRecording();
final Uint8List byteData = await picture
.toImage(width, height)
.then((ui.Image image) =>
image.toByteData(format: ui.ImageByteFormat.png))
.then((ByteData? byteData) => byteData!.buffer.asUint8List());
return Tile(width, height, byteData);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/bash
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

if pgrep -lf chromedriver > /dev/null; then
echo "chromedriver is running."

if [ $# -eq 0 ]; then
echo "No target specified, running all tests..."
find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}'
else
echo "Running test target: $1..."
set -x
flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target=$1
fi

else
echo "chromedriver is not running."
echo "Please, check the README.md for instructions on how to use run_test.sh"
fi

Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore:unnecessary_import
import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
Expand Down Expand Up @@ -171,6 +167,26 @@ void main() {
<dynamic>['fromAssetImage', 'some/path.png', 1.0]),
isA<BitmapDescriptor>());
});

test('mipmaps determines dpi', () async {
const ImageConfiguration imageConfiguration = ImageConfiguration(
devicePixelRatio: 3,
);

final BitmapDescriptor mip = await BitmapDescriptor.fromAssetImage(
imageConfiguration,
'red_square.png',
);
final BitmapDescriptor scaled = await BitmapDescriptor.fromAssetImage(
imageConfiguration,
'red_square.png',
mipmaps: false,
);

expect((mip.toJson() as List<dynamic>)[2], 1);
expect((scaled.toJson() as List<dynamic>)[2], 3);
});

test('name cannot be null or empty', () {
expect(() {
BitmapDescriptor.fromJson(<dynamic>['fromAssetImage', null, 1.0]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 0.5.0

* **BREAKING CHANGE:** Fires a `MapStyleException` when an invalid JSON is used
in `setMapStyle` (was `FormatException` previously).
* Implements a `GoogleMapsInspectorPlatform` to allow integration tests to inspect
parts of the internal state of a map.

## 0.4.0+9

* Removes obsolete null checks on non-nullable values.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Mocks generated by Mockito 5.4.0 from annotations
// Mocks generated by Mockito 5.4.1 from annotations
// in google_maps_flutter_web_integration_tests/integration_test/google_maps_controller_test.dart.
// Do not manually edit this file.

// @dart=2.19

// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:google_maps/google_maps.dart' as _i2;
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'
Expand Down
Loading