diff --git a/.ci.yaml b/.ci.yaml index 3310b3129a..c95d2f349d 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -245,6 +245,38 @@ targets: "PACKAGE_SHARDING": "--shardIndex 1 --shardCount 2" } + # Wasm unit tests in master + - name: Linux_web web_dart_unit_test_wasm_shard_1 master + bringup: true + recipe: packages/packages + timeout: 60 + properties: + add_recipes_cq: "true" + target_file: web_dart_unit_tests_wasm.yaml + channel: master + version_file: flutter_master.version + package_sharding: "--shardIndex 0 --shardCount 2" + env_variables: >- + { + "CHANNEL": "master", + "PACKAGE_SHARDING": "--shardIndex 0 --shardCount 2" + } + + - name: Linux_web web_dart_unit_test_wasm_shard_2 master + bringup: true + recipe: packages/packages + timeout: 60 + properties: + target_file: web_dart_unit_tests_wasm.yaml + channel: master + version_file: flutter_master.version + package_sharding: "--shardIndex 1 --shardCount 2" + env_variables: >- + { + "CHANNEL": "master", + "PACKAGE_SHARDING": "--shardIndex 1 --shardCount 2" + } + - name: Linux analyze master recipe: packages/packages timeout: 30 @@ -846,6 +878,7 @@ targets: "CHANNEL": "stable" } + # JS integration tests in master - name: Linux_web web_platform_tests_shard_1 master recipe: packages/packages timeout: 60 @@ -888,6 +921,53 @@ targets: "PACKAGE_SHARDING": "--shardIndex 2 --shardCount 3" } + # Wasm integration tests in master + - name: Linux_web web_platform_tests_wasm_shard_1 master + bringup: true + recipe: packages/packages + timeout: 60 + properties: + target_file: web_platform_tests_wasm.yaml + version_file: flutter_master.version + channel: master + package_sharding: "--shardIndex 0 --shardCount 3" + env_variables: >- + { + "CHANNEL": "master", + "PACKAGE_SHARDING": "--shardIndex 0 --shardCount 3" + } + + - name: Linux_web web_platform_tests_wasm_shard_2 master + bringup: true + recipe: packages/packages + timeout: 60 + properties: + target_file: web_platform_tests_wasm.yaml + version_file: flutter_master.version + channel: master + package_sharding: "--shardIndex 1 --shardCount 3" + env_variables: >- + { + "CHANNEL": "master", + "PACKAGE_SHARDING": "--shardIndex 1 --shardCount 3" + } + + - name: Linux_web web_platform_tests_wasm_shard_3 master + bringup: true + recipe: packages/packages + timeout: 60 + properties: + target_file: web_platform_tests_wasm.yaml + version_file: flutter_master.version + channel: master + package_sharding: "--shardIndex 2 --shardCount 3" + env_variables: >- + { + "CHANNEL": "master", + "PACKAGE_SHARDING": "--shardIndex 2 --shardCount 3" + } + + # JS integration tests in stable - name: Linux_web web_platform_tests_shard_1 stable recipe: packages/packages timeout: 60 diff --git a/.ci/targets/web_dart_unit_tests.yaml b/.ci/targets/web_dart_unit_tests.yaml index cd7336a9a3..16cdf1771b 100644 --- a/.ci/targets/web_dart_unit_tests.yaml +++ b/.ci/targets/web_dart_unit_tests.yaml @@ -4,4 +4,8 @@ tasks: infra_step: true # Note infra steps failing prevents "always" from running. - name: Dart unit tests - web script: .ci/scripts/tool_runner.sh - args: ["dart-test", "--exclude=script/configs/dart_unit_tests_exceptions.yaml", "--platform=chrome"] + args: [ + "dart-test", + "--platform=chrome", + "--exclude=script/configs/dart_unit_tests_exceptions.yaml" + ] diff --git a/.ci/targets/web_dart_unit_tests_wasm.yaml b/.ci/targets/web_dart_unit_tests_wasm.yaml new file mode 100644 index 0000000000..a5a6eeeddf --- /dev/null +++ b/.ci/targets/web_dart_unit_tests_wasm.yaml @@ -0,0 +1,13 @@ +tasks: + - name: prepare tool + script: .ci/scripts/prepare_tool.sh + infra_step: true # Note infra steps failing prevents "always" from running. + - name: Dart unit tests - web (wasm) + script: .ci/scripts/tool_runner.sh + args: [ + "dart-test", + "--platform=chrome", + "--wasm", + "--exclude=script/configs/dart_unit_tests_exceptions.yaml", + "--exclude=script/configs/dart_unit_tests_wasm_exceptions.yaml" + ] diff --git a/.ci/targets/web_platform_tests.yaml b/.ci/targets/web_platform_tests.yaml index 699cc9a5e9..94083d302a 100644 --- a/.ci/targets/web_platform_tests.yaml +++ b/.ci/targets/web_platform_tests.yaml @@ -6,9 +6,11 @@ tasks: script: .ci/scripts/tool_runner.sh args: ["fetch-deps", "--web", "--supporting-target-platforms-only"] infra_step: true - - name: build examples - script: .ci/scripts/tool_runner.sh - args: ["build-examples", "--web"] - name: drive examples script: .ci/scripts/tool_runner.sh - args: ["drive-examples", "--web", "--run-chromedriver", "--exclude=script/configs/exclude_integration_web.yaml"] + args: [ + "drive-examples", + "--web", + "--run-chromedriver", + "--exclude=script/configs/exclude_integration_web.yaml", + ] diff --git a/.ci/targets/web_platform_tests_wasm.yaml b/.ci/targets/web_platform_tests_wasm.yaml new file mode 100644 index 0000000000..c6de74a5ad --- /dev/null +++ b/.ci/targets/web_platform_tests_wasm.yaml @@ -0,0 +1,18 @@ +tasks: + - name: prepare tool + script: .ci/scripts/prepare_tool.sh + infra_step: true # Note infra steps failing prevents "always" from running. + - name: download Dart deps + script: .ci/scripts/tool_runner.sh + args: ["fetch-deps", "--web", "--supporting-target-platforms-only"] + infra_step: true + - name: drive examples + script: .ci/scripts/tool_runner.sh + args: [ + "drive-examples", + "--web", + "--wasm", + "--run-chromedriver", + "--exclude=script/configs/exclude_integration_web.yaml", + "--exclude=script/configs/exclude_integration_web_wasm.yaml" + ] diff --git a/packages/animations/.gitignore b/packages/animations/.gitignore index f3c205341e..955a348605 100644 --- a/packages/animations/.gitignore +++ b/packages/animations/.gitignore @@ -31,9 +31,6 @@ .pub/ /build/ -# Web related -lib/generated_plugin_registrant.dart - # Symbolication related app.*.symbols diff --git a/packages/animations/example/.gitignore b/packages/animations/example/.gitignore index ae1f1838ee..a981f586a1 100644 --- a/packages/animations/example/.gitignore +++ b/packages/animations/example/.gitignore @@ -30,8 +30,5 @@ .pub/ /build/ -# Web related -lib/generated_plugin_registrant.dart - # Exceptions to above rules. !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/packages/google_adsense/example/integration_test/experimental_ad_unit_widget_test.dart b/packages/google_adsense/example/integration_test/experimental_ad_unit_widget_test.dart index 0127622dd7..4f7cb10562 100644 --- a/packages/google_adsense/example/integration_test/experimental_ad_unit_widget_test.dart +++ b/packages/google_adsense/example/integration_test/experimental_ad_unit_widget_test.dart @@ -205,7 +205,8 @@ Future pumpAdWidget(Widget adUnit, WidgetTester tester) async { // This extra pump is needed for the platform view to actually render in the DOM. await tester.pump(); - + // One more for skwasm. + await tester.pump(); // This extra pump is needed to simulate the async behavior of the adsense JS mock. await tester.pumpAndSettle(); } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart index 0912fcbaec..725e8e38ed 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart @@ -232,11 +232,11 @@ void main() { visualization.HeatmapLayerOptions() ..data = [gmaps.LatLng(0, 0)].toJS; - expect(heatmap.data, hasLength(0)); + expect(heatmap.data.array.toDart, hasLength(0)); controller.update(options); - expect(heatmap.data, hasLength(1)); + expect(heatmap.data.array.toDart, hasLength(1)); }); group('remove', () { diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart index ec8198679d..6b712eeb7a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart @@ -435,7 +435,7 @@ void main() { controller.addHeatmaps(heatmaps); expect( - controller.heatmaps[const HeatmapId('1')]?.heatmap?.data, + controller.heatmaps[const HeatmapId('1')]!.heatmap!.data.array.toDart, hasLength(0), ); @@ -450,7 +450,7 @@ void main() { expect(controller.heatmaps.length, 1); expect( - controller.heatmaps[const HeatmapId('1')]?.heatmap?.data, + controller.heatmaps[const HeatmapId('1')]!.heatmap!.data.array.toDart, hasLength(1), ); }); @@ -510,7 +510,9 @@ void main() { controller.heatmaps.values.first.heatmap!; expect( - heatmap.get('gradient'), + (heatmap.get('gradient')! as JSArray) + .toDart + .map((JSString? value) => value!.toDart), ['rgba(250, 186, 218, 0.00)', 'rgba(250, 186, 218, 1.00)'], ); }); diff --git a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md index efbec138c5..ff31e24efb 100644 --- a/packages/image_picker/image_picker_platform_interface/CHANGELOG.md +++ b/packages/image_picker/image_picker_platform_interface/CHANGELOG.md @@ -1,6 +1,7 @@ -## NEXT +## 2.10.1 * Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. +* Fixes Wasm tests in internal PickedFile implementation. ## 2.10.0 diff --git a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart index c8c9e5a0ac..ce28227c30 100644 --- a/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart +++ b/packages/image_picker/image_picker_platform_interface/lib/src/types/picked_file/picked_file.dart @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(dit): Remove this, https://github.com/flutter/flutter/issues/144286 + export 'lost_data.dart'; export 'unsupported.dart' - if (dart.library.html) 'html.dart' + if (dart.library.js_interop) 'html.dart' if (dart.library.io) 'io.dart'; diff --git a/packages/image_picker/image_picker_platform_interface/pubspec.yaml b/packages/image_picker/image_picker_platform_interface/pubspec.yaml index 3f56e0e394..c48aedbd73 100644 --- a/packages/image_picker/image_picker_platform_interface/pubspec.yaml +++ b/packages/image_picker/image_picker_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/image_picker/ issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.10.0 +version: 2.10.1 environment: sdk: ^3.4.0 @@ -20,6 +20,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + web: ^1.1.0 topics: - image-picker diff --git a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart index b5036946eb..cc2191444a 100644 --- a/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart +++ b/packages/image_picker/image_picker_platform_interface/test/picked_file_html_test.dart @@ -6,15 +6,18 @@ library; import 'dart:convert'; -import 'dart:html' as html; +import 'dart:js_interop'; +import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:image_picker_platform_interface/image_picker_platform_interface.dart'; +import 'package:web/web.dart' as web; const String expectedStringContents = 'Hello, world!'; -final List bytes = utf8.encode(expectedStringContents); -final html.File textFile = html.File(>[bytes], 'hello.txt'); -final String textFileUrl = html.Url.createObjectUrl(textFile); +final Uint8List bytes = utf8.encode(expectedStringContents); +final web.File textFile = + web.File([bytes.toJS].toJS, 'hello.txt'); +final String textFileUrl = web.URL.createObjectURL(textFile); void main() { group('Create with an objectUrl', () { diff --git a/packages/pointer_interceptor/pointer_interceptor_web/example/integration_test/widget_test.dart b/packages/pointer_interceptor/pointer_interceptor_web/example/integration_test/widget_test.dart index f1b323ae31..c47d238076 100644 --- a/packages/pointer_interceptor/pointer_interceptor_web/example/integration_test/widget_test.dart +++ b/packages/pointer_interceptor/pointer_interceptor_web/example/integration_test/widget_test.dart @@ -70,7 +70,8 @@ Future _fullyRenderApp(WidgetTester tester) async { await tester.pumpWidget(const app.MyApp()); // Pump 2 frames so the framework injects the platform view into the DOM. await tester.pump(); - await tester.pump(); + // Give the browser some time to perform DOM operations (for Wasm code) + await tester.pump(const Duration(milliseconds: 500)); } // Calls [_getHtmlElementAt] passing it the center of the widget identified by diff --git a/packages/rfw/test/material_widgets_test.dart b/packages/rfw/test/material_widgets_test.dart index 648d7249d0..12fb4aea90 100644 --- a/packages/rfw/test/material_widgets_test.dart +++ b/packages/rfw/test/material_widgets_test.dart @@ -13,6 +13,12 @@ import 'tolerant_comparator.dart' if (dart.library.js_interop) 'tolerant_comparator_web.dart'; import 'utils.dart'; +/// A const to tell apart Wasm from JS web. +/// +/// This is used below to do comparisons of numbers, where in JS a whole double +/// is serialized as "2", in Wasm (and non-web platforms) it's "2.0". +const bool kIsJS = kIsWeb && !kIsWasm; + void main() { const LibraryName coreName = LibraryName(['core']); const LibraryName materialName = LibraryName(['material']); @@ -229,7 +235,7 @@ void main() { await tester.pumpAndSettle(); expect(eventLog, contains('menu_item {args: second}')); expect(eventLog, - contains(kIsWeb ? 'dropdown {value: 2}' : 'dropdown {value: 2.0}')); + contains(kIsJS ? 'dropdown {value: 2}' : 'dropdown {value: 2.0}')); await tester.tapAt(const Offset(20.0, 20.0)); await tester.pump(); @@ -682,15 +688,15 @@ void main() { await _slideToValue(tester, sliderFinder, 20.0); await tester.pumpAndSettle(); expect(eventLog, - contains(kIsWeb ? 'slider {value: 20}' : 'slider {value: 20.0}')); + contains(kIsJS ? 'slider {value: 20}' : 'slider {value: 20.0}')); expect( eventLog, contains( - kIsWeb ? 'slider.start {value: 0}' : 'slider.start {value: 0.0}')); + kIsJS ? 'slider.start {value: 0}' : 'slider.start {value: 0.0}')); expect( eventLog, contains( - kIsWeb ? 'slider.end {value: 20}' : 'slider.end {value: 20.0}')); + kIsJS ? 'slider.end {value: 20}' : 'slider.end {value: 20.0}')); }); } diff --git a/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart b/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart index 9c700c87d0..b3b1890f23 100644 --- a/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart +++ b/packages/url_launcher/url_launcher_web/example/integration_test/link_widget_test.dart @@ -34,6 +34,7 @@ void main() { )); // Platform view creation happens asynchronously. await tester.pumpAndSettle(); + await tester.pump(); final html.Element anchor = _findSingleAnchor(); expect(anchor.getAttribute('href'), uri.toString()); @@ -51,6 +52,7 @@ void main() { )), )); await tester.pumpAndSettle(); + await tester.pump(); // Check that the same anchor has been updated. expect(anchor.getAttribute('href'), uri2.toString()); @@ -68,6 +70,7 @@ void main() { )), )); await tester.pumpAndSettle(); + await tester.pump(); // Check that internal route properly prepares using the default // [UrlStrategy] @@ -102,6 +105,7 @@ void main() { ), )); await tester.pumpAndSettle(); + await tester.pump(); final Size containerSize = tester.getSize(find.byKey(containerKey)); // The Stack widget inserted by the `WebLinkDelegate` shouldn't loosen the @@ -130,6 +134,7 @@ void main() { )); // Platform view creation happens asynchronously. await tester.pumpAndSettle(); + await tester.pump(); final html.Element anchor = _findSingleAnchor(); expect(anchor.hasAttribute('href'), false); @@ -161,6 +166,7 @@ void main() { ); await tester.pumpAndSettle(); + await tester.pump(); await tester.scrollUntilVisible( find.text('#${itemCount - 1}'), @@ -213,6 +219,7 @@ void main() { )); // Platform view creation happens asynchronously. await tester.pumpAndSettle(); + await tester.pump(); expect(observer.currentRouteName, '/'); expect(testPlugin.launches, isEmpty); @@ -227,10 +234,6 @@ void main() { // should be no calls to `launchUrl`. expect(observer.currentRouteName, '/foobar'); expect(testPlugin.launches, isEmpty); - - // Needed when testing on on Chrome98 headless in CI. - // See https://github.com/flutter/flutter/issues/121161 - await tester.pumpAndSettle(); }); testWidgets('keydown to navigate to internal link', @@ -258,6 +261,7 @@ void main() { )); // Platform view creation happens asynchronously. await tester.pumpAndSettle(); + await tester.pump(); expect(observer.currentRouteName, '/'); expect(testPlugin.launches, isEmpty); @@ -272,10 +276,6 @@ void main() { // should be no calls to `launchUrl`. expect(observer.currentRouteName, '/foobar'); expect(testPlugin.launches, isEmpty); - - // Needed when testing on on Chrome98 headless in CI. - // See https://github.com/flutter/flutter/issues/121161 - await tester.pumpAndSettle(); }); testWidgets('click to navigate to external link', @@ -300,6 +300,7 @@ void main() { )); // Platform view creation happens asynchronously. await tester.pumpAndSettle(); + await tester.pump(); expect(observer.currentRouteName, '/'); expect(testPlugin.launches, isEmpty); @@ -315,10 +316,6 @@ void main() { // no calls to `launchUrl`. expect(observer.currentRouteName, '/'); expect(testPlugin.launches, isEmpty); - - // Needed when testing on on Chrome98 headless in CI. - // See https://github.com/flutter/flutter/issues/121161 - await tester.pumpAndSettle(); }); testWidgets('keydown to navigate to external link', @@ -343,6 +340,7 @@ void main() { )); // Platform view creation happens asynchronously. await tester.pumpAndSettle(); + await tester.pump(); expect(observer.currentRouteName, '/'); expect(testPlugin.launches, isEmpty); @@ -357,17 +355,13 @@ void main() { // `launchUrl`, and there's no change to the app's route name. expect(observer.currentRouteName, '/'); expect(testPlugin.launches, ['https://google.com']); - - // Needed when testing on on Chrome98 headless in CI. - // See https://github.com/flutter/flutter/issues/121161 - await tester.pumpAndSettle(); }); }); } html.Element _findSingleAnchor() { final List foundAnchors = []; - html.NodeList anchors = html.document.querySelectorAll('a'); + final html.NodeList anchors = html.document.querySelectorAll('a'); for (int i = 0; i < anchors.length; i++) { final html.Element anchor = anchors.item(i)! as html.Element; if (anchor.hasProperty(linkViewIdProperty.toJS).toDart) { @@ -375,27 +369,24 @@ html.Element _findSingleAnchor() { } } - // Search inside the shadow DOM as well. - final html.ShadowRoot? shadowRoot = - html.document.querySelector('flt-glass-pane')?.shadowRoot; - if (shadowRoot != null) { - anchors = shadowRoot.querySelectorAll('a'); - for (int i = 0; i < anchors.length; i++) { - final html.Element anchor = anchors.item(i)! as html.Element; - if (anchor.hasProperty(linkViewIdProperty.toJS).toDart) { - foundAnchors.add(anchor); - } - } - } - return foundAnchors.single; } void _simulateClick(html.Element target) { + // Stop the browser from navigating away from the test suite. + target.addEventListener( + 'click', + (html.Event e) { + e.preventDefault(); + }.toJS); + // Synthesize a click event. target.dispatchEvent( html.MouseEvent( 'click', - html.MouseEventInit()..bubbles = true, + html.MouseEventInit( + bubbles: true, + cancelable: true, + ), ), ); } @@ -404,7 +395,11 @@ void _simulateKeydown(html.Element target) { target.dispatchEvent( html.KeyboardEvent( 'keydown', - html.KeyboardEventInit()..bubbles = true, + html.KeyboardEventInit( + bubbles: true, + cancelable: true, + code: 'Space', + ), ), ); } diff --git a/packages/vector_graphics_codec/CHANGELOG.md b/packages/vector_graphics_codec/CHANGELOG.md index a4781180d5..4714938b5b 100644 --- a/packages/vector_graphics_codec/CHANGELOG.md +++ b/packages/vector_graphics_codec/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.13 + +* Works around a subtle Wasm bug in `writeRadialGradient`. + ## 1.1.12 * Transfers the package source from https://github.com/dnfield/vector_graphics diff --git a/packages/vector_graphics_codec/lib/vector_graphics_codec.dart b/packages/vector_graphics_codec/lib/vector_graphics_codec.dart index 5888860a41..d8e613340b 100644 --- a/packages/vector_graphics_codec/lib/vector_graphics_codec.dart +++ b/packages/vector_graphics_codec/lib/vector_graphics_codec.dart @@ -394,10 +394,10 @@ class VectorGraphicsCodec { buffer._putFloat32(centerY); buffer._putFloat32(radius); - if (focalX != null) { + if (focalX != null && focalY != null) { buffer._putUint8(1); buffer._putFloat32(focalX); - buffer._putFloat32(focalY!); + buffer._putFloat32(focalY); } else { buffer._putUint8(0); } @@ -710,7 +710,7 @@ class VectorGraphicsCodec { return id; } - /// Write a new path to the [buffer], returing the identifier + /// Write a new path to the [buffer], returning the identifier /// assigned to it. /// /// The [fillType] argument is either `1` for a fill or `0` for a stroke. diff --git a/packages/vector_graphics_codec/pubspec.yaml b/packages/vector_graphics_codec/pubspec.yaml index 78af4cdae4..04bf772d39 100644 --- a/packages/vector_graphics_codec/pubspec.yaml +++ b/packages/vector_graphics_codec/pubspec.yaml @@ -2,7 +2,7 @@ name: vector_graphics_codec description: An encoding library for the binary format used in `package:vector_graphics` repository: https://github.com/flutter/packages/tree/main/packages/vector_graphics_codec issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+vector_graphics%22 -version: 1.1.12 +version: 1.1.13 environment: sdk: ^3.4.0 diff --git a/packages/video_player/video_player/example/integration_test/video_player_test.dart b/packages/video_player/video_player/example/integration_test/video_player_test.dart index a431ece7bc..3265ca6dff 100644 --- a/packages/video_player/video_player/example/integration_test/video_player_test.dart +++ b/packages/video_player/video_player/example/integration_test/video_player_test.dart @@ -199,6 +199,10 @@ void main() { expect(controller.value.position, lessThanOrEqualTo(controller.value.duration)); }, + // Flaky on the web, headless browsers don't like to seek to non-buffered + // positions of a video (and since this isn't even injecting the video + // element on the page, the video never starts buffering with the test) + skip: kIsWeb, ); testWidgets('test video player view with local asset', diff --git a/script/configs/dart_unit_tests_wasm_exceptions.yaml b/script/configs/dart_unit_tests_wasm_exceptions.yaml new file mode 100644 index 0000000000..9978ed364e --- /dev/null +++ b/script/configs/dart_unit_tests_wasm_exceptions.yaml @@ -0,0 +1,10 @@ +# Packages that are excluded from dart unit tests (compiled to Wasm) +# +# This list should be kept as short as possible, and things should remain here +# only as long as necessary, since in general all web packages should work with +# Wasm. +# +# This is only used for the rare case where a package fails in Wasm, but works +# in JS mode. + +[] # Needed so the contents of this file are an empty array, not `null`! diff --git a/script/configs/exclude_all_packages_app_wasm.yaml b/script/configs/exclude_all_packages_app_wasm.yaml index 8a02d4e479..7c503b36fb 100644 --- a/script/configs/exclude_all_packages_app_wasm.yaml +++ b/script/configs/exclude_all_packages_app_wasm.yaml @@ -1,8 +1,8 @@ # This list should be kept as short as possible, and things should remain here # only as long as necessary, since in general the goal is for all of the latest # versions of packages to be mutually compatible, and compilable with Wasm. - -# This is only used for wasm compilation. Once all packages in the repo have -# been migrated, remove this file and use `exclude_all_packages_app.yaml` only. +# +# This is only used for the rare case where a package fails in Wasm, but works +# in JS mode. [] # Needed so the contents of this file are an empty array, not `null`! diff --git a/script/configs/exclude_integration_web_wasm.yaml b/script/configs/exclude_integration_web_wasm.yaml new file mode 100644 index 0000000000..8172d52169 --- /dev/null +++ b/script/configs/exclude_integration_web_wasm.yaml @@ -0,0 +1,8 @@ +# This list should be kept as short as possible, and things should remain here +# only as long as necessary, since in general all web packages should work with +# Wasm. +# +# This is only used for the rare case where a package fails in Wasm, but works +# in JS mode. + +[] # Needed so the contents of this file are an empty array, not `null`! diff --git a/script/tool/lib/src/dart_test_command.dart b/script/tool/lib/src/dart_test_command.dart index 716cd7fbe4..fcad751f47 100644 --- a/script/tool/lib/src/dart_test_command.dart +++ b/script/tool/lib/src/dart_test_command.dart @@ -41,6 +41,8 @@ class DartTestCommand extends PackageLoopingCommand { help: 'Runs tests on the given platform instead of the default platform ' '("vm" in most cases, "chrome" for web plugin implementations).', ); + argParser.addFlag(kWebWasmFlag, + help: 'Compile to WebAssembly rather than JavaScript'); } static const String _platformFlag = 'platform'; @@ -108,18 +110,21 @@ class DartTestCommand extends PackageLoopingCommand { platform = 'chrome'; } + // Whether to run web tests compiled to wasm. + final bool wasm = platform != 'vm' && getBoolArg(kWebWasmFlag); + bool passed; if (package.requiresFlutter()) { - passed = await _runFlutterTests(package, platform: platform); + passed = await _runFlutterTests(package, platform: platform, wasm: wasm); } else { - passed = await _runDartTests(package, platform: platform); + passed = await _runDartTests(package, platform: platform, wasm: wasm); } return passed ? PackageResult.success() : PackageResult.fail(); } /// Runs the Dart tests for a Flutter package, returning true on success. Future _runFlutterTests(RepositoryPackage package, - {String? platform}) async { + {String? platform, bool wasm = false}) async { final String experiment = getStringArg(kEnableExperiment); final int exitCode = await processRunner.runAndStream( @@ -131,6 +136,7 @@ class DartTestCommand extends PackageLoopingCommand { // Flutter defaults to VM mode (under a different name) and explicitly // setting it is deprecated, so pass nothing in that case. if (platform != null && platform != 'vm') '--platform=$platform', + if (wasm) '--wasm', ], workingDir: package.directory, ); @@ -139,7 +145,7 @@ class DartTestCommand extends PackageLoopingCommand { /// Runs the Dart tests for a non-Flutter package, returning true on success. Future _runDartTests(RepositoryPackage package, - {String? platform}) async { + {String? platform, bool wasm = false}) async { // Unlike `flutter test`, `dart run test` does not automatically get // packages if (!await runPubGet(package, processRunner, super.platform)) { @@ -156,6 +162,7 @@ class DartTestCommand extends PackageLoopingCommand { if (experiment.isNotEmpty) '--enable-experiment=$experiment', 'test', if (platform != null) '--platform=$platform', + if (wasm) '--compiler=dart2wasm', ], workingDir: package.directory, ); diff --git a/script/tool/test/dart_test_command_test.dart b/script/tool/test/dart_test_command_test.dart index 0289ebdfb7..b5786797db 100644 --- a/script/tool/test/dart_test_command_test.dart +++ b/script/tool/test/dart_test_command_test.dart @@ -337,6 +337,33 @@ test_on: vm && browser ); }); + test('runs in Chrome (wasm) when requested for Flutter package', () async { + final RepositoryPackage package = createFakePackage( + 'a_package', + packagesDir, + isFlutter: true, + extraFiles: ['test/empty_test.dart'], + ); + + await runCapturingPrint( + runner, ['dart-test', '--platform=chrome', '--wasm']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall( + getFlutterCommand(mockPlatform), + const [ + 'test', + '--color', + '--platform=chrome', + '--wasm', + ], + package.path), + ]), + ); + }); + test('runs in Chrome by default for Flutter plugins that implement web', () async { final RepositoryPackage plugin = createFakePlugin( @@ -517,6 +544,33 @@ test_on: vm && browser ); }); + test('runs in Chrome (wasm) when requested for Dart package', () async { + final RepositoryPackage package = createFakePackage( + 'package', + packagesDir, + extraFiles: ['test/empty_test.dart'], + ); + + await runCapturingPrint( + runner, ['dart-test', '--platform=chrome', '--wasm']); + + expect( + processRunner.recordedCalls, + orderedEquals([ + ProcessCall('dart', const ['pub', 'get'], package.path), + ProcessCall( + 'dart', + const [ + 'run', + 'test', + '--platform=chrome', + '--compiler=dart2wasm', + ], + package.path), + ]), + ); + }); + test('skips running in browser mode if package opts out', () async { final RepositoryPackage package = createFakePackage( 'a_package',