[web] Make window.locale(s) non-null; upgrade to null safe deps (flutter/engine#24922)

* Make window.locale(s) non-null

* upgrade deps to null-safe; migrate some test libs
This commit is contained in:
Yegor 2021-03-11 14:28:49 -08:00 committed by GitHub
parent 87509d8518
commit 5a5f326745
9 changed files with 77 additions and 67 deletions

View File

@ -270,7 +270,7 @@ Future<String> fetchLatestChromeVersion() async {
final Client client = Client();
try {
final Response response = await client.get(
'https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2FLAST_CHANGE?alt=media');
Uri.parse('https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2FLAST_CHANGE?alt=media'));
if (response.statusCode != 200) {
throw BrowserInstallerException(
'Failed to fetch latest Chrome version. Server returned status code ${response.statusCode}');

View File

@ -32,8 +32,8 @@ abstract class SingletonFlutterWindow extends FlutterWindow {
platformDispatcher.onMetricsChanged = callback;
}
Locale? get locale => platformDispatcher.locale;
List<Locale>? get locales => platformDispatcher.locales;
Locale get locale => platformDispatcher.locale;
List<Locale> get locales => platformDispatcher.locales;
Locale? computePlatformResolvedLocale(List<Locale> supportedLocales) {
return platformDispatcher.computePlatformResolvedLocale(supportedLocales);

View File

@ -5,20 +5,21 @@ environment:
sdk: ">=2.12.0-0 <3.0.0"
dependencies:
js: 0.6.3-nullsafety.3
meta: 1.3.0-nullsafety.6
js: 0.6.3
meta: 1.3.0
dev_dependencies:
analyzer: 0.39.15
archive: 2.0.13
http: 0.12.1
image: 2.1.13
mockito: 4.1.1
path: 1.8.0-nullsafety.3
test: 1.16.0-nullsafety.9
quiver: 3.0.0-nullsafety.2
yaml: 2.2.1
watcher: 0.9.7+15
analyzer: 1.1.0
archive: 3.1.2
html: 0.15.0
http: 0.13.0
image: 3.0.1
mockito: 5.0.0
path: 1.8.0
quiver: 3.0.0
test: 1.16.6
yaml: 3.0.0
watcher: 1.0.0
web_test_utils:
path: ../../web_sdk/web_test_utils
web_engine_tester:
@ -32,4 +33,4 @@ dev_dependencies:
git:
url: git://github.com/flutter/web_installers.git
path: packages/web_drivers/
ref: 58081a8b2fbf234e9c8da86fce28adfefe3c2093
ref: 946111ae3248132e3773bf5c5327bcbbefa0c5f2

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
// @dart = 2.12
@TestOn('!safari')
// TODO(nurhan): https://github.com/flutter/flutter/issues/51169
@ -471,14 +471,14 @@ void testMain() {
});
group('$HashUrlStrategy', () {
TestPlatformLocation location;
late TestPlatformLocation location;
setUp(() {
location = TestPlatformLocation();
});
tearDown(() {
location = null;
location = TestPlatformLocation();
});
test('leading slash is optional', () {
@ -544,11 +544,15 @@ Future<void> systemNavigatorPop() {
/// A mock implementation of [PlatformLocation] that doesn't access the browser.
class TestPlatformLocation extends PlatformLocation {
String pathname;
String search;
String hash;
String? hash;
dynamic state;
@override
String get pathname => throw UnimplementedError();
@override
String get search => throw UnimplementedError();
@override
void addPopStateListener(html.EventListener fn) {
throw UnimplementedError();

View File

@ -3,7 +3,7 @@
// found in the LICENSE file.
/// Provides utilities for testing engine code.
// @dart = 2.6
// @dart = 2.12
library matchers;
import 'dart:html' as html;
@ -12,7 +12,6 @@ import 'dart:math' as math;
import 'package:html/parser.dart' as html_package;
import 'package:html/dom.dart' as html_package;
import 'package:meta/meta.dart';
import 'package:test/test.dart';
import 'package:ui/ui.dart';
@ -23,9 +22,9 @@ import 'package:ui/src/engine.dart';
/// If [root] is `null` returns all surfaces from the last rendered scene.
///
/// Surfaces are returned in a depth-first order.
Iterable<PersistedSurface> enumerateSurfaces([PersistedSurface root]) {
Iterable<PersistedSurface> enumerateSurfaces([PersistedSurface? root]) {
root ??= SurfaceSceneBuilder.debugLastFrameScene;
final List<PersistedSurface> surfaces = <PersistedSurface>[root];
final List<PersistedSurface> surfaces = <PersistedSurface>[root!];
root.visitChildren((PersistedSurface surface) {
surfaces.addAll(enumerateSurfaces(surface));
@ -37,7 +36,7 @@ Iterable<PersistedSurface> enumerateSurfaces([PersistedSurface root]) {
/// Enumerates all pictures nested under [root].
///
/// If [root] is `null` returns all pictures from the last rendered scene.
Iterable<PersistedPicture> enumeratePictures([PersistedSurface root]) {
Iterable<PersistedPicture> enumeratePictures([PersistedSurface? root]) {
root ??= SurfaceSceneBuilder.debugLastFrameScene;
return enumerateSurfaces(root).whereType<PersistedPicture>();
}
@ -45,7 +44,7 @@ Iterable<PersistedPicture> enumeratePictures([PersistedSurface root]) {
/// Enumerates all offset surfaces nested under [root].
///
/// If [root] is `null` returns all pictures from the last rendered scene.
Iterable<PersistedOffset> enumerateOffsets([PersistedSurface root]) {
Iterable<PersistedOffset> enumerateOffsets([PersistedSurface? root]) {
root ??= SurfaceSceneBuilder.debugLastFrameScene;
return enumerateSurfaces(root).whereType<PersistedOffset>();
}
@ -76,7 +75,7 @@ typedef DistanceFunction<T> = num Function(T a, T b);
///
/// Calling an instance of this type must either be done dynamically, or by
/// first casting it to a [DistanceFunction<T>] for some concrete T.
typedef AnyDistanceFunction = num Function(Null a, Null b);
typedef AnyDistanceFunction = num Function(Never a, Never b);
const Map<Type, AnyDistanceFunction> _kStandardDistanceFunctions =
<Type, AnyDistanceFunction>{
@ -108,7 +107,7 @@ double _rectDistance(Rect a, Rect b) {
}
double _sizeDistance(Size a, Size b) {
final Offset delta = b - a;
final Offset delta = (b - a) as Offset;
return delta.distance;
}
@ -134,11 +133,11 @@ double _sizeDistance(Size a, Size b) {
/// [double]s and has an optional `epsilon` parameter.
/// * [closeTo], which specializes in numbers only.
Matcher within<T>({
@required num distance,
@required T from,
DistanceFunction<T> distanceFunction,
required num distance,
required T from,
DistanceFunction<T>? distanceFunction,
}) {
distanceFunction ??= _kStandardDistanceFunctions[T];
distanceFunction ??= _kStandardDistanceFunctions[T] as DistanceFunction<T>?;
if (distanceFunction == null) {
throw ArgumentError(
@ -158,7 +157,7 @@ class _IsWithinDistance<T> extends Matcher {
final num epsilon;
@override
bool matches(Object object, Map<dynamic, dynamic> matchState) {
bool matches(Object? object, Map<dynamic, dynamic> matchState) {
if (object is! T) {
return false;
}
@ -183,7 +182,7 @@ class _IsWithinDistance<T> extends Matcher {
@override
Description describeMismatch(
Object object,
Object? object,
Description mismatchDescription,
Map<dynamic, dynamic> matchState,
bool verbose,
@ -230,11 +229,11 @@ enum HtmlComparisonMode {
String canonicalizeHtml(String htmlContent,
{HtmlComparisonMode mode = HtmlComparisonMode.nonLayoutOnly,
bool throwOnUnusedAttributes = false}) {
if (htmlContent == null || htmlContent.trim().isEmpty) {
if (htmlContent.trim().isEmpty) {
return '';
}
String _unusedAttribute(String name) {
String? _unusedAttribute(String name) {
if (throwOnUnusedAttributes) {
fail('Provided HTML contains style attribute "$name" which '
'is not used for comparison in the test. The HTML was:\n\n$htmlContent');
@ -244,7 +243,7 @@ String canonicalizeHtml(String htmlContent,
}
html_package.Element _cleanup(html_package.Element original) {
String replacementTag = original.localName;
String replacementTag = original.localName!;
switch (replacementTag) {
case 'flt-scene':
replacementTag = 's';
@ -256,7 +255,7 @@ String canonicalizeHtml(String htmlContent,
replacementTag = 'o';
break;
case 'flt-clip':
final String clipType = original.attributes['clip-type'];
final String? clipType = original.attributes['clip-type'];
switch (clipType) {
case 'rect':
replacementTag = 'clip';
@ -314,7 +313,7 @@ String canonicalizeHtml(String htmlContent,
});
if (original.attributes.containsKey('style')) {
final String styleValue = original.attributes['style'];
final String styleValue = original.attributes['style']!;
int attrCount = 0;
final String processedAttributes = styleValue
@ -368,7 +367,7 @@ String canonicalizeHtml(String htmlContent,
attrCount++;
return attr.trim();
})
.where((String attr) => attr != null && attr.isNotEmpty)
.where((String? attr) => attr != null && attr.isNotEmpty)
.join('; ');
if (attrCount > 0) {
@ -412,7 +411,7 @@ void expectHtml(html.Element element, String expectedHtml,
{HtmlComparisonMode mode = HtmlComparisonMode.nonLayoutOnly}) {
expectedHtml =
canonicalizeHtml(expectedHtml, mode: mode, throwOnUnusedAttributes: true);
final String actualHtml = canonicalizeHtml(element.outerHtml, mode: mode);
final String actualHtml = canonicalizeHtml(element.outerHtml!, mode: mode);
expect(actualHtml, expectedHtml);
}
@ -462,7 +461,7 @@ class SceneTester {
final SurfaceScene scene;
void expectSceneHtml(String expectedHtml) {
expectHtml(scene.webOnlyRootElement, expectedHtml,
expectHtml(scene.webOnlyRootElement!, expectedHtml,
mode: HtmlComparisonMode.noAttributes);
}
}

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
// @dart = 2.12
import 'dart:typed_data';
import 'package:ui/src/engine.dart' hide window;
@ -31,8 +31,8 @@ class PlatformMessage {
/// It holds all intercepted platform messages in a [messages] list that can
/// be inspected in tests.
class PlatformMessagesSpy {
PlatformMessageCallback _callback;
PlatformMessageCallback _backup;
PlatformMessageCallback? _callback;
PlatformMessageCallback? _backup;
bool get _isActive => _callback != null;
@ -44,8 +44,8 @@ class PlatformMessagesSpy {
/// This is typically called inside a test's `setUp` callback.
void setUp() {
assert(!_isActive);
_callback = (String channel, ByteData data,
PlatformMessageResponseCallback callback) {
_callback = (String channel, ByteData? data,
PlatformMessageResponseCallback? callback) {
messages.add(PlatformMessage(
channel,
const JSONMethodCodec().decodeMethodCall(data),

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.6
// @dart = 2.12
import 'dart:async';
import 'dart:html' as html;
import 'dart:js_util' as js_util;
@ -22,7 +22,7 @@ void main() {
}
void testMain() {
EngineSingletonFlutterWindow window;
late EngineSingletonFlutterWindow window;
setUp(() {
ui.webOnlyInitializeEngine();
@ -31,7 +31,6 @@ void testMain() {
tearDown(() async {
await window.resetHistory();
window = null;
});
test('window.defaultRouteName should not change', () async {
@ -42,7 +41,7 @@ void testMain() {
expect(window.defaultRouteName, '/initial');
// Changing the URL in the address bar later shouldn't affect [window.defaultRouteName].
strategy.replaceState(null, null, '/newpath');
strategy.replaceState(null, '', '/newpath');
expect(window.defaultRouteName, '/initial');
});
@ -86,7 +85,7 @@ void testMain() {
);
await callback.future;
expect(window.browserHistory is SingleEntryBrowserHistory, true);
expect(window.browserHistory.urlStrategy.getPath(), '/bar');
expect(window.browserHistory.urlStrategy!.getPath(), '/bar');
// We can still receive nav2 update.
callback = Completer<void>();
@ -103,10 +102,10 @@ void testMain() {
);
await callback.future;
expect(window.browserHistory is MultiEntriesBrowserHistory, true);
expect(window.browserHistory.urlStrategy.getPath(), '/baz');
expect(window.browserHistory.urlStrategy!.getPath(), '/baz');
// Throws assertion error if it receives nav1 update after nav2 update.
AssertionError caughtAssertion;
late AssertionError caughtAssertion;
await window.handleNavigationMessage(
JSONMethodCodec().encodeMethodCall(MethodCall(
'routeUpdated',
@ -124,7 +123,7 @@ void testMain() {
);
// The history does not change.
expect(window.browserHistory is MultiEntriesBrowserHistory, true);
expect(window.browserHistory.urlStrategy.getPath(), '/baz');
expect(window.browserHistory.urlStrategy!.getPath(), '/baz');
});
test('initialize browser history with default url strategy (single)', () async {
@ -149,7 +148,7 @@ void testMain() {
// The url strategy should've been set to the default, and the path
// should've been correctly set to "/bar".
expect(window.browserHistory.urlStrategy, isNot(isNull));
expect(window.browserHistory.urlStrategy.getPath(), '/bar');
expect(window.browserHistory.urlStrategy!.getPath(), '/bar');
}, skip: browserEngine == BrowserEngine.webkit); // https://github.com/flutter/flutter/issues/50836
test('initialize browser history with default url strategy (multiple)', () async {
@ -177,7 +176,7 @@ void testMain() {
// The url strategy should've been set to the default, and the path
// should've been correctly set to "/baz".
expect(window.browserHistory.urlStrategy, isNot(isNull));
expect(window.browserHistory.urlStrategy.getPath(), '/baz');
expect(window.browserHistory.urlStrategy!.getPath(), '/baz');
}, skip: browserEngine == BrowserEngine.webkit); // https://github.com/flutter/flutter/issues/50836
test('can disable location strategy', () async {
@ -231,6 +230,13 @@ void testMain() {
// Second time is not allowed.
expect(() => jsSetUrlStrategy(null), throwsA(isAssertionError));
});
// Regression test for https://github.com/flutter/flutter/issues/77817
test('window.locale(s) are not nullable', () {
// If the getters were nullable, these expressions would result in compiler errors.
ui.window.locale.countryCode;
ui.window.locales.first.countryCode;
});
}
void jsSetUrlStrategy(dynamic strategy) {

View File

@ -4,9 +4,9 @@ environment:
sdk: ">=2.2.0 <3.0.0"
dependencies:
js: 0.6.3-nullsafety.3
stream_channel: 2.1.0-nullsafety.3
test: 1.16.0-nullsafety.9
webkit_inspection_protocol: 0.5.0
js: 0.6.3
stream_channel: 2.1.0
test: 1.16.6
webkit_inspection_protocol: 1.0.0
ui:
path: ../../lib/web_ui

View File

@ -4,7 +4,7 @@ environment:
sdk: ">=2.11.0-0 <3.0.0"
dependencies:
path: 1.8.0-nullsafety.3
image: 2.1.13
js: 0.6.3-nullsafety.3
yaml: 2.2.1
path: 1.8.0
image: 3.0.1
js: 0.6.3
yaml: 3.0.0