diff --git a/lib/web_ui/dev/chrome_installer.dart b/lib/web_ui/dev/chrome_installer.dart index 3766488f497dd..36254e8f6303b 100644 --- a/lib/web_ui/dev/chrome_installer.dart +++ b/lib/web_ui/dev/chrome_installer.dart @@ -270,7 +270,7 @@ Future 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}'); diff --git a/lib/web_ui/lib/src/ui/window.dart b/lib/web_ui/lib/src/ui/window.dart index ef3452947b5a1..06a8b75df8bf5 100644 --- a/lib/web_ui/lib/src/ui/window.dart +++ b/lib/web_ui/lib/src/ui/window.dart @@ -32,8 +32,8 @@ abstract class SingletonFlutterWindow extends FlutterWindow { platformDispatcher.onMetricsChanged = callback; } - Locale? get locale => platformDispatcher.locale; - List? get locales => platformDispatcher.locales; + Locale get locale => platformDispatcher.locale; + List get locales => platformDispatcher.locales; Locale? computePlatformResolvedLocale(List supportedLocales) { return platformDispatcher.computePlatformResolvedLocale(supportedLocales); diff --git a/lib/web_ui/pubspec.yaml b/lib/web_ui/pubspec.yaml index b85a59e194c67..4b140731890e0 100644 --- a/lib/web_ui/pubspec.yaml +++ b/lib/web_ui/pubspec.yaml @@ -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 diff --git a/lib/web_ui/test/engine/history_test.dart b/lib/web_ui/test/engine/history_test.dart index e1a0140b6347a..b32a5f2411677 100644 --- a/lib/web_ui/test/engine/history_test.dart +++ b/lib/web_ui/test/engine/history_test.dart @@ -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 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(); diff --git a/lib/web_ui/test/matchers.dart b/lib/web_ui/test/matchers.dart index 586d8a01de319..db6947dcf306e 100644 --- a/lib/web_ui/test/matchers.dart +++ b/lib/web_ui/test/matchers.dart @@ -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 enumerateSurfaces([PersistedSurface root]) { +Iterable enumerateSurfaces([PersistedSurface? root]) { root ??= SurfaceSceneBuilder.debugLastFrameScene; - final List surfaces = [root]; + final List surfaces = [root!]; root.visitChildren((PersistedSurface surface) { surfaces.addAll(enumerateSurfaces(surface)); @@ -37,7 +36,7 @@ Iterable enumerateSurfaces([PersistedSurface root]) { /// Enumerates all pictures nested under [root]. /// /// If [root] is `null` returns all pictures from the last rendered scene. -Iterable enumeratePictures([PersistedSurface root]) { +Iterable enumeratePictures([PersistedSurface? root]) { root ??= SurfaceSceneBuilder.debugLastFrameScene; return enumerateSurfaces(root).whereType(); } @@ -45,7 +44,7 @@ Iterable enumeratePictures([PersistedSurface root]) { /// Enumerates all offset surfaces nested under [root]. /// /// If [root] is `null` returns all pictures from the last rendered scene. -Iterable enumerateOffsets([PersistedSurface root]) { +Iterable enumerateOffsets([PersistedSurface? root]) { root ??= SurfaceSceneBuilder.debugLastFrameScene; return enumerateSurfaces(root).whereType(); } @@ -76,7 +75,7 @@ typedef DistanceFunction = 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] for some concrete T. -typedef AnyDistanceFunction = num Function(Null a, Null b); +typedef AnyDistanceFunction = num Function(Never a, Never b); const Map _kStandardDistanceFunctions = { @@ -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({ - @required num distance, - @required T from, - DistanceFunction distanceFunction, + required num distance, + required T from, + DistanceFunction? distanceFunction, }) { - distanceFunction ??= _kStandardDistanceFunctions[T]; + distanceFunction ??= _kStandardDistanceFunctions[T] as DistanceFunction?; if (distanceFunction == null) { throw ArgumentError( @@ -158,7 +157,7 @@ class _IsWithinDistance extends Matcher { final num epsilon; @override - bool matches(Object object, Map matchState) { + bool matches(Object? object, Map matchState) { if (object is! T) { return false; } @@ -183,7 +182,7 @@ class _IsWithinDistance extends Matcher { @override Description describeMismatch( - Object object, + Object? object, Description mismatchDescription, Map 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); } } diff --git a/lib/web_ui/test/spy.dart b/lib/web_ui/test/spy.dart index ed7596e7313ad..0b6a1fa57fd46 100644 --- a/lib/web_ui/test/spy.dart +++ b/lib/web_ui/test/spy.dart @@ -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), diff --git a/lib/web_ui/test/window_test.dart b/lib/web_ui/test/window_test.dart index 229bc65ca40a7..b538a7ec66135 100644 --- a/lib/web_ui/test/window_test.dart +++ b/lib/web_ui/test/window_test.dart @@ -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(); @@ -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) { diff --git a/web_sdk/web_engine_tester/pubspec.yaml b/web_sdk/web_engine_tester/pubspec.yaml index af9f4ed712b84..0577fe9bb55f0 100644 --- a/web_sdk/web_engine_tester/pubspec.yaml +++ b/web_sdk/web_engine_tester/pubspec.yaml @@ -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 diff --git a/web_sdk/web_test_utils/pubspec.yaml b/web_sdk/web_test_utils/pubspec.yaml index 15b2cacc1b604..c9d8896d54a0e 100644 --- a/web_sdk/web_test_utils/pubspec.yaml +++ b/web_sdk/web_test_utils/pubspec.yaml @@ -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