mirror of
https://github.com/flutter/flutter
synced 2024-10-01 05:54:08 +00:00
[web] enable CanvasKit tests using a local bundle fetched from CIPD (#92134)
This commit is contained in:
parent
e7c809e8a8
commit
ad7727a21c
168
.ci.yaml
168
.ci.yaml
|
@ -1184,6 +1184,174 @@ targets:
|
|||
- bin/
|
||||
- .ci.yaml
|
||||
|
||||
- name: Linux web_canvaskit_tests_0
|
||||
bringup: true
|
||||
recipe: flutter/flutter_drone
|
||||
timeout: 60
|
||||
properties:
|
||||
dependencies: >-
|
||||
[
|
||||
{"dependency": "android_sdk"},
|
||||
{"dependency": "chrome_and_driver"},
|
||||
{"dependency": "goldctl"}
|
||||
]
|
||||
shard: web_canvaskit_tests
|
||||
subshard: "0"
|
||||
tags: >
|
||||
["framework","hostonly","shard"]
|
||||
scheduler: luci
|
||||
runIf:
|
||||
- dev/
|
||||
- packages/
|
||||
- bin/
|
||||
|
||||
- name: Linux web_canvaskit_tests_1
|
||||
bringup: true
|
||||
recipe: flutter/flutter_drone
|
||||
timeout: 60
|
||||
properties:
|
||||
dependencies: >-
|
||||
[
|
||||
{"dependency": "android_sdk"},
|
||||
{"dependency": "chrome_and_driver"},
|
||||
{"dependency": "goldctl"}
|
||||
]
|
||||
shard: web_canvaskit_tests
|
||||
subshard: "1"
|
||||
tags: >
|
||||
["framework","hostonly","shard"]
|
||||
scheduler: luci
|
||||
runIf:
|
||||
- dev/
|
||||
- packages/
|
||||
- bin/
|
||||
|
||||
- name: Linux web_canvaskit_tests_2
|
||||
bringup: true
|
||||
recipe: flutter/flutter_drone
|
||||
timeout: 60
|
||||
properties:
|
||||
dependencies: >-
|
||||
[
|
||||
{"dependency": "android_sdk"},
|
||||
{"dependency": "chrome_and_driver"},
|
||||
{"dependency": "goldctl"}
|
||||
]
|
||||
shard: web_canvaskit_tests
|
||||
subshard: "2"
|
||||
tags: >
|
||||
["framework","hostonly","shard"]
|
||||
scheduler: luci
|
||||
runIf:
|
||||
- dev/
|
||||
- packages/
|
||||
- bin/
|
||||
|
||||
- name: Linux web_canvaskit_tests_3
|
||||
bringup: true
|
||||
recipe: flutter/flutter_drone
|
||||
timeout: 60
|
||||
properties:
|
||||
dependencies: >-
|
||||
[
|
||||
{"dependency": "android_sdk"},
|
||||
{"dependency": "chrome_and_driver"},
|
||||
{"dependency": "goldctl"}
|
||||
]
|
||||
shard: web_canvaskit_tests
|
||||
subshard: "3"
|
||||
tags: >
|
||||
["framework","hostonly","shard"]
|
||||
scheduler: luci
|
||||
runIf:
|
||||
- dev/
|
||||
- packages/
|
||||
- bin/
|
||||
|
||||
- name: Linux web_canvaskit_tests_4
|
||||
bringup: true
|
||||
recipe: flutter/flutter_drone
|
||||
timeout: 60
|
||||
properties:
|
||||
dependencies: >-
|
||||
[
|
||||
{"dependency": "android_sdk"},
|
||||
{"dependency": "chrome_and_driver"},
|
||||
{"dependency": "goldctl"}
|
||||
]
|
||||
shard: web_canvaskit_tests
|
||||
subshard: "4"
|
||||
tags: >
|
||||
["framework","hostonly","shard"]
|
||||
scheduler: luci
|
||||
runIf:
|
||||
- dev/
|
||||
- packages/
|
||||
- bin/
|
||||
|
||||
- name: Linux web_canvaskit_tests_5
|
||||
bringup: true
|
||||
recipe: flutter/flutter_drone
|
||||
timeout: 60
|
||||
properties:
|
||||
dependencies: >-
|
||||
[
|
||||
{"dependency": "android_sdk"},
|
||||
{"dependency": "chrome_and_driver"},
|
||||
{"dependency": "goldctl"}
|
||||
]
|
||||
shard: web_canvaskit_tests
|
||||
subshard: "5"
|
||||
tags: >
|
||||
["framework","hostonly","shard"]
|
||||
scheduler: luci
|
||||
runIf:
|
||||
- dev/
|
||||
- packages/
|
||||
- bin/
|
||||
|
||||
- name: Linux web_canvaskit_tests_6
|
||||
bringup: true
|
||||
recipe: flutter/flutter_drone
|
||||
timeout: 60
|
||||
properties:
|
||||
dependencies: >-
|
||||
[
|
||||
{"dependency": "android_sdk"},
|
||||
{"dependency": "chrome_and_driver"},
|
||||
{"dependency": "goldctl"}
|
||||
]
|
||||
shard: web_canvaskit_tests
|
||||
subshard: "6"
|
||||
tags: >
|
||||
["framework","hostonly","shard"]
|
||||
scheduler: luci
|
||||
runIf:
|
||||
- dev/
|
||||
- packages/
|
||||
- bin/
|
||||
|
||||
- name: Linux web_canvaskit_tests_7_last
|
||||
bringup: true
|
||||
recipe: flutter/flutter_drone
|
||||
timeout: 60
|
||||
properties:
|
||||
dependencies: >-
|
||||
[
|
||||
{"dependency": "android_sdk"},
|
||||
{"dependency": "chrome_and_driver"},
|
||||
{"dependency": "goldctl"}
|
||||
]
|
||||
shard: web_canvaskit_tests
|
||||
subshard: "7_last"
|
||||
tags: >
|
||||
["framework","hostonly","shard"]
|
||||
scheduler: luci
|
||||
runIf:
|
||||
- dev/
|
||||
- packages/
|
||||
- bin/
|
||||
|
||||
- name: Linux web_tool_tests
|
||||
recipe: flutter/flutter_drone
|
||||
timeout: 60
|
||||
|
|
|
@ -225,6 +225,7 @@
|
|||
# web_integration_tests @yjbanov @flutter/web
|
||||
# web_long_running_tests @yjbanov @flutter/web
|
||||
# web_tests @yjbanov @flutter/web
|
||||
# web_canvaskit_tests @yjbanov @flutter/web
|
||||
# web_tool_tests @zanderso @flutter/tool
|
||||
# fuchsia_precache @zanderso @flutter/tool
|
||||
# skp_generator @Hixie
|
||||
|
|
|
@ -74,13 +74,66 @@ const String kSubshardKey = 'SUBSHARD';
|
|||
int get webShardCount => Platform.environment.containsKey('WEB_SHARD_COUNT')
|
||||
? int.parse(Platform.environment['WEB_SHARD_COUNT']!)
|
||||
: 8;
|
||||
/// Tests that we don't run on Web for compilation reasons.
|
||||
|
||||
/// Tests that we don't run on Web.
|
||||
///
|
||||
/// In general avoid adding new tests here. If a test cannot run on the web
|
||||
/// because it fails at runtime, such as when a piece of functionality is not
|
||||
/// implemented or not implementable on the web, prefer using `skip` in the
|
||||
/// test code. Only add tests here that cannot be skipped using `skip`. For
|
||||
/// example:
|
||||
///
|
||||
/// * Test code cannot be compiled because it uses Dart VM-specific
|
||||
/// functionality. In this case `skip` doesn't help because the code cannot
|
||||
/// reach the point where it can even run the skipping logic.
|
||||
/// * Migrations. It is OK to put tests here that need to be temporarily
|
||||
/// disabled in certain modes because of some migration or initial bringup.
|
||||
///
|
||||
/// The key in the map is the renderer type that the list applies to. The value
|
||||
/// is the list of tests known to fail for that renderer.
|
||||
//
|
||||
// TODO(yjbanov): we're getting rid of this as part of https://github.com/flutter/flutter/projects/60
|
||||
const List<String> kWebTestFileKnownFailures = <String>[
|
||||
'test/services/message_codecs_vm_test.dart',
|
||||
'test/examples/sector_layout_test.dart',
|
||||
];
|
||||
const Map<String, List<String>> kWebTestFileKnownFailures = <String, List<String>>{
|
||||
'html': <String>[
|
||||
// These tests are not compilable on the web due to dependencies on
|
||||
// VM-specific functionality.
|
||||
'test/services/message_codecs_vm_test.dart',
|
||||
'test/examples/sector_layout_test.dart',
|
||||
],
|
||||
'canvaskit': <String>[
|
||||
// These tests are not compilable on the web due to dependencies on
|
||||
// VM-specific functionality.
|
||||
'test/services/message_codecs_vm_test.dart',
|
||||
'test/examples/sector_layout_test.dart',
|
||||
|
||||
// These tests are broken and need to be fixed.
|
||||
// TODO(yjbanov): https://github.com/flutter/flutter/issues/71604
|
||||
'test/painting/decoration_test.dart',
|
||||
'test/material/text_selection_theme_test.dart',
|
||||
'test/material/date_picker_test.dart',
|
||||
'test/rendering/layers_test.dart',
|
||||
'test/painting/text_style_test.dart',
|
||||
'test/widgets/image_test.dart',
|
||||
'test/cupertino/colors_test.dart',
|
||||
'test/cupertino/slider_test.dart',
|
||||
'test/material/text_field_test.dart',
|
||||
'test/rendering/proxy_box_test.dart',
|
||||
'test/widgets/app_overrides_test.dart',
|
||||
'test/material/calendar_date_picker_test.dart',
|
||||
'test/material/ink_paint_test.dart',
|
||||
'test/rendering/editable_test.dart',
|
||||
'test/cupertino/dialog_test.dart',
|
||||
'test/widgets/shape_decoration_test.dart',
|
||||
'test/material/time_picker_theme_test.dart',
|
||||
'test/cupertino/picker_test.dart',
|
||||
'test/material/chip_theme_test.dart',
|
||||
'test/cupertino/nav_bar_test.dart',
|
||||
'test/widgets/performance_overlay_test.dart',
|
||||
'test/widgets/html_element_view_test.dart',
|
||||
'test/cupertino/scaffold_test.dart',
|
||||
'test/rendering/platform_view_test.dart',
|
||||
],
|
||||
};
|
||||
|
||||
const String kSmokeTestShardName = 'smoke_tests';
|
||||
const List<String> _kAllBuildModes = <String>['debug', 'profile', 'release'];
|
||||
|
@ -143,8 +196,10 @@ Future<void> main(List<String> args) async {
|
|||
// web_tool_tests is also used by HHH: https://dart.googlesource.com/recipes/+/refs/heads/master/recipes/dart/flutter_engine.py
|
||||
'web_tool_tests': _runWebToolTests,
|
||||
'tool_integration_tests': _runIntegrationToolTests,
|
||||
// All the unit/widget tests run using `flutter test --platform=chrome`
|
||||
'web_tests': _runWebUnitTests,
|
||||
// All the unit/widget tests run using `flutter test --platform=chrome --web-renderer=html`
|
||||
'web_tests': _runWebHtmlUnitTests,
|
||||
// All the unit/widget tests run using `flutter test --platform=chrome --web-renderer=canvaskit`
|
||||
'web_canvaskit_tests': _runWebCanvasKitUnitTests,
|
||||
// All web integration tests
|
||||
'web_long_running_tests': _runWebLongRunningTests,
|
||||
'flutter_plugins': _runFlutterPluginsTests,
|
||||
|
@ -802,7 +857,15 @@ Future<void> _runFrameworkCoverage() async {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _runWebUnitTests() async {
|
||||
Future<void> _runWebHtmlUnitTests() {
|
||||
return _runWebUnitTests('html');
|
||||
}
|
||||
|
||||
Future<void> _runWebCanvasKitUnitTests() {
|
||||
return _runWebUnitTests('canvaskit');
|
||||
}
|
||||
|
||||
Future<void> _runWebUnitTests(String webRenderer) async {
|
||||
final Map<String, ShardRunner> subshards = <String, ShardRunner>{};
|
||||
|
||||
final Directory flutterPackageDirectory = Directory(path.join(flutterRoot, 'packages', 'flutter'));
|
||||
|
@ -817,7 +880,7 @@ Future<void> _runWebUnitTests() async {
|
|||
)
|
||||
.whereType<File>()
|
||||
.map<String>((File file) => path.relative(file.path, from: flutterPackageDirectory.path))
|
||||
.where((String filePath) => !kWebTestFileKnownFailures.contains(path.split(filePath).join('/')))
|
||||
.where((String filePath) => !kWebTestFileKnownFailures[webRenderer]!.contains(path.split(filePath).join('/')))
|
||||
.toList()
|
||||
// Finally we shuffle the list because we want the average cost per file to be uniformly
|
||||
// distributed. If the list is not sorted then different shards and batches may have
|
||||
|
@ -832,6 +895,7 @@ Future<void> _runWebUnitTests() async {
|
|||
// This for loop computes all but the last shard.
|
||||
for (int index = 0; index < webShardCount - 1; index += 1) {
|
||||
subshards['$index'] = () => _runFlutterWebTest(
|
||||
webRenderer,
|
||||
flutterPackageDirectory.path,
|
||||
allTests.sublist(
|
||||
index * testsPerShard,
|
||||
|
@ -846,6 +910,7 @@ Future<void> _runWebUnitTests() async {
|
|||
// between `.cirrus.yml` and `test.dart`.
|
||||
subshards['${webShardCount - 1}_last'] = () async {
|
||||
await _runFlutterWebTest(
|
||||
webRenderer,
|
||||
flutterPackageDirectory.path,
|
||||
allTests.sublist(
|
||||
(webShardCount - 1) * testsPerShard,
|
||||
|
@ -853,12 +918,14 @@ Future<void> _runWebUnitTests() async {
|
|||
),
|
||||
);
|
||||
await _runFlutterWebTest(
|
||||
webRenderer,
|
||||
path.join(flutterRoot, 'packages', 'flutter_web_plugins'),
|
||||
<String>['test'],
|
||||
);
|
||||
await _runFlutterWebTest(
|
||||
path.join(flutterRoot, 'packages', 'flutter_driver'),
|
||||
<String>[path.join('test', 'src', 'web_tests', 'web_extension_test.dart')],
|
||||
webRenderer,
|
||||
path.join(flutterRoot, 'packages', 'flutter_driver'),
|
||||
<String>[path.join('test', 'src', 'web_tests', 'web_extension_test.dart')],
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1421,7 +1488,7 @@ Future<void> _runWebDebugTest(String target, {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _runFlutterWebTest(String workingDirectory, List<String> tests) async {
|
||||
Future<void> _runFlutterWebTest(String webRenderer, String workingDirectory, List<String> tests) async {
|
||||
await runCommand(
|
||||
flutter,
|
||||
<String>[
|
||||
|
@ -1430,9 +1497,8 @@ Future<void> _runFlutterWebTest(String workingDirectory, List<String> tests) asy
|
|||
'--concurrency=1', // do not parallelize on Cirrus, to reduce flakiness
|
||||
'-v',
|
||||
'--platform=chrome',
|
||||
// TODO(ferhatb): Run web tests with both rendering backends.
|
||||
'--web-renderer=html', // use html backend for web tests.
|
||||
'--sound-null-safety', // web tests do not autodetect yet.
|
||||
'--web-renderer=$webRenderer',
|
||||
'--sound-null-safety',
|
||||
...flutterTestArgs,
|
||||
...tests,
|
||||
],
|
||||
|
|
|
@ -19,6 +19,7 @@ import 'package:process/process.dart';
|
|||
const String _kFlutterRootKey = 'FLUTTER_ROOT';
|
||||
const String _kGoldctlKey = 'GOLDCTL';
|
||||
const String _kTestBrowserKey = 'FLUTTER_TEST_BROWSER';
|
||||
const String _kWebRendererKey = 'FLUTTER_WEB_RENDERER';
|
||||
|
||||
/// A client for uploading image tests and making baseline requests to the
|
||||
/// Flutter Gold Dashboard.
|
||||
|
@ -368,6 +369,9 @@ class SkiaGoldClient {
|
|||
if (platform.environment[_kTestBrowserKey] != null) {
|
||||
keys['Browser'] = platform.environment[_kTestBrowserKey];
|
||||
keys['Platform'] = '${keys['Platform']}-browser';
|
||||
if (platform.environment[_kWebRendererKey] == 'canvaskit') {
|
||||
keys['WebRenderer'] = 'canvaskit';
|
||||
}
|
||||
}
|
||||
return json.encode(keys);
|
||||
}
|
||||
|
@ -413,7 +417,10 @@ class SkiaGoldClient {
|
|||
/// the image keys.
|
||||
String getTraceID(String testName) {
|
||||
final Map<String, dynamic> keys = <String, dynamic>{
|
||||
if (platform.environment[_kTestBrowserKey] != null) 'Browser' : platform.environment[_kTestBrowserKey],
|
||||
if (platform.environment[_kTestBrowserKey] != null)
|
||||
'Browser' : platform.environment[_kTestBrowserKey],
|
||||
if (platform.environment[_kTestBrowserKey] != null && platform.environment[_kWebRendererKey] == 'canvaskit')
|
||||
'WebRenderer' : 'canvaskit',
|
||||
'CI' : 'luci',
|
||||
'Platform' : platform.operatingSystem,
|
||||
'name' : testName,
|
||||
|
|
|
@ -404,17 +404,57 @@ class WebReleaseBundle extends Target {
|
|||
}
|
||||
}
|
||||
|
||||
/// Static assets provided by the Flutter SDK that do not change, such as
|
||||
/// CanvasKit.
|
||||
///
|
||||
/// These assets can be cached forever and are only invalidated when the
|
||||
/// Flutter SDK is upgraded to a new version.
|
||||
class WebBuiltInAssets extends Target {
|
||||
const WebBuiltInAssets(this.fileSystem);
|
||||
|
||||
final FileSystem fileSystem;
|
||||
|
||||
@override
|
||||
String get name => 'web_static_assets';
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[];
|
||||
|
||||
@override
|
||||
List<String> get depfiles => const <String>[];
|
||||
|
||||
@override
|
||||
List<Source> get inputs => const <Source>[];
|
||||
|
||||
@override
|
||||
List<Source> get outputs => const <Source>[];
|
||||
|
||||
@override
|
||||
Future<void> build(Environment environment) async {
|
||||
final Directory flutterWebSdk = globals.artifacts.getHostArtifact(HostArtifact.flutterWebSdk) as Directory;
|
||||
final Directory canvasKitDirectory = flutterWebSdk.childDirectory('canvaskit');
|
||||
for (final File file in canvasKitDirectory.listSync(recursive: true).whereType<File>()) {
|
||||
final String relativePath = fileSystem.path.relative(file.path, from: canvasKitDirectory.path);
|
||||
final String targetPath = fileSystem.path.join(environment.outputDir.path, 'canvaskit', relativePath);
|
||||
file.copySync(targetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a service worker for a web target.
|
||||
class WebServiceWorker extends Target {
|
||||
const WebServiceWorker();
|
||||
const WebServiceWorker(this.fileSystem);
|
||||
|
||||
final FileSystem fileSystem;
|
||||
|
||||
@override
|
||||
String get name => 'web_service_worker';
|
||||
|
||||
@override
|
||||
List<Target> get dependencies => const <Target>[
|
||||
Dart2JSTarget(),
|
||||
WebReleaseBundle(),
|
||||
List<Target> get dependencies => <Target>[
|
||||
const Dart2JSTarget(),
|
||||
const WebReleaseBundle(),
|
||||
WebBuiltInAssets(fileSystem),
|
||||
];
|
||||
|
||||
@override
|
||||
|
|
|
@ -49,7 +49,7 @@ List<Target> _kDefaultTargets = <Target>[
|
|||
const ReleaseBundleLinuxAssets(TargetPlatform.linux_x64),
|
||||
const ReleaseBundleLinuxAssets(TargetPlatform.linux_arm64),
|
||||
// Web targets
|
||||
const WebServiceWorker(),
|
||||
WebServiceWorker(globals.fs),
|
||||
const ReleaseAndroidApplication(),
|
||||
// This is a one-off rule for bundle and aot compat.
|
||||
const CopyFlutterBundle(),
|
||||
|
|
|
@ -196,6 +196,14 @@ class FlutterWebSdk extends CachedArtifact {
|
|||
entity.copySync(newPath);
|
||||
}
|
||||
}
|
||||
|
||||
final String canvasKitVersion = cache.getVersionFor('canvaskit')!;
|
||||
final String canvasKitUrl = '$_cipdBaseUrl/flutter/web/canvaskit_bundle/+/$canvasKitVersion';
|
||||
return artifactUpdater.downloadZipArchive(
|
||||
'Downloading CanvasKit...',
|
||||
Uri.parse(canvasKitUrl),
|
||||
location,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import '../base/file_system.dart';
|
|||
import '../base/io.dart';
|
||||
import '../base/logger.dart';
|
||||
import '../convert.dart';
|
||||
import '../web/compile.dart';
|
||||
import 'test_compiler.dart';
|
||||
import 'test_config.dart';
|
||||
|
||||
|
@ -31,6 +32,7 @@ class TestGoldenComparator {
|
|||
@required Logger logger,
|
||||
@required FileSystem fileSystem,
|
||||
@required ProcessManager processManager,
|
||||
@required this.webRenderer,
|
||||
}) : tempDir = fileSystem.systemTempDirectory.createTempSync('flutter_web_platform.'),
|
||||
_logger = logger,
|
||||
_fileSystem = fileSystem,
|
||||
|
@ -42,6 +44,7 @@ class TestGoldenComparator {
|
|||
final Logger _logger;
|
||||
final FileSystem _fileSystem;
|
||||
final ProcessManager _processManager;
|
||||
final WebRendererMode webRenderer;
|
||||
|
||||
TestCompiler _compiler;
|
||||
TestGoldenComparatorProcess _previousComparator;
|
||||
|
@ -88,6 +91,7 @@ class TestGoldenComparator {
|
|||
final Map<String, String> environment = <String, String>{
|
||||
// Chrome is the only supported browser currently.
|
||||
'FLUTTER_TEST_BROWSER': 'chrome',
|
||||
'FLUTTER_WEB_RENDERER': webRenderer == WebRendererMode.html ? 'html' : 'canvaskit',
|
||||
};
|
||||
return _processManager.start(command, environment: environment);
|
||||
}
|
||||
|
|
|
@ -53,11 +53,13 @@ class FlutterWebPlatform extends PlatformPlugin {
|
|||
@required Logger logger,
|
||||
@required Artifacts artifacts,
|
||||
@required ProcessManager processManager,
|
||||
@required Cache cache,
|
||||
}) : _fileSystem = fileSystem,
|
||||
_flutterToolPackageConfig = flutterToolPackageConfig,
|
||||
_chromiumLauncher = chromiumLauncher,
|
||||
_logger = logger,
|
||||
_artifacts = artifacts {
|
||||
_artifacts = artifacts,
|
||||
_cache = cache {
|
||||
final shelf.Cascade cascade = shelf.Cascade()
|
||||
.add(_webSocketHandler.handler)
|
||||
.add(createStaticHandler(
|
||||
|
@ -65,6 +67,7 @@ class FlutterWebPlatform extends PlatformPlugin {
|
|||
serveFilesOutsidePath: true,
|
||||
))
|
||||
.add(_handleStaticArtifact)
|
||||
.add(_localCanvasKitHandler)
|
||||
.add(_goldenFileHandler)
|
||||
.add(_wrapperHandler)
|
||||
.add(_handleTestRequest)
|
||||
|
@ -80,6 +83,7 @@ class FlutterWebPlatform extends PlatformPlugin {
|
|||
fileSystem: _fileSystem,
|
||||
logger: _logger,
|
||||
processManager: processManager,
|
||||
webRenderer: _rendererMode,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -95,6 +99,7 @@ class FlutterWebPlatform extends PlatformPlugin {
|
|||
final OneOffHandler _webSocketHandler = OneOffHandler();
|
||||
final AsyncMemoizer<void> _closeMemo = AsyncMemoizer<void>();
|
||||
final String _root;
|
||||
final Cache _cache;
|
||||
|
||||
/// Allows only one test suite (typically one test file) to be loaded and run
|
||||
/// at any given point in time. Loading more than one file at a time is known
|
||||
|
@ -117,6 +122,7 @@ class FlutterWebPlatform extends PlatformPlugin {
|
|||
@required ChromiumLauncher chromiumLauncher,
|
||||
@required Artifacts artifacts,
|
||||
@required ProcessManager processManager,
|
||||
@required Cache cache,
|
||||
}) async {
|
||||
final shelf_io.IOServer server = shelf_io.IOServer(await HttpMultiServer.loopback(0));
|
||||
final PackageConfig packageConfig = await loadPackageConfigWithLogging(
|
||||
|
@ -145,6 +151,7 @@ class FlutterWebPlatform extends PlatformPlugin {
|
|||
logger: logger,
|
||||
nullAssertions: nullAssertions,
|
||||
processManager: processManager,
|
||||
cache: cache,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -218,6 +225,23 @@ class FlutterWebPlatform extends PlatformPlugin {
|
|||
'host.dart.js',
|
||||
));
|
||||
|
||||
File _canvasKitFile(String relativePath) {
|
||||
// TODO(yjbanov): https://github.com/flutter/flutter/issues/52588
|
||||
//
|
||||
// Update this when we start building CanvasKit from sources. In the
|
||||
// meantime, get the Web SDK directory from cache rather than through
|
||||
// Artifacts. The latter is sensitive to `--local-engine`, which changes
|
||||
// the directory to point to ENGINE/src/out. However, CanvasKit is not yet
|
||||
// built as part of the engine, but fetched from CIPD, and so it won't be
|
||||
// found in ENGINE/src/out.
|
||||
final Directory webSdkDirectory = _cache.getWebSdkDirectory();
|
||||
final File canvasKitFile = _fileSystem.file(_fileSystem.path.join(
|
||||
webSdkDirectory.path,
|
||||
relativePath,
|
||||
));
|
||||
return canvasKitFile;
|
||||
}
|
||||
|
||||
Future<shelf.Response> _handleTestRequest(shelf.Request request) async {
|
||||
if (request.url.path.endsWith('.dart.browser_test.dart.js')) {
|
||||
final String leadingPath = request.url.path.split('.browser_test.dart.js')[0];
|
||||
|
@ -365,6 +389,37 @@ class FlutterWebPlatform extends PlatformPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
/// Serves a local build of CanvasKit, replacing the CDN build, which can
|
||||
/// cause test flakiness due to reliance on network.
|
||||
shelf.Response _localCanvasKitHandler(shelf.Request request) {
|
||||
final String path = _fileSystem.path.fromUri(request.url);
|
||||
if (!path.startsWith('canvaskit/')) {
|
||||
return shelf.Response.notFound('Not a CanvasKit file request');
|
||||
}
|
||||
|
||||
final String extension = _fileSystem.path.extension(path);
|
||||
String contentType;
|
||||
switch (extension) {
|
||||
case '.js':
|
||||
contentType = 'text/javascript';
|
||||
break;
|
||||
case '.wasm':
|
||||
contentType = 'application/wasm';
|
||||
break;
|
||||
default:
|
||||
final String error = 'Failed to determine Content-Type for "${request.url.path}".';
|
||||
_logger.printError(error);
|
||||
return shelf.Response.internalServerError(body: error);
|
||||
}
|
||||
|
||||
return shelf.Response.ok(
|
||||
_canvasKitFile(path).openRead(),
|
||||
headers: <String, Object>{
|
||||
HttpHeaders.contentTypeHeader: contentType,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// A handler that serves wrapper files used to bootstrap tests.
|
||||
shelf.Response _wrapperHandler(shelf.Request request) {
|
||||
final String path = _fileSystem.path.fromUri(request.url);
|
||||
|
@ -377,6 +432,11 @@ class FlutterWebPlatform extends PlatformPlugin {
|
|||
<html>
|
||||
<head>
|
||||
<title>${htmlEscape.convert(test)} Test</title>
|
||||
<script>
|
||||
window.flutterConfiguration = {
|
||||
canvasKitBaseUrl: "/canvaskit/"
|
||||
};
|
||||
</script>
|
||||
$link
|
||||
<script src="static/dart.js"></script>
|
||||
</head>
|
||||
|
|
|
@ -176,6 +176,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
|
|||
browserFinder: findChromeExecutable,
|
||||
logger: globals.logger,
|
||||
),
|
||||
cache: globals.cache,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -37,7 +37,7 @@ Future<void> buildWeb(
|
|||
final Status status = globals.logger.startProgress('Compiling $target for the Web...');
|
||||
final Stopwatch sw = Stopwatch()..start();
|
||||
try {
|
||||
final BuildResult result = await globals.buildSystem.build(const WebServiceWorker(), Environment(
|
||||
final BuildResult result = await globals.buildSystem.build(WebServiceWorker(globals.fs), Environment(
|
||||
projectDir: globals.fs.currentDirectory,
|
||||
outputDir: outputDirectory,
|
||||
buildDir: flutterProject.directory
|
||||
|
|
|
@ -637,7 +637,7 @@ void main() {
|
|||
environment.outputDir.childDirectory('a').childFile('a.txt')
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('A');
|
||||
await const WebServiceWorker().build(environment);
|
||||
await WebServiceWorker(globals.fs).build(environment);
|
||||
|
||||
expect(environment.outputDir.childFile('flutter_service_worker.js'), exists);
|
||||
// Contains file hash.
|
||||
|
@ -656,7 +656,7 @@ void main() {
|
|||
environment.outputDir
|
||||
.childFile('index.html')
|
||||
.createSync(recursive: true);
|
||||
await const WebServiceWorker().build(environment);
|
||||
await WebServiceWorker(globals.fs).build(environment);
|
||||
|
||||
expect(environment.outputDir.childFile('flutter_service_worker.js'), exists);
|
||||
// Contains file hash for both `/` and index.html.
|
||||
|
@ -674,7 +674,7 @@ void main() {
|
|||
environment.outputDir
|
||||
.childFile('main.dart.js.map')
|
||||
.createSync(recursive: true);
|
||||
await const WebServiceWorker().build(environment);
|
||||
await WebServiceWorker(globals.fs).build(environment);
|
||||
|
||||
// No caching of source maps.
|
||||
expect(environment.outputDir.childFile('flutter_service_worker.js').readAsStringSync(),
|
||||
|
|
|
@ -728,20 +728,49 @@ void main() {
|
|||
expect(logger.errorText, contains('Failed to delete some stamp files'));
|
||||
});
|
||||
|
||||
testWithoutContext('FlutterWebSdk deletes previous directory contents', () {
|
||||
testWithoutContext('FlutterWebSdk fetches web artifacts and deletes previous directory contents', () async {
|
||||
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
|
||||
final File canvasKitVersionFile = fileSystem.currentDirectory
|
||||
.childDirectory('cache')
|
||||
.childDirectory('bin')
|
||||
.childDirectory('internal')
|
||||
.childFile('canvaskit.version');
|
||||
canvasKitVersionFile.createSync(recursive: true);
|
||||
canvasKitVersionFile.writeAsStringSync('abcdefg');
|
||||
|
||||
final Cache cache = Cache.test(processManager: FakeProcessManager.any(), fileSystem: fileSystem);
|
||||
final Directory webCacheDirectory = cache.getWebSdkDirectory();
|
||||
final FakeArtifactUpdater artifactUpdater = FakeArtifactUpdater();
|
||||
final FlutterWebSdk webSdk = FlutterWebSdk(cache, platform: FakePlatform());
|
||||
|
||||
final List<String> messages = <String>[];
|
||||
final List<String> downloads = <String>[];
|
||||
final List<String> locations = <String>[];
|
||||
artifactUpdater.onDownloadZipArchive = (String message, Uri uri, Directory location) {
|
||||
messages.add(message);
|
||||
downloads.add(uri.toString());
|
||||
locations.add(location.path);
|
||||
location.createSync(recursive: true);
|
||||
location.childFile('foo').createSync();
|
||||
};
|
||||
webCacheDirectory.childFile('bar').createSync(recursive: true);
|
||||
|
||||
webSdk.updateInner(artifactUpdater, fileSystem, FakeOperatingSystemUtils());
|
||||
await webSdk.updateInner(artifactUpdater, fileSystem, FakeOperatingSystemUtils());
|
||||
|
||||
expect(messages, <String>[
|
||||
'Downloading Web SDK...',
|
||||
'Downloading CanvasKit...',
|
||||
]);
|
||||
|
||||
expect(downloads, <String>[
|
||||
'https://storage.googleapis.com/flutter_infra_release/flutter/null/flutter-web-sdk-linux-x64.zip',
|
||||
'https://chrome-infra-packages.appspot.com/dl/flutter/web/canvaskit_bundle/+/abcdefg',
|
||||
]);
|
||||
|
||||
expect(locations, <String>[
|
||||
'cache/bin/cache/flutter_web_sdk',
|
||||
'cache/bin/cache/flutter_web_sdk',
|
||||
]);
|
||||
|
||||
expect(webCacheDirectory.childFile('foo'), exists);
|
||||
expect(webCacheDirectory.childFile('bar'), isNot(exists));
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'package:flutter_tools/src/base/file_system.dart';
|
|||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/test/flutter_web_goldens.dart';
|
||||
import 'package:flutter_tools/src/test/test_compiler.dart';
|
||||
import 'package:flutter_tools/src/web/compile.dart';
|
||||
import 'package:test/fake.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
|
@ -45,7 +46,12 @@ void main() {
|
|||
'--non-interactive',
|
||||
'--packages=.dart_tool/package_config.json',
|
||||
'compiler_output'
|
||||
], stdout: '${jsonEncode(expectedResponse)}\n',
|
||||
],
|
||||
stdout: '${jsonEncode(expectedResponse)}\n',
|
||||
environment: const <String, String>{
|
||||
'FLUTTER_TEST_BROWSER': 'chrome',
|
||||
'FLUTTER_WEB_RENDERER': 'html',
|
||||
},
|
||||
));
|
||||
|
||||
final TestGoldenComparator comparator = TestGoldenComparator(
|
||||
|
@ -54,6 +60,7 @@ void main() {
|
|||
processManager: processManager,
|
||||
fileSystem: MemoryFileSystem.test(),
|
||||
logger: BufferLogger.test(),
|
||||
webRenderer: WebRendererMode.html,
|
||||
);
|
||||
|
||||
final String result = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false);
|
||||
|
@ -82,6 +89,7 @@ void main() {
|
|||
processManager: processManager,
|
||||
fileSystem: MemoryFileSystem.test(),
|
||||
logger: BufferLogger.test(),
|
||||
webRenderer: WebRendererMode.canvaskit,
|
||||
);
|
||||
|
||||
final String result = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false);
|
||||
|
@ -114,6 +122,7 @@ void main() {
|
|||
processManager: processManager,
|
||||
fileSystem: MemoryFileSystem.test(),
|
||||
logger: BufferLogger.test(),
|
||||
webRenderer: WebRendererMode.html,
|
||||
);
|
||||
|
||||
final String result1 = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false);
|
||||
|
@ -158,6 +167,7 @@ void main() {
|
|||
processManager: processManager,
|
||||
fileSystem: MemoryFileSystem.test(),
|
||||
logger: BufferLogger.test(),
|
||||
webRenderer: WebRendererMode.canvaskit,
|
||||
);
|
||||
|
||||
final String result1 = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false);
|
||||
|
@ -192,6 +202,7 @@ void main() {
|
|||
processManager: processManager,
|
||||
fileSystem: fileSystem,
|
||||
logger: BufferLogger.test(),
|
||||
webRenderer: WebRendererMode.html,
|
||||
);
|
||||
|
||||
final String result = await comparator.compareGoldens(testUri, imageBytes, goldenKey, false);
|
||||
|
|
|
@ -190,7 +190,7 @@ void testWithoutContext(String description, FutureOr<void> Function() body, {
|
|||
List<String>? tags,
|
||||
Map<String, dynamic>? onPlatform,
|
||||
int? retry,
|
||||
}) {
|
||||
}) {
|
||||
return test(
|
||||
description, () async {
|
||||
return runZoned(body, zoneValues: <Object, Object>{
|
||||
|
|
Loading…
Reference in a new issue