Unverified Commit cfb63356 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] use frontend_server for web test compilation (#70714)

parent 94244747
...@@ -88,7 +88,10 @@ const List<String> kWebTestFileKnownFailures = <String>[ ...@@ -88,7 +88,10 @@ const List<String> kWebTestFileKnownFailures = <String>[
'test/examples/sector_layout_test.dart', 'test/examples/sector_layout_test.dart',
// This test relies on widget tracking capability in the VM. // This test relies on widget tracking capability in the VM.
'test/widgets/widget_inspector_test.dart', 'test/widgets/widget_inspector_test.dart',
'test/painting/decoration_test.dart',
'test/material/time_picker_test.dart',
'test/material/text_field_test.dart',
'test/material/floating_action_button_test.dart',
'test/widgets/selectable_text_test.dart', 'test/widgets/selectable_text_test.dart',
'test/widgets/color_filter_test.dart', 'test/widgets/color_filter_test.dart',
'test/widgets/editable_text_cursor_test.dart', 'test/widgets/editable_text_cursor_test.dart',
...@@ -97,6 +100,16 @@ const List<String> kWebTestFileKnownFailures = <String>[ ...@@ -97,6 +100,16 @@ const List<String> kWebTestFileKnownFailures = <String>[
'test/cupertino/refresh_test.dart', 'test/cupertino/refresh_test.dart',
'test/cupertino/text_field_test.dart', 'test/cupertino/text_field_test.dart',
'test/cupertino/route_test.dart', 'test/cupertino/route_test.dart',
'test/foundation/error_reporting_test.dart',
'test/foundation/consolidate_response_test.dart',
'test/foundation/stack_trace_test.dart',
'test/services/message_codecs_vm_test.dart',
'test/services/platform_messages_test.dart',
'test/widgets/image_resolution_test.dart ',
'test/widgets/platform_view_test.dart',
'test/widgets/route_notification_messages_test.dart',
'test/widgets/semantics_tester_generateTestSemanticsExpressionForCurrentSemanticsTree_test.dart',
'test/widgets/text_golden_test.dart',
]; ];
/// When you call this, you can pass additional arguments to pass custom /// When you call this, you can pass additional arguments to pass custom
...@@ -782,7 +795,7 @@ Future<void> _runWebUnitTests() async { ...@@ -782,7 +795,7 @@ Future<void> _runWebUnitTests() async {
) )
.whereType<File>() .whereType<File>()
.map<String>((File file) => path.relative(file.path, from: flutterPackageDirectory.path)) .map<String>((File file) => path.relative(file.path, from: flutterPackageDirectory.path))
.where((String filePath) => !kWebTestFileKnownFailures.contains(filePath)) .where((String filePath) => !kWebTestFileKnownFailures.contains(path.split(filePath).join('/')))
.toList() .toList()
// Finally we shuffle the list because we want the average cost per file to be uniformly // 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 // distributed. If the list is not sorted then different shards and batches may have
......
This package contains the custom build script used to compile Flutter for Web applications before support for JavaScript was added into the frontend_server. It is still used for test compilation today and is hosted here to reduce the number of dependencies that the flutter_tool has. For more information on the plans for flutter test --platform=chrome, see https://github.com/flutter/flutter/issues/50594
# Use the analysis options settings from the top level of the repo (not
# the ones from above, which include the `public_member_api_docs` rule).
include: ../../analysis_options.yaml
linter:
rules:
unawaited_futures: true
curly_braces_in_flow_control_structures: true
// Copyright 2014 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_for_file: implementation_imports
import 'dart:isolate';
import 'package:build/build.dart';
import 'package:build_config/build_config.dart';
import 'package:build_modules/build_modules.dart';
import 'package:build_modules/builders.dart';
import 'package:build_modules/src/module_builder.dart';
import 'package:build_modules/src/platform.dart';
import 'package:build_runner/build_runner.dart' as build_runner;
import 'package:build_runner_core/build_runner_core.dart' as core;
import 'package:build_test/builder.dart';
import 'package:build_test/src/debug_test_builder.dart';
import 'package:build_web_compilers/build_web_compilers.dart';
import 'package:build_web_compilers/builders.dart';
import 'package:build_web_compilers/src/dev_compiler_bootstrap.dart';
import 'package:path/path.dart' as path; // ignore: package_path_import
import 'package:test_core/backend.dart'; // ignore: deprecated_member_use
import 'package:build_runner_core/src/util/constants.dart' as core;
const String ddcBootstrapExtension = '.dart.bootstrap.js';
const String jsEntrypointExtension = '.dart.js';
const String jsEntrypointSourceMapExtension = '.dart.js.map';
const String jsEntrypointArchiveExtension = '.dart.js.tar.gz';
const String digestsEntrypointExtension = '.digests';
const String jsModuleErrorsExtension = '.ddc.js.errors';
const String jsModuleExtension = '.ddc.js';
const String jsSourceMapExtension = '.ddc.js.map';
const String kReleaseFlag = 'release';
const String kProfileFlag = 'profile';
final DartPlatform flutterWebPlatform = DartPlatform.register('flutter_web', <String>[
'async',
'collection',
'convert',
'core',
'developer',
'html',
'html_common',
'indexed_db',
'js',
'js_util',
'math',
'svg',
'typed_data',
'web_audio',
'web_gl',
'web_sql',
'_internal',
// Flutter web specific libraries.
'ui',
'_engine',
]);
/// The builders required to compile a Flutter application to the web.
final List<core.BuilderApplication> builders = <core.BuilderApplication>[
core.apply(
'flutter_tools:test_bootstrap',
<BuilderFactory>[
(BuilderOptions options) => const DebugTestBuilder(),
(BuilderOptions options) => const FlutterWebTestBootstrapBuilder(),
],
core.toRoot(),
hideOutput: true,
defaultGenerateFor: const InputSet(
include: <String>[
'test/**',
],
),
),
core.apply(
'flutter_tools:module_library',
<Builder Function(BuilderOptions)>[moduleLibraryBuilder],
core.toAllPackages(),
isOptional: true,
hideOutput: true,
appliesBuilders: <String>['flutter_tools:module_cleanup']),
core.apply(
'flutter_tools:ddc_modules',
<Builder Function(BuilderOptions)>[
(BuilderOptions options) => MetaModuleBuilder(flutterWebPlatform),
(BuilderOptions options) => MetaModuleCleanBuilder(flutterWebPlatform),
(BuilderOptions options) => ModuleBuilder(flutterWebPlatform),
],
core.toNoneByDefault(),
isOptional: true,
hideOutput: true,
appliesBuilders: <String>['flutter_tools:module_cleanup']),
core.apply(
'flutter_tools:ddc',
<Builder Function(BuilderOptions)>[
(BuilderOptions builderOptions) => KernelBuilder(
platformSdk: builderOptions.config['flutterWebSdk'] as String,
summaryOnly: true,
sdkKernelPath: path.join('kernel', 'flutter_ddc_sdk.dill'),
outputExtension: ddcKernelExtension,
platform: flutterWebPlatform,
librariesPath: path.absolute(path.join(builderOptions.config['flutterWebSdk'] as String, 'libraries.json')),
kernelTargetName: 'ddc',
useIncrementalCompiler: true,
trackUnusedInputs: true,
experiments: <String>['non-nullable'], // ignore: deprecated_member_use
),
(BuilderOptions builderOptions) => DevCompilerBuilder(
useIncrementalCompiler: true,
trackUnusedInputs: true,
platform: flutterWebPlatform,
platformSdk: builderOptions.config['flutterWebSdk'] as String,
sdkKernelPath: path.url.join('kernel', 'flutter_ddc_sdk.dill'),
experiments: <String>['non-nullable'],
librariesPath: path.absolute(path.join(builderOptions.config['flutterWebSdk'] as String, 'libraries.json')),
),
],
core.toAllPackages(),
isOptional: true,
hideOutput: true,
appliesBuilders: <String>['flutter_tools:ddc_modules']),
core.apply(
'flutter_tools:test_entrypoint',
<BuilderFactory>[
(BuilderOptions options) => const FlutterWebTestEntrypointBuilder(),
],
core.toRoot(),
hideOutput: true,
defaultGenerateFor: const InputSet(
include: <String>[
'test/**_test.dart.browser_test.dart',
],
),
),
core.applyPostProcess('flutter_tools:module_cleanup', moduleCleanup,
defaultGenerateFor: const InputSet()),
];
/// The entry point to this build script.
Future<void> main(List<String> args, [SendPort sendPort]) async {
core.overrideGeneratedOutputDirectory('flutter_web');
final int result = await build_runner.run(args, builders);
sendPort?.send(result);
}
/// A ddc-only entry point builder that respects the Flutter target flag.
class FlutterWebTestEntrypointBuilder implements Builder {
const FlutterWebTestEntrypointBuilder();
@override
Map<String, List<String>> get buildExtensions => const <String, List<String>>{
'.dart': <String>[
ddcBootstrapExtension,
jsEntrypointExtension,
jsEntrypointSourceMapExtension,
jsEntrypointArchiveExtension,
digestsEntrypointExtension,
],
};
@override
Future<void> build(BuildStep buildStep) async {
log.info('building for target ${buildStep.inputId.path}');
await bootstrapDdc(
buildStep,
platform: flutterWebPlatform,
skipPlatformCheck: true,
);
}
}
/// Bootstraps the test entry point.
class FlutterWebTestBootstrapBuilder implements Builder {
const FlutterWebTestBootstrapBuilder();
@override
Map<String, List<String>> get buildExtensions => const <String, List<String>>{
'_test.dart': <String>[
'_test.dart.browser_test.dart',
],
};
@override
Future<void> build(BuildStep buildStep) async {
final AssetId id = buildStep.inputId;
final String contents = await buildStep.readAsString(id);
final String assetPath = id.pathSegments.first == 'lib'
? path.url.join('packages', id.package, id.path)
: id.path;
final Uri testUrl = path.toUri(path.absolute(assetPath));
final Metadata metadata = parseMetadata(
assetPath, contents, Runtime.builtIn.map((Runtime runtime) => runtime.name).toSet());
if (metadata.testOn.evaluate(SuitePlatform(Runtime.chrome))) {
await buildStep.writeAsString(id.addExtension('.browser_test.dart'), '''
// @dart = 2.8
import 'dart:ui' as ui;
import 'dart:html';
import 'dart:js';
import 'package:stream_channel/stream_channel.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:test_api/src/backend/stack_trace_formatter.dart'; // ignore: implementation_imports
import 'package:test_api/src/remote_listener.dart'; // ignore: implementation_imports
import 'package:test_api/src/suite_channel_manager.dart'; // ignore: implementation_imports
import "${path.url.basename(id.path)}" as test;
Future<void> main() async {
// Extra initialization for flutter_web.
// The following parameters are hard-coded in Flutter's test embedder. Since
// we don't have an embedder yet this is the lowest-most layer we can put
// this stuff in.
ui.debugEmulateFlutterTesterEnvironment = true;
await ui.webOnlyInitializePlatform();
webGoldenComparator = DefaultWebGoldenComparator(Uri.parse('$testUrl'));
// TODO(flutterweb): remove need for dynamic cast.
(ui.window as dynamic).debugOverrideDevicePixelRatio(3.0);
(ui.window as dynamic).webOnlyDebugPhysicalSizeOverride = const ui.Size(2400, 1800);
internalBootstrapBrowserTest(() => test.main);
}
void internalBootstrapBrowserTest(Function getMain()) {
var channel = serializeSuite(getMain, hidePrints: false);
postMessageChannel().pipe(channel);
}
StreamChannel serializeSuite(Function getMain(),
{bool hidePrints = true, Future beforeLoad()}) =>
RemoteListener.start(getMain,
hidePrints: hidePrints, beforeLoad: beforeLoad);
StreamChannel suiteChannel(String name) {
var manager = SuiteChannelManager.current;
if (manager == null) {
throw StateError('suiteChannel() may only be called within a test worker.');
}
return manager.connectOut(name);
}
StreamChannel postMessageChannel() {
var controller = StreamChannelController(sync: true);
window.onMessage.firstWhere((message) {
return message.origin == window.location.origin && message.data == "port";
}).then((message) {
var port = message.ports.first;
var portSubscription = port.onMessage.listen((message) {
controller.local.sink.add(message.data);
});
controller.local.stream.listen((data) {
port.postMessage({"data": data});
}, onDone: () {
port.postMessage({"event": "done"});
portSubscription.cancel();
});
});
context['parent'].callMethod('postMessage', [
JsObject.jsify({"href": window.location.href, "ready": true}),
window.location.origin,
]);
return controller.foreign;
}
''');
}
}
}
name: _flutter_web_build_script
description: A build script for flutter test --platform=chrome
homepage: https://flutter.dev
author: Flutter Authors <flutter-dev@googlegroups.com>
environment:
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
sdk: ">=2.7.0 <3.0.0"
dependencies:
# We depend on very specific internal implementation details of the
# 'test' package, which change between versions, so when upgrading
# this, make sure the tests are still running correctly.
test_api: 0.2.19-nullsafety.6
test_core: 0.3.12-nullsafety.9
build_runner: 1.10.2
build_test: 1.3.0
build_runner_core: 5.2.0
dart_style: 1.3.6
code_builder: 3.5.0
build: 1.3.0
build_modules: 2.10.1
build_daemon: 2.1.4
build_web_compilers: 2.11.0
_fe_analyzer_shared: 7.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
analyzer: 0.39.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
archive: 2.0.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.5.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
bazel_worker: 0.1.25 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
boolean_selector: 2.1.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
build_config: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
build_resolvers: 1.3.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
built_collection: 4.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
built_value: 7.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.2.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
checked_yaml: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.15.0-nullsafety.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 0.14.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.16.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
fixnum: 0.10.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
glob: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
graphs: 0.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
html: 0.14.0+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http_multi_server: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http_parser: 3.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
io: 0.3.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
js: 0.6.3-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
json_annotation: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
logging: 0.11.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.10-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.3.0-nullsafety.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
mime: 0.9.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_interop: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_io: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_preamble: 1.4.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
package_config: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
path: 1.8.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pedantic: 1.10.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pool: 1.5.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
protobuf: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pub_semver: 1.4.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pubspec_parse: 0.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
quiver: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
scratch_space: 0.0.4+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf: 0.7.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_packages_handler: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_static: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_web_socket: 0.2.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_map_stack_trace: 2.1.0-nullsafety.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_maps: 0.10.10-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_span: 1.8.0-nullsafety.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stack_trace: 1.10.0-nullsafety.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.1.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_transform: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.1.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.2.0-nullsafety.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test: 1.16.0-nullsafety.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
timing: 0.1.1+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.3.0-nullsafety.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service: 5.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webkit_inspection_protocol: 0.7.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dartdoc:
# Exclude this package from the hosted API docs.
nodoc: true
# PUBSPEC CHECKSUM: d4a7
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome')
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import '../flutter_test_alternative.dart'; import '../flutter_test_alternative.dart';
...@@ -40,7 +38,7 @@ void main() { ...@@ -40,7 +38,7 @@ void main() {
expect(field[_TestEnum.c], isTrue); expect(field[_TestEnum.c], isTrue);
expect(field[_TestEnum.d], isTrue); expect(field[_TestEnum.d], isTrue);
expect(field[_TestEnum.e], isTrue); expect(field[_TestEnum.e], isTrue);
}); }, skip: kIsWeb);
test('BitField.filed control test', () { test('BitField.filed control test', () {
final BitField<_TestEnum> field1 = BitField<_TestEnum>.filled(8, true); final BitField<_TestEnum> field1 = BitField<_TestEnum>.filled(8, true);
...@@ -50,5 +48,5 @@ void main() { ...@@ -50,5 +48,5 @@ void main() {
final BitField<_TestEnum> field2 = BitField<_TestEnum>.filled(8, false); final BitField<_TestEnum> field2 = BitField<_TestEnum>.filled(8, false);
expect(field2[_TestEnum.d], isFalse); expect(field2[_TestEnum.d], isFalse);
}); }, skip: kIsWeb);
} }
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome')
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
...@@ -147,7 +145,7 @@ void main() { ...@@ -147,7 +145,7 @@ void main() {
]); ]);
}); });
}); });
}); }, skip: kIsWeb);
} }
class MockHttpClientResponse extends Fake implements HttpClientResponse { class MockHttpClientResponse extends Fake implements HttpClientResponse {
......
...@@ -2,12 +2,11 @@ ...@@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome') // This test is not intended to run on the web.
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import '../flutter_test_alternative.dart'; import '../flutter_test_alternative.dart';
void main() { void main() {
test('isWeb is false for flutter tester', () { test('isWeb is false for flutter tester', () {
expect(kIsWeb, false); expect(kIsWeb, false);
}); }, skip: kIsWeb);
} }
// Copyright 2014 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 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
test('defines match expectations per platform', () {
expect(kIsWeb, !const bool.fromEnvironment('dart.library.io'));
expect(kIsWeb, !const bool.fromEnvironment('dart.library.isolate'));
expect(kIsWeb, const bool.fromEnvironment('dart.library.html'));
});
}
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome') // web has different stack traces
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import '../flutter_test_alternative.dart'; import '../flutter_test_alternative.dart';
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome') // isolates not supported on the web.
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import '../flutter_test_alternative.dart'; import '../flutter_test_alternative.dart';
...@@ -31,5 +29,5 @@ void main() { ...@@ -31,5 +29,5 @@ void main() {
expect(await compute(test1Async, 0), 1); expect(await compute(test1Async, 0), 1);
expect(compute(test2Async, 0), throwsException); expect(compute(test2Async, 0), throwsException);
}); }, skip: kIsWeb);
} }
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome')
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import '../flutter_test_alternative.dart'; import '../flutter_test_alternative.dart';
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome') // web does not support certain 64bit behavior
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
...@@ -42,7 +40,7 @@ void main() { ...@@ -42,7 +40,7 @@ void main() {
expect(written.lengthInBytes, equals(8)); expect(written.lengthInBytes, equals(8));
final ReadBuffer read = ReadBuffer(written); final ReadBuffer read = ReadBuffer(written);
expect(read.getInt64(), equals(-9000000000000)); expect(read.getInt64(), equals(-9000000000000));
}); }, skip: kIsWeb);
test('of 64-bit integer in big endian', () { test('of 64-bit integer in big endian', () {
final WriteBuffer write = WriteBuffer(); final WriteBuffer write = WriteBuffer();
write.putInt64(-9000000000000, endian: Endian.big); write.putInt64(-9000000000000, endian: Endian.big);
...@@ -50,7 +48,7 @@ void main() { ...@@ -50,7 +48,7 @@ void main() {
expect(written.lengthInBytes, equals(8)); expect(written.lengthInBytes, equals(8));
final ReadBuffer read = ReadBuffer(written); final ReadBuffer read = ReadBuffer(written);
expect(read.getInt64(endian: Endian.big), equals(-9000000000000)); expect(read.getInt64(endian: Endian.big), equals(-9000000000000));
}); }, skip: kIsWeb);
test('of double', () { test('of double', () {
final WriteBuffer write = WriteBuffer(); final WriteBuffer write = WriteBuffer();
write.putFloat64(3.14); write.putFloat64(3.14);
...@@ -88,7 +86,7 @@ void main() { ...@@ -88,7 +86,7 @@ void main() {
final ReadBuffer read = ReadBuffer(written); final ReadBuffer read = ReadBuffer(written);
read.getUint8(); read.getUint8();
expect(read.getInt64List(3), equals(integers)); expect(read.getInt64List(3), equals(integers));
}); }, skip: kIsWeb);
test('of double list when unaligned', () { test('of double list when unaligned', () {
final Float64List doubles = Float64List.fromList(<double>[3.14, double.nan]); final Float64List doubles = Float64List.fromList(<double>[3.14, double.nan]);
final WriteBuffer write = WriteBuffer(); final WriteBuffer write = WriteBuffer();
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome') // web has different stack traces
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import '../flutter_test_alternative.dart'; import '../flutter_test_alternative.dart';
...@@ -16,7 +14,7 @@ void main() { ...@@ -16,7 +14,7 @@ void main() {
expect(filtered[0], matches(r'^#0 +main\.<anonymous closure> \(.*stack_trace_test\.dart:[0-9]+:[0-9]+\)$')); expect(filtered[0], matches(r'^#0 +main\.<anonymous closure> \(.*stack_trace_test\.dart:[0-9]+:[0-9]+\)$'));
expect(filtered[1], matches(r'^#1 +Declarer\.test\.<anonymous closure>.<anonymous closure> \(package:test_api/.+:[0-9]+:[0-9]+\)$')); expect(filtered[1], matches(r'^#1 +Declarer\.test\.<anonymous closure>.<anonymous closure> \(package:test_api/.+:[0-9]+:[0-9]+\)$'));
expect(filtered[2], equals('<asynchronous suspension>')); expect(filtered[2], equals('<asynchronous suspension>'));
}); }, skip: kIsWeb);
test('FlutterError.defaultStackFilter (async test body)', () async { test('FlutterError.defaultStackFilter (async test body)', () async {
final List<String> filtered = FlutterError.defaultStackFilter(StackTrace.current.toString().trimRight().split('\n')).toList(); final List<String> filtered = FlutterError.defaultStackFilter(StackTrace.current.toString().trimRight().split('\n')).toList();
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome') // whole file needs triage.
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome') // This whole test suite needs triage.
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:ui' as ui show window, BoxHeightStyle, BoxWidthStyle; import 'dart:ui' as ui show window, BoxHeightStyle, BoxWidthStyle;
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome') // entire file needs triage.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome')
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui' as ui show Image, ColorFilter; import 'dart:ui' as ui show Image, ColorFilter;
...@@ -357,7 +356,7 @@ void main() { ...@@ -357,7 +356,7 @@ void main() {
' The ImageConfiguration was:\n' ' The ImageConfiguration was:\n'
' ImageConfiguration(size: Size(100.0, 100.0))\n' ' ImageConfiguration(size: Size(100.0, 100.0))\n'
); );
}); }, skip: kIsWeb);
test('DecorationImage - error listener', () async { test('DecorationImage - error listener', () async {
late String exception; late String exception;
...@@ -702,5 +701,5 @@ void main() { ...@@ -702,5 +701,5 @@ void main() {
expect(info.image.debugGetOpenHandleStackTraces()!.length, baselineRefCount); expect(info.image.debugGetOpenHandleStackTraces()!.length, baselineRefCount);
info.dispose(); info.dispose();
}); }, skip: kIsWeb);
} }
...@@ -2,9 +2,6 @@ ...@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// TODO(yjbanov): enable Web when https://github.com/flutter/engine/pull/12747 rolls into the framework.
@TestOn('!chrome')
import 'dart:convert'; import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui' as ui; import 'dart:ui' as ui;
......
...@@ -2,13 +2,9 @@ ...@@ -2,13 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// This file contains tests that are only supported by the Dart VM. For
// example, on the Web there's no way to express large integers.
@TestOn('!chrome')
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import '../flutter_test_alternative.dart'; import '../flutter_test_alternative.dart';
import 'message_codecs_testing.dart'; import 'message_codecs_testing.dart';
...@@ -81,5 +77,5 @@ void main() { ...@@ -81,5 +77,5 @@ void main() {
]; ];
checkEncodeDecode<dynamic>(standard, message); checkEncodeDecode<dynamic>(standard, message);
}); });
}); }, skip: kIsWeb);
} }
...@@ -2,9 +2,6 @@ ...@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome') // missing web infrastructure for plugins.
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
......
...@@ -248,7 +248,7 @@ void main() { ...@@ -248,7 +248,7 @@ void main() {
expect(errorDetails.exception, isAssertionError); expect(errorDetails.exception, isAssertionError);
const String toMatch = '... Normal element mounting ('; const String toMatch = '... Normal element mounting (';
expect(toMatch.allMatches(errorDetails.toString()).length, 1); expect(toMatch.allMatches(errorDetails.toString()).length, 1);
}); }, skip: kIsWeb);
} }
class TestStatefulWidget extends StatefulWidget { class TestStatefulWidget extends StatefulWidget {
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('chrome') @TestOn('chrome')
import 'dart:async'; import 'dart:async';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome') // asset bundle behaves differently.
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui' as ui show Image; import 'dart:ui' as ui show Image;
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome') // diagnostics use Platform.operatingSystem.
import 'dart:io' show Platform; import 'dart:io' show Platform;
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
...@@ -530,6 +530,6 @@ void main() { ...@@ -530,6 +530,6 @@ void main() {
' constraints: BoxConstraints(w=800.0, h=400.0)\n' ' constraints: BoxConstraints(w=800.0, h=400.0)\n'
' size: Size(800.0, 400.0)\n' ' size: Size(800.0, 400.0)\n'
)); ));
}); }, skip: kIsWeb);
} }
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome')
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui'; import 'dart:ui';
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('chrome')
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome')
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
@TestOn('!chrome') // Flaky on web
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
......
...@@ -950,10 +950,10 @@ class WebDevFS implements DevFS { ...@@ -950,10 +950,10 @@ class WebDevFS implements DevFS {
parentDirectory.childFile('${compilerOutput.outputFilename}.json'); parentDirectory.childFile('${compilerOutput.outputFilename}.json');
sourcemapFile = sourcemapFile =
parentDirectory.childFile('${compilerOutput.outputFilename}.map'); parentDirectory.childFile('${compilerOutput.outputFilename}.map');
metadataFile = parentDirectory metadataFile =
.childFile('${compilerOutput.outputFilename}.metadata'); parentDirectory.childFile('${compilerOutput.outputFilename}.metadata');
modules = webAssetServer.write( modules =
codeFile, manifestFile, sourcemapFile, metadataFile); webAssetServer.write(codeFile, manifestFile, sourcemapFile, metadataFile);
} on FileSystemException catch (err) { } on FileSystemException catch (err) {
throwToolExit('Failed to load recompiled sources:\n$err'); throwToolExit('Failed to load recompiled sources:\n$err');
} }
......
...@@ -2,266 +2,261 @@ ...@@ -2,266 +2,261 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:build_daemon/client.dart'; import 'dart:typed_data';
import 'package:build_daemon/constants.dart' as daemon;
import 'package:build_daemon/data/build_status.dart'; import 'package:meta/meta.dart';
import 'package:build_daemon/data/build_target.dart';
import 'package:build_daemon/data/server_log.dart';
import 'package:path/path.dart' as path; // ignore: package_path_import
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/utils.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../cache.dart'; import '../bundle.dart';
import '../dart/pub.dart'; import '../compile.dart';
import '../convert.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../platform_plugins.dart';
import '../plugins.dart';
import '../project.dart';
import '../web/compile.dart'; import '../web/compile.dart';
/// A build_runner specific implementation of the [WebCompilationProxy]. // TODO(jonahwilliams): this class was kept around to reduce the diff in the migration
// from build_runner to the frontend_server, but should be removed/refactored to be
// similar to the test_compiler pattern used for regular flutter tests
class BuildRunnerWebCompilationProxy extends WebCompilationProxy { class BuildRunnerWebCompilationProxy extends WebCompilationProxy {
BuildRunnerWebCompilationProxy(); BuildRunnerWebCompilationProxy();
@override @override
Future<bool> initialize({ Future<WebVirtualFS> initialize({
Directory projectDirectory, @required Directory projectDirectory,
String testOutputDir, @required String testOutputDir,
List<String> testFiles, @required List<String> testFiles,
BuildMode mode, @required BuildInfo buildInfo,
String projectName,
bool initializePlatform,
}) async { }) async {
// Create the .dart_tool directory if it doesn't exist. if (buildInfo.nullSafetyMode == NullSafetyMode.sound) {
projectDirectory throwToolExit('flutter test --platform=chrome does not currently support sound mode');
.childDirectory('.dart_tool')
.createSync();
final FlutterProject flutterProject = FlutterProject.fromDirectory(projectDirectory);
final bool hasWebPlugins = (await findPlugins(flutterProject))
.any((Plugin p) => p.platforms.containsKey(WebPlugin.kConfigKey));
final BuildDaemonClient client = await const BuildDaemonCreator().startBuildDaemon(
projectDirectory.path,
release: mode == BuildMode.release,
profile: mode == BuildMode.profile,
hasPlugins: hasWebPlugins,
initializePlatform: initializePlatform,
testTargets: WebTestTargetManifest(
testFiles
.map<String>((String absolutePath) {
final String relativePath = path.relative(absolutePath, from: projectDirectory.path);
return '${path.withoutExtension(relativePath)}.*';
})
.toList(),
),
);
client.startBuild();
bool success = true;
await for (final BuildResults results in client.buildResults) {
final BuildResult result = results.results.firstWhere((BuildResult result) {
return result.target == 'web';
}, orElse: () {
// Assume build failed if we lack any results.
return DefaultBuildResult((DefaultBuildResultBuilder b) => b.status == BuildStatus.failed);
});
if (result.status == BuildStatus.failed) {
success = false;
break;
}
if (result.status == BuildStatus.succeeded) {
break;
}
} }
if (!success || testOutputDir == null) { final List<String> extraFrontEndOptions = List<String>.of(buildInfo.extraFrontEndOptions ?? <String>[]);
return success; if (!extraFrontEndOptions.contains('--no-sound-null-safety')) {
extraFrontEndOptions.add('--no-sound-null-safety');
} }
final Directory rootDirectory = projectDirectory final Directory outputDirectory = globals.fs.directory(testOutputDir)
.childDirectory('.dart_tool') ..createSync(recursive: true);
.childDirectory('build') final List<File> generatedFiles = <File>[];
.childDirectory('flutter_web'); for (final String testFilePath in testFiles) {
final List<String> relativeTestSegments = globals.fs.path.split(
globals.fs.path.relative(testFilePath, from: projectDirectory.childDirectory('test').path));
final File generatedFile = globals.fs.file(
globals.fs.path.join(outputDirectory.path, '${relativeTestSegments.join('_')}.test.dart'));
generatedFile
..createSync(recursive: true)
..writeAsStringSync(_generateEntrypoint(relativeTestSegments.join('/'), testFilePath));
generatedFiles.add(generatedFile);
}
// Generate a fake main file that imports all tests to be executed. This will force
// each of them to be compiled.
final StringBuffer buffer = StringBuffer('// @dart=2.8\n');
for (final File generatedFile in generatedFiles) {
buffer.writeln('import "${globals.fs.path.basename(generatedFile.path)}";');
}
buffer.writeln('void main() {}');
globals.fs.file(globals.fs.path.join(outputDirectory.path, 'main.dart'))
..createSync()
..writeAsStringSync(buffer.toString());
final Iterable<Directory> childDirectories = rootDirectory final ResidentCompiler residentCompiler = ResidentCompiler(
.listSync() globals.artifacts.getArtifactPath(Artifact.flutterWebSdk, mode: buildInfo.mode),
.whereType<Directory>(); buildMode: buildInfo.mode,
for (final Directory childDirectory in childDirectories) { trackWidgetCreation: buildInfo.trackWidgetCreation,
final String path = globals.fs.path.join( fileSystemRoots: <String>[
projectDirectory.childDirectory('test').path,
testOutputDir, testOutputDir,
'packages', ],
globals.fs.path.basename(childDirectory.path), // Override the filesystem scheme so that the frontend_server can find
); // the generated entrypoint code.
globals.fsUtils.copyDirectorySync( fileSystemScheme: 'org-dartlang-app',
childDirectory.childDirectory('lib'), initializeFromDill: getDefaultCachedKernelPath(
globals.fs.directory(path), trackWidgetCreation: buildInfo.trackWidgetCreation,
); dartDefines: buildInfo.dartDefines,
extraFrontEndOptions: extraFrontEndOptions,
),
targetModel: TargetModel.dartdevc,
extraFrontEndOptions: extraFrontEndOptions,
platformDill: globals.fs.file(globals.artifacts
.getArtifactPath(Artifact.webPlatformKernelDill, mode: buildInfo.mode))
.absolute.uri.toString(),
dartDefines: buildInfo.dartDefines,
librariesSpec: globals.fs.file(globals.artifacts
.getArtifactPath(Artifact.flutterWebLibrariesJson)).uri.toString(),
packagesPath: buildInfo.packagesPath,
artifacts: globals.artifacts,
processManager: globals.processManager,
logger: globals.logger,
platform: globals.platform,
);
final CompilerOutput output = await residentCompiler.recompile(
Uri.parse('org-dartlang-app:///main.dart'),
<Uri>[],
outputPath: outputDirectory.childFile('out').path,
packageConfig: buildInfo.packageConfig,
);
if (output.errorCount > 0) {
throwToolExit('Failed to compile');
} }
final Directory outputDirectory = rootDirectory final File codeFile = outputDirectory.childFile('${output.outputFilename}.sources');
.childDirectory(projectName) final File manifestFile = outputDirectory.childFile('${output.outputFilename}.json');
.childDirectory('test'); final File sourcemapFile = outputDirectory.childFile('${output.outputFilename}.map');
globals.fsUtils.copyDirectorySync( final File metadataFile = outputDirectory.childFile('${output.outputFilename}.metadata');
outputDirectory, final WebVirtualFS webVirtualFS = WebVirtualFS();
globals.fs.directory(globals.fs.path.join(testOutputDir)), _write(
codeFile,
manifestFile,
sourcemapFile,
metadataFile,
webVirtualFS,
); );
return success; return webVirtualFS;
} }
}
class WebTestTargetManifest {
WebTestTargetManifest(this.buildFilters);
WebTestTargetManifest.all() : buildFilters = null;
final List<String> buildFilters;
bool get hasBuildFilters => buildFilters != null && buildFilters.isNotEmpty; void _write(
} File codeFile,
File manifestFile,
/// A testable interface for starting a build daemon. File sourcemapFile,
class BuildDaemonCreator { File metadataFile,
const BuildDaemonCreator(); WebVirtualFS webVirtualFS,
) {
final Uint8List codeBytes = codeFile.readAsBytesSync();
final Uint8List sourcemapBytes = sourcemapFile.readAsBytesSync();
final Uint8List metadataBytes = metadataFile.readAsBytesSync();
final Map<String, dynamic> manifest =
castStringKeyedMap(json.decode(manifestFile.readAsStringSync()));
for (final String filePath in manifest.keys) {
if (filePath == null) {
globals.printTrace('Invalid manifest file: $filePath');
continue;
}
final Map<String, dynamic> offsets =
castStringKeyedMap(manifest[filePath]);
final List<int> codeOffsets =
(offsets['code'] as List<dynamic>).cast<int>();
final List<int> sourcemapOffsets =
(offsets['sourcemap'] as List<dynamic>).cast<int>();
final List<int> metadataOffsets =
(offsets['metadata'] as List<dynamic>).cast<int>();
if (codeOffsets.length != 2 ||
sourcemapOffsets.length != 2 ||
metadataOffsets.length != 2) {
globals.printTrace('Invalid manifest byte offsets: $offsets');
continue;
}
// TODO(jonahwilliams): find a way to get build checks working for flutter for web. final int codeStart = codeOffsets[0];
static const String _ignoredLine1 = 'Warning: Interpreting this as package URI'; final int codeEnd = codeOffsets[1];
static const String _ignoredLine2 = 'build_script.dart was not found in the asset graph, incremental builds will not work'; if (codeStart < 0 || codeEnd > codeBytes.lengthInBytes) {
static const String _ignoredLine3 = 'have your dependencies specified fully in your pubspec.yaml'; globals.printTrace('Invalid byte index: [$codeStart, $codeEnd]');
continue;
}
final Uint8List byteView = Uint8List.view(
codeBytes.buffer,
codeStart,
codeEnd - codeStart,
);
final String fileName =
filePath.startsWith('/') ? filePath.substring(1) : filePath;
webVirtualFS.files[fileName] = byteView;
/// Start a build daemon and register the web targets. final int sourcemapStart = sourcemapOffsets[0];
/// final int sourcemapEnd = sourcemapOffsets[1];
/// [initializePlatform] controls whether we should invoke [webOnlyInitializePlatform]. if (sourcemapStart < 0 || sourcemapEnd > sourcemapBytes.lengthInBytes) {
Future<BuildDaemonClient> startBuildDaemon(String workingDirectory, { globals.printTrace('Invalid byte index: [$sourcemapStart, $sourcemapEnd]');
bool release = false, continue;
bool profile = false, }
bool hasPlugins = false, final Uint8List sourcemapView = Uint8List.view(
bool initializePlatform = true, sourcemapBytes.buffer,
WebTestTargetManifest testTargets, sourcemapStart,
}) async { sourcemapEnd - sourcemapStart,
try {
final BuildDaemonClient client = await _connectClient(
workingDirectory,
release: release,
profile: profile,
hasPlugins: hasPlugins,
initializePlatform: initializePlatform,
testTargets: testTargets,
); );
_registerBuildTargets(client, testTargets); final String sourcemapName = '$fileName.map';
return client; webVirtualFS.sourcemaps[sourcemapName] = sourcemapView;
} on OptionsSkew {
throwToolExit( final int metadataStart = metadataOffsets[0];
'Incompatible options with current running build daemon.\n\n' final int metadataEnd = metadataOffsets[1];
'Please stop other flutter_tool instances running in this directory ' if (metadataStart < 0 || metadataEnd > metadataBytes.lengthInBytes) {
'before starting a new instance with these options.' globals
.printTrace('Invalid byte index: [$metadataStart, $metadataEnd]');
continue;
}
final Uint8List metadataView = Uint8List.view(
metadataBytes.buffer,
metadataStart,
metadataEnd - metadataStart,
); );
final String metadataName = '$fileName.metadata';
webVirtualFS.metadataFiles[metadataName] = metadataView;
} }
return null;
} }
void _registerBuildTargets( String _generateEntrypoint(String relativeTestPath, String absolutePath) {
BuildDaemonClient client, return '''
WebTestTargetManifest testTargets, // @dart = 2.8
) { import 'org-dartlang-app:///$relativeTestPath' as test;
final OutputLocation outputLocation = OutputLocation((OutputLocationBuilder b) => b import 'dart:ui' as ui;
..output = '' import 'dart:html';
..useSymlinks = true import 'dart:js';
..hoist = false); import 'package:stream_channel/stream_channel.dart';
client.registerBuildTarget(DefaultBuildTarget((DefaultBuildTargetBuilder b) => b import 'package:flutter_test/flutter_test.dart';
..target = 'web' import 'package:test_api/src/backend/stack_trace_formatter.dart'; // ignore: implementation_imports
..outputLocation = outputLocation?.toBuilder())); import 'package:test_api/src/remote_listener.dart'; // ignore: implementation_imports
if (testTargets != null) { import 'package:test_api/src/suite_channel_manager.dart'; // ignore: implementation_imports
client.registerBuildTarget(DefaultBuildTarget((DefaultBuildTargetBuilder b) {
b.target = 'test'; // Extra initialization for flutter_web.
b.outputLocation = outputLocation?.toBuilder(); // The following parameters are hard-coded in Flutter's test embedder. Since
if (testTargets.hasBuildFilters) { // we don't have an embedder yet this is the lowest-most layer we can put
b.buildFilters.addAll(testTargets.buildFilters); // this stuff in.
} Future<void> main() async {
})); ui.debugEmulateFlutterTesterEnvironment = true;
} await ui.webOnlyInitializePlatform();
webGoldenComparator = DefaultWebGoldenComparator(Uri.parse('$absolutePath'));
(ui.window as dynamic).debugOverrideDevicePixelRatio(3.0);
(ui.window as dynamic).webOnlyDebugPhysicalSizeOverride = const ui.Size(2400, 1800);
internalBootstrapBrowserTest(() => test.main);
} }
Future<BuildDaemonClient> _connectClient( void internalBootstrapBrowserTest(Function getMain()) {
String workingDirectory, { var channel = serializeSuite(getMain, hidePrints: false);
bool release, postMessageChannel().pipe(channel);
bool profile, }
bool hasPlugins,
bool initializePlatform,
WebTestTargetManifest testTargets,
}) async {
// The build script is stored in an auxiliary package to reduce
// dependencies of the main tool.
final String buildScriptPackages = globals.fs.path.join(
Cache.flutterRoot,
'packages',
'_flutter_web_build_script',
'.packages',
);
final String buildScript = globals.fs.path.join(
Cache.flutterRoot,
'packages',
'_flutter_web_build_script',
'lib',
'build_script.dart',
);
if (!globals.fs.isFileSync(buildScript)) {
throwToolExit('Expected a file $buildScript to exist in the Flutter SDK.');
}
// If we're missing the .packages file, perform a pub get.
if (!globals.fs.isFileSync(buildScriptPackages)) {
await pub.get(
context: PubContext.pubGet,
directory: globals.fs.file(buildScriptPackages).parent.path,
generateSyntheticPackage: false,
);
}
final String flutterWebSdk = globals.artifacts.getArtifactPath(Artifact.flutterWebSdk);
// On Windows we need to call the snapshot directly otherwise StreamChannel serializeSuite(Function getMain(), {bool hidePrints = true, Future beforeLoad()}) => RemoteListener.start(getMain, hidePrints: hidePrints, beforeLoad: beforeLoad);
// the process will start in a disjoint cmd without access to
// STDIO.
final List<String> args = <String>[
globals.artifacts.getArtifactPath(Artifact.engineDartBinary),
'--disable-dart-dev',
'--packages=$buildScriptPackages',
buildScript,
'daemon',
'--enable-experiment=non-nullable',
'--skip-build-script-check',
'--define', 'flutter_tools:ddc=flutterWebSdk=$flutterWebSdk',
// The following will cause build runner to only build tests that were requested.
if (testTargets != null && testTargets.hasBuildFilters)
for (final String buildFilter in testTargets.buildFilters)
'--build-filter=$buildFilter',
];
return BuildDaemonClient.connect( StreamChannel suiteChannel(String name) {
workingDirectory, var manager = SuiteChannelManager.current;
args, if (manager == null) {
logHandler: (ServerLog serverLog) { throw StateError('suiteChannel() may only be called within a test worker.');
switch (serverLog.level) { }
case Level.SEVERE: return manager.connectOut(name);
case Level.SHOUT: }
// Ignore certain non-actionable messages on startup.
if (serverLog.message.contains(_ignoredLine1) || StreamChannel postMessageChannel() {
serverLog.message.contains(_ignoredLine2) || var controller = StreamChannelController(sync: true);
serverLog.message.contains(_ignoredLine3)) { window.onMessage.firstWhere((message) {
return; return message.origin == window.location.origin && message.data == "port";
} }).then((message) {
globals.printError(serverLog.message); var port = message.ports.first;
if (serverLog.error != null) { var portSubscription = port.onMessage.listen((message) {
globals.printError(serverLog.error); controller.local.sink.add(message.data);
} });
if (serverLog.stackTrace != null) { controller.local.stream.listen((data) {
globals.printTrace(serverLog.stackTrace); port.postMessage({"data": data});
} }, onDone: () {
break; port.postMessage({"event": "done"});
default: portSubscription.cancel();
if (serverLog.message.contains('Skipping compiling')) { });
globals.printError(serverLog.message); });
} else { context['parent'].callMethod('postMessage', [
globals.printTrace(serverLog.message); JsObject.jsify({"href": window.location.href, "ready": true}),
} window.location.origin,
} ]);
}, return controller.foreign;
buildMode: daemon.BuildMode.Manual, }
); ''';
} }
} }
...@@ -15,7 +15,6 @@ import 'package:path/path.dart' as p; // ignore: package_path_import ...@@ -15,7 +15,6 @@ import 'package:path/path.dart' as p; // ignore: package_path_import
import 'package:pool/pool.dart'; import 'package:pool/pool.dart';
import 'package:shelf/shelf.dart' as shelf; import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as shelf_io; import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf_packages_handler/shelf_packages_handler.dart';
import 'package:shelf_static/shelf_static.dart'; import 'package:shelf_static/shelf_static.dart';
import 'package:shelf_web_socket/shelf_web_socket.dart'; import 'package:shelf_web_socket/shelf_web_socket.dart';
import 'package:stream_channel/stream_channel.dart'; import 'package:stream_channel/stream_channel.dart';
...@@ -34,6 +33,7 @@ import '../dart/package_map.dart'; ...@@ -34,6 +33,7 @@ import '../dart/package_map.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import '../project.dart'; import '../project.dart';
import '../web/chrome.dart'; import '../web/chrome.dart';
import '../web/compile.dart';
import 'test_compiler.dart'; import 'test_compiler.dart';
import 'test_config.dart'; import 'test_config.dart';
...@@ -42,23 +42,19 @@ class FlutterWebPlatform extends PlatformPlugin { ...@@ -42,23 +42,19 @@ class FlutterWebPlatform extends PlatformPlugin {
FlutterProject flutterProject, FlutterProject flutterProject,
String shellPath, String shellPath,
this.updateGoldens, this.updateGoldens,
@required BuildInfo buildInfo, @required this.buildInfo,
@required this.webVirtualFS,
}) { }) {
final shelf.Cascade cascade = shelf.Cascade() final shelf.Cascade cascade = shelf.Cascade()
.add(_webSocketHandler.handler) .add(_webSocketHandler.handler)
.add(packagesDirHandler())
.add(_jsHandler.handler)
.add(createStaticHandler( .add(createStaticHandler(
globals.fs.path.join(Cache.flutterRoot, 'packages', 'flutter_tools'), globals.fs.path.join(Cache.flutterRoot, 'packages', 'flutter_tools'),
serveFilesOutsidePath: true, serveFilesOutsidePath: true,
)) ))
.add(createStaticHandler(
_config.suiteDefaults.precompiledPath,
serveFilesOutsidePath: true,
))
.add(_handleStaticArtifact) .add(_handleStaticArtifact)
.add(_goldenFileHandler) .add(_goldenFileHandler)
.add(_wrapperHandler) .add(_wrapperHandler)
.add(_handleTestRequest)
.add(createStaticHandler( .add(createStaticHandler(
p.join(p.current, 'test'), p.join(p.current, 'test'),
serveFilesOutsidePath: true, serveFilesOutsidePath: true,
...@@ -72,15 +68,18 @@ class FlutterWebPlatform extends PlatformPlugin { ...@@ -72,15 +68,18 @@ class FlutterWebPlatform extends PlatformPlugin {
); );
} }
final WebVirtualFS webVirtualFS;
final BuildInfo buildInfo;
static Future<FlutterWebPlatform> start(String root, { static Future<FlutterWebPlatform> start(String root, {
FlutterProject flutterProject, FlutterProject flutterProject,
String shellPath, String shellPath,
bool updateGoldens = false, bool updateGoldens = false,
bool pauseAfterLoad = false, bool pauseAfterLoad = false,
@required BuildInfo buildInfo, @required BuildInfo buildInfo,
@required WebVirtualFS webVirtualFS,
}) async { }) async {
final shelf_io.IOServer server = final shelf_io.IOServer server = shelf_io.IOServer(await HttpMultiServer.loopback(0));
shelf_io.IOServer(await HttpMultiServer.loopback(0));
return FlutterWebPlatform._( return FlutterWebPlatform._(
server, server,
Configuration.current.change(pauseAfterLoad: pauseAfterLoad), Configuration.current.change(pauseAfterLoad: pauseAfterLoad),
...@@ -89,14 +88,10 @@ class FlutterWebPlatform extends PlatformPlugin { ...@@ -89,14 +88,10 @@ class FlutterWebPlatform extends PlatformPlugin {
shellPath: shellPath, shellPath: shellPath,
updateGoldens: updateGoldens, updateGoldens: updateGoldens,
buildInfo: buildInfo, buildInfo: buildInfo,
webVirtualFS: webVirtualFS,
); );
} }
final Future<PackageConfig> _packagesFuture = loadPackageConfigWithLogging(
globals.fs.file(globals.fs.path.join('.dart_tool', 'package_config.json')),
logger: globals.logger,
);
final Future<PackageConfig> _flutterToolsPackageMap = loadPackageConfigWithLogging( final Future<PackageConfig> _flutterToolsPackageMap = loadPackageConfigWithLogging(
globals.fs.file(globals.fs.path.join( globals.fs.file(globals.fs.path.join(
Cache.flutterRoot, Cache.flutterRoot,
...@@ -176,6 +171,35 @@ class FlutterWebPlatform extends PlatformPlugin { ...@@ -176,6 +171,35 @@ class FlutterWebPlatform extends PlatformPlugin {
'host.dart.js', 'host.dart.js',
)); ));
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];
final String generatedFile = globals.fs.path.split(leadingPath).join('_') + '.bootstrap.js';
return shelf.Response.ok(bootstrapFileContents('/' + generatedFile, 'require.js', 'dart_stack_trace_mapper.js'), headers: <String, String>{
HttpHeaders.contentTypeHeader: 'text/javascript',
});
}
if (request.url.path.endsWith('.dart.bootstrap.js')) {
final String leadingPath = request.url.path.split('.dart.bootstrap.js')[0];
final String generatedFile = globals.fs.path.split(leadingPath).join('_') + '.dart.test.dart.js';
return shelf.Response.ok(generatedActualMain(globals.fs.path.basename(leadingPath) + '.dart.bootstrap', '/' + generatedFile), headers: <String, String>{
HttpHeaders.contentTypeHeader: 'text/javascript',
});
}
if (request.url.path.endsWith('.dart.js')) {
final String path = request.url.path.split('.dart.js')[0];
return shelf.Response.ok(webVirtualFS.files[path + '.dart.lib.js'], headers: <String, String>{
HttpHeaders.contentTypeHeader: 'text/javascript',
});
}
if (request.url.path.endsWith('.lib.js.map')) {
return shelf.Response.ok(webVirtualFS.sourcemaps[request.url.path], headers: <String, String>{
HttpHeaders.contentTypeHeader: 'text/plain',
});
}
return shelf.Response.notFound('');
}
Future<shelf.Response> _handleStaticArtifact(shelf.Request request) async { Future<shelf.Response> _handleStaticArtifact(shelf.Request request) async {
if (request.requestedUri.path.contains('require.js')) { if (request.requestedUri.path.contains('require.js')) {
return shelf.Response.ok( return shelf.Response.ok(
...@@ -190,7 +214,7 @@ class FlutterWebPlatform extends PlatformPlugin { ...@@ -190,7 +214,7 @@ class FlutterWebPlatform extends PlatformPlugin {
headers: <String, String>{'Content-Type': 'text/javascript'}, headers: <String, String>{'Content-Type': 'text/javascript'},
); );
} else if (request.requestedUri.path } else if (request.requestedUri.path
.contains('stack_trace_mapper.dart.js')) { .contains('dart_stack_trace_mapper.js')) {
return shelf.Response.ok( return shelf.Response.ok(
stackTraceMapper.openRead(), stackTraceMapper.openRead(),
headers: <String, String>{'Content-Type': 'text/javascript'}, headers: <String, String>{'Content-Type': 'text/javascript'},
...@@ -212,8 +236,7 @@ class FlutterWebPlatform extends PlatformPlugin { ...@@ -212,8 +236,7 @@ class FlutterWebPlatform extends PlatformPlugin {
FutureOr<shelf.Response> _packageFilesHandler(shelf.Request request) async { FutureOr<shelf.Response> _packageFilesHandler(shelf.Request request) async {
if (request.requestedUri.pathSegments.first == 'packages') { if (request.requestedUri.pathSegments.first == 'packages') {
final PackageConfig packageConfig = await _packagesFuture; final Uri fileUri = buildInfo.packageConfig.resolve(Uri(
final Uri fileUri = packageConfig.resolve(Uri(
scheme: 'package', scheme: 'package',
pathSegments: request.requestedUri.pathSegments.skip(1), pathSegments: request.requestedUri.pathSegments.skip(1),
)); ));
...@@ -289,7 +312,6 @@ class FlutterWebPlatform extends PlatformPlugin { ...@@ -289,7 +312,6 @@ class FlutterWebPlatform extends PlatformPlugin {
} }
final OneOffHandler _webSocketHandler = OneOffHandler(); final OneOffHandler _webSocketHandler = OneOffHandler();
final PathHandler _jsHandler = PathHandler();
final AsyncMemoizer<void> _closeMemo = AsyncMemoizer<void>(); final AsyncMemoizer<void> _closeMemo = AsyncMemoizer<void>();
final String _root; final String _root;
...@@ -315,7 +337,6 @@ class FlutterWebPlatform extends PlatformPlugin { ...@@ -315,7 +337,6 @@ class FlutterWebPlatform extends PlatformPlugin {
</html> </html>
''', headers: <String, String>{'Content-Type': 'text/html'}); ''', headers: <String, String>{'Content-Type': 'text/html'});
} }
globals.printTrace('Did not find anything for request: ${request.url}');
return shelf.Response.notFound('Not found.'); return shelf.Response.notFound('Not found.');
} }
...@@ -351,7 +372,8 @@ class FlutterWebPlatform extends PlatformPlugin { ...@@ -351,7 +372,8 @@ class FlutterWebPlatform extends PlatformPlugin {
final Uri suiteUrl = url.resolveUri(globals.fs.path.toUri(globals.fs.path.withoutExtension( final Uri suiteUrl = url.resolveUri(globals.fs.path.toUri(globals.fs.path.withoutExtension(
globals.fs.path.relative(path, from: globals.fs.path.join(_root, 'test'))) + globals.fs.path.relative(path, from: globals.fs.path.join(_root, 'test'))) +
'.html')); '.html'));
final RunnerSuite suite = await _browserManager.load(path, suiteUrl, suiteConfig, message, onDone: () async { final String relativePath = globals.fs.path.relative(globals.fs.path.normalize(path), from: globals.fs.currentDirectory.path);
final RunnerSuite suite = await _browserManager.load(relativePath, suiteUrl, suiteConfig, message, onDone: () async {
await _browserManager.close(); await _browserManager.close();
_browserManager = null; _browserManager = null;
lockResource.release(); lockResource.release();
...@@ -374,10 +396,8 @@ class FlutterWebPlatform extends PlatformPlugin { ...@@ -374,10 +396,8 @@ class FlutterWebPlatform extends PlatformPlugin {
throw StateError('Another browser is currently running.'); throw StateError('Another browser is currently running.');
} }
final Completer<WebSocketChannel> completer = final Completer<WebSocketChannel> completer = Completer<WebSocketChannel>.sync();
Completer<WebSocketChannel>.sync(); final String path = _webSocketHandler.create(webSocketHandler(completer.complete));
final String path =
_webSocketHandler.create(webSocketHandler(completer.complete));
final Uri webSocketUrl = url.replace(scheme: 'ws').resolve(path); final Uri webSocketUrl = url.replace(scheme: 'ws').resolve(path);
final Uri hostUrl = url final Uri hostUrl = url
.resolve('static/index.html') .resolve('static/index.html')
...@@ -453,66 +473,6 @@ class OneOffHandler { ...@@ -453,66 +473,6 @@ class OneOffHandler {
} }
} }
class PathHandler {
/// A trie of path components to handlers.
final _Node _paths = _Node();
/// The shelf handler.
shelf.Handler get handler => _onRequest;
/// Returns middleware that nests all requests beneath the URL prefix
/// [beneath].
static shelf.Middleware nestedIn(String beneath) {
return (FutureOr<shelf.Response> Function(shelf.Request) handler) {
final PathHandler pathHandler = PathHandler()..add(beneath, handler);
return pathHandler.handler;
};
}
/// Routes requests at or under [path] to [handler].
///
/// If [path] is a parent or child directory of another path in this handler,
/// the longest matching prefix wins.
void add(String path, shelf.Handler handler) {
_Node node = _paths;
for (final String component in p.url.split(path)) {
node = node.children.putIfAbsent(component, () => _Node());
}
node.handler = handler;
}
FutureOr<shelf.Response> _onRequest(shelf.Request request) {
shelf.Handler handler;
int handlerIndex;
_Node node = _paths;
final List<String> components = p.url.split(request.url.path);
for (int i = 0; i < components.length; i++) {
node = node.children[components[i]];
if (node == null) {
break;
}
if (node.handler == null) {
continue;
}
handler = node.handler;
handlerIndex = i;
}
if (handler == null) {
return shelf.Response.notFound('Not found.');
}
return handler(
request.change(path: p.url.joinAll(components.take(handlerIndex + 1))));
}
}
/// A trie node.
class _Node {
shelf.Handler handler;
final Map<String, _Node> children = <String, _Node>{};
}
class BrowserManager { class BrowserManager {
/// Creates a new BrowserManager that communicates with [browser] over /// Creates a new BrowserManager that communicates with [browser] over
/// [webSocket]. /// [webSocket].
...@@ -992,3 +952,68 @@ void main() async { ...@@ -992,3 +952,68 @@ void main() async {
'''; ''';
} }
} }
String bootstrapFileContents(String mainUri, String requireUrl, String mapperUrl) {
return '''
(function() {
if (typeof document != 'undefined') {
var el = document.createElement("script");
el.defer = true;
el.async = false;
el.src = '$mapperUrl';
document.head.appendChild(el);
el = document.createElement("script");
el.defer = true;
el.async = false;
el.src = '$requireUrl';
el.setAttribute("data-main", '$mainUri');
document.head.appendChild(el);
} else {
importScripts('$mapperUrl', '$requireUrl');
require.config({
baseUrl: baseUrl,
});
window = self;
require(['$mainUri']);
}
})();
''';
}
String generatedActualMain(String bootstrapUrl, String mainUri) {
return '''
/* ENTRYPOINT_EXTENTION_MARKER */
// Create the main module loaded below.
define("$bootstrapUrl", ["$mainUri", "dart_sdk"], function(app, dart_sdk) {
dart_sdk.dart.setStartAsyncSynchronously(true);
dart_sdk._debugger.registerDevtoolsFormatter();
if (false) {
dart_sdk.dart.nonNullAsserts(true);
}
// See the generateMainModule doc comment.
var child = {};
child.main = app[Object.keys(app)[0]].main;
/* MAIN_EXTENSION_MARKER */
child.main();
window.\$dartLoader = {};
window.\$dartLoader.rootDirectories = [];
if (window.\$requireLoader) {
window.\$requireLoader.getModuleLibraries = dart_sdk.dart.getModuleLibraries;
}
if (window.\$dartStackTraceUtility && !window.\$dartStackTraceUtility.ready) {
window.\$dartStackTraceUtility.ready = true;
let dart = dart_sdk.dart;
window.\$dartStackTraceUtility.setSourceMapProvider(function(url) {
var baseUrl = window.location.protocol + '//' + window.location.host;
url = url.replace(baseUrl + '/', '');
if (url == 'dart_sdk.js') {
return dart.getSourceMap('dart_sdk');
}
url = url.replace(".lib.js", "");
return dart.getSourceMap(url);
});
}
});
''';
}
...@@ -121,14 +121,13 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner { ...@@ -121,14 +121,13 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
.absolute .absolute
.uri .uri
.toFilePath(); .toFilePath();
final bool result = await webCompilationProxy.initialize( final WebVirtualFS result = await webCompilationProxy.initialize(
projectDirectory: flutterProject.directory, projectDirectory: flutterProject.directory,
testOutputDir: tempBuildDir, testOutputDir: tempBuildDir,
testFiles: testFiles, testFiles: testFiles,
projectName: flutterProject.manifest.appName, buildInfo: buildInfo,
initializePlatform: true,
); );
if (!result) { if (result == null) {
throwToolExit('Failed to compile tests'); throwToolExit('Failed to compile tests');
} }
testArgs testArgs
...@@ -146,6 +145,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner { ...@@ -146,6 +145,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
flutterProject: flutterProject, flutterProject: flutterProject,
pauseAfterLoad: startPaused, pauseAfterLoad: startPaused,
buildInfo: buildInfo, buildInfo: buildInfo,
webVirtualFS: result,
); );
}, },
); );
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:typed_data';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import '../base/common.dart'; import '../base/common.dart';
...@@ -96,19 +98,19 @@ class WebCompilationProxy { ...@@ -96,19 +98,19 @@ class WebCompilationProxy {
const WebCompilationProxy(); const WebCompilationProxy();
/// Initialize the web compiler from the `projectDirectory`. /// Initialize the web compiler from the `projectDirectory`.
/// Future<WebVirtualFS> initialize({
/// Returns whether or not the build was successful.
///
/// `release` controls whether we build the bundle for dartdevc or only
/// the entry points for dart2js to later take over.
Future<bool> initialize({
@required Directory projectDirectory, @required Directory projectDirectory,
@required String projectName, @required String testOutputDir,
String testOutputDir, @required List<String> testFiles,
List<String> testFiles, @required BuildInfo buildInfo,
BuildMode mode,
bool initializePlatform,
}) async { }) async {
throw UnimplementedError(); throw UnimplementedError();
} }
} }
class WebVirtualFS {
final Map<String, Uint8List> metadataFiles = <String, Uint8List>{};
final Map<String, Uint8List> files = <String, Uint8List>{};
final Map<String, Uint8List> sourcemaps = <String, Uint8List>{};
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment