Plumbing flags required for running tests with the DDC module system. (#2295)
* Updating the legacy loader to use the new DDC module loader API
* Adding tests and plumbing for the DDC module system.
* updating changelog
* Restructuring asset bundling and flags
* Restructuring asset bundling and flags
* Updating test sdk paths
* Moving the module format specifier to an enum and unioning static assets across module formats
* Fixing analysis errors
* Exposing utilities/ddc_names.dart
* removing extraneous export
* Fixing race condition without extraneous plumbing.
* Extending tests and restructuring logic into helpers
* Extending sdk config tests and moving autorun functionality into the test context.
* Fixing analysis errors
* adding missing DDC sound sdks to asset generator test
* Fixing ddc and amd paths
* Keeping the first instance of an app connection and extending timeouts
* formatting files
* Exposing utilities/ddc_names.dart
* Loosen `vm_service` constraints and prepare DWDS for release to 23.1.1 (#2329)
* Reset DWDS to version `23.2.0-wip` after release (#2334)
* Adding changelog
---------
Co-authored-by: Elliott Brooks <21270878+elliette@users.noreply.github.com>
diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md
index bedef0c..f0922af 100644
--- a/dwds/CHANGELOG.md
+++ b/dwds/CHANGELOG.md
@@ -1,6 +1,7 @@
## 23.2.0-wip
- Send untruncated `dart:developer` logs to debugging clients. - [#2333](https://github.com/dart-lang/webdev/pull/2333)
+- Enabling tests that run with the DDC module system and exposing `utilities/ddc_names.dart` - [#2295](https://github.com/dart-lang/webdev/pull/2295)
## 23.1.1
diff --git a/dwds/lib/dwds.dart b/dwds/lib/dwds.dart
index a901639..d0898d7 100644
--- a/dwds/lib/dwds.dart
+++ b/dwds/lib/dwds.dart
@@ -41,5 +41,6 @@
CompilerOptions;
export 'src/services/expression_compiler_service.dart'
show ExpressionCompilerService;
+export 'src/utilities/ddc_names.dart';
export 'src/utilities/sdk_configuration.dart'
show SdkLayout, SdkConfiguration, SdkConfigurationProvider;
diff --git a/dwds/lib/expression_compiler.dart b/dwds/lib/expression_compiler.dart
index 19283a7..6748414 100644
--- a/dwds/lib/expression_compiler.dart
+++ b/dwds/lib/expression_compiler.dart
@@ -7,4 +7,5 @@
ExpressionCompilationResult,
ExpressionCompiler,
CompilerOptions,
+ ModuleFormat,
ModuleInfo;
diff --git a/dwds/lib/src/loaders/legacy.dart b/dwds/lib/src/loaders/legacy.dart
index bfaa503..fb35c09 100644
--- a/dwds/lib/src/loaders/legacy.dart
+++ b/dwds/lib/src/loaders/legacy.dart
@@ -181,7 +181,11 @@
return '''
$_baseUrlScript
var scripts = ${const JsonEncoder.withIndent(" ").convert(scripts)};
-window.\$dartLoader.loadScripts(scripts);
+window.\$dartLoader.loadConfig.loadScriptFn = function(loader) {
+ loader.addScriptsToQueue(scripts, null);
+ loader.loadEnqueuedModules();
+};
+window.\$dartLoader.loader.nextAttempt();
''';
}
diff --git a/dwds/lib/src/services/chrome_proxy_service.dart b/dwds/lib/src/services/chrome_proxy_service.dart
index 3f9f458..9a6051c 100644
--- a/dwds/lib/src/services/chrome_proxy_service.dart
+++ b/dwds/lib/src/services/chrome_proxy_service.dart
@@ -187,7 +187,7 @@
'with sound null safety: $soundNullSafety');
final compilerOptions = CompilerOptions(
- moduleFormat: moduleFormat,
+ moduleFormat: ModuleFormat.values.byName(moduleFormat),
soundNullSafety: soundNullSafety,
canaryFeatures: canaryFeatures,
experiments: experiments,
diff --git a/dwds/lib/src/services/expression_compiler.dart b/dwds/lib/src/services/expression_compiler.dart
index 6135a70..c1b7306 100644
--- a/dwds/lib/src/services/expression_compiler.dart
+++ b/dwds/lib/src/services/expression_compiler.dart
@@ -4,7 +4,7 @@
/// Options passed to DDC and the expression compiler.
class CompilerOptions {
- final String moduleFormat;
+ final ModuleFormat moduleFormat;
final bool soundNullSafety;
final bool canaryFeatures;
final List<String> experiments;
@@ -17,6 +17,9 @@
});
}
+/// Indicates the module system DDC is targeting.
+enum ModuleFormat { amd, ddc, es6 }
+
/// Result of compilation of dart expression to JavaScript
class ExpressionCompilationResult {
final bool isError;
diff --git a/dwds/lib/src/services/expression_compiler_service.dart b/dwds/lib/src/services/expression_compiler_service.dart
index 36a51f4..4865cb1 100644
--- a/dwds/lib/src/services/expression_compiler_service.dart
+++ b/dwds/lib/src/services/expression_compiler_service.dart
@@ -89,7 +89,7 @@
'--asset-server-port',
'$port',
'--module-format',
- compilerOptions.moduleFormat,
+ compilerOptions.moduleFormat.name,
if (verbose) '--verbose',
compilerOptions.soundNullSafety
? '--sound-null-safety'
diff --git a/dwds/lib/utilities.dart b/dwds/lib/utilities.dart
new file mode 100644
index 0000000..02e84d8
--- /dev/null
+++ b/dwds/lib/utilities.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export 'src/utilities/ddc_names.dart';
diff --git a/dwds/test/devtools_test.dart b/dwds/test/devtools_test.dart
index b7e1ddf..8e9fb48 100644
--- a/dwds/test/devtools_test.dart
+++ b/dwds/test/devtools_test.dart
@@ -32,110 +32,115 @@
final context = TestContext(TestProject.testWithSoundNullSafety, provider);
- group('Injected client', () {
- setUp(() async {
- await context.setUp(
- debugSettings: TestDebugSettings.withDevTools(context),
+ group(
+ 'Injected client',
+ () {
+ setUp(() async {
+ await context.setUp(
+ debugSettings: TestDebugSettings.withDevTools(context),
+ );
+ await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']);
+ // Wait for DevTools to actually open.
+ await Future.delayed(const Duration(seconds: 2));
+ });
+
+ tearDown(() async {
+ await context.tearDown();
+ });
+
+ test(
+ 'can launch devtools',
+ () async {
+ final windows = await context.webDriver.windows.toList();
+ await context.webDriver.driver.switchTo.window(windows.last);
+ expect(await context.webDriver.pageSource, contains('DevTools'));
+ expect(await context.webDriver.currentUrl, contains('ide=Dwds'));
+ // TODO(https://github.com/dart-lang/webdev/issues/1888): Re-enable.
+ },
+ skip: Platform.isWindows,
);
- await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']);
- // Wait for DevTools to actually open.
- await Future.delayed(const Duration(seconds: 2));
- });
- tearDown(() async {
- await context.tearDown();
- });
+ test('can not launch devtools for the same app in multiple tabs',
+ () async {
+ final appUrl = await context.webDriver.currentUrl;
+ // Open a new tab, select it, and navigate to the app
+ await context.webDriver.driver
+ .execute("window.open('$appUrl', '_blank');", []);
+ await Future.delayed(const Duration(seconds: 2));
+ final newAppWindow = await context.webDriver.windows.last;
+ await newAppWindow.setAsActive();
- test(
- 'can launch devtools',
- () async {
- final windows = await context.webDriver.windows.toList();
- await context.webDriver.driver.switchTo.window(windows.last);
- expect(await context.webDriver.pageSource, contains('DevTools'));
- expect(await context.webDriver.currentUrl, contains('ide=Dwds'));
- // TODO(https://github.com/dart-lang/webdev/issues/1888): Re-enable.
- },
- skip: Platform.isWindows,
- );
+ // Wait for the page to be ready before trying to open DevTools again.
+ await _waitForPageReady(context);
- test('can not launch devtools for the same app in multiple tabs', () async {
- final appUrl = await context.webDriver.currentUrl;
- // Open a new tab, select it, and navigate to the app
- await context.webDriver.driver
- .execute("window.open('$appUrl', '_blank');", []);
- await Future.delayed(const Duration(seconds: 2));
- final newAppWindow = await context.webDriver.windows.last;
- await newAppWindow.setAsActive();
+ // Try to open devtools and check for the alert.
+ await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']);
+ await Future.delayed(const Duration(seconds: 2));
+ final alert = context.webDriver.driver.switchTo.alert;
+ expect(alert, isNotNull);
+ expect(
+ await alert.text,
+ contains('This app is already being debugged in a different tab'),
+ );
+ await alert.accept();
- // Wait for the page to be ready before trying to open DevTools again.
- await _waitForPageReady(context);
-
- // Try to open devtools and check for the alert.
- await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']);
- await Future.delayed(const Duration(seconds: 2));
- final alert = context.webDriver.driver.switchTo.alert;
- expect(alert, isNotNull);
- expect(
- await alert.text,
- contains('This app is already being debugged in a different tab'),
- );
- await alert.accept();
-
- var windows = await context.webDriver.windows.toList();
- for (final window in windows) {
- if (window.id != newAppWindow.id) {
- await window.setAsActive();
- await window.close();
+ var windows = await context.webDriver.windows.toList();
+ for (final window in windows) {
+ if (window.id != newAppWindow.id) {
+ await window.setAsActive();
+ await window.close();
+ }
}
- }
- await newAppWindow.setAsActive();
- await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']);
- await Future.delayed(const Duration(seconds: 2));
- windows = await context.webDriver.windows.toList();
- final devToolsWindow =
- windows.firstWhere((window) => window != newAppWindow);
- await devToolsWindow.setAsActive();
- expect(await context.webDriver.pageSource, contains('DevTools'));
- });
+ await newAppWindow.setAsActive();
+ await context.webDriver.driver.keyboard.sendChord([Keyboard.alt, 'd']);
+ await Future.delayed(const Duration(seconds: 2));
+ windows = await context.webDriver.windows.toList();
+ final devToolsWindow =
+ windows.firstWhere((window) => window != newAppWindow);
+ await devToolsWindow.setAsActive();
+ expect(await context.webDriver.pageSource, contains('DevTools'));
+ });
- test(
- 'destroys and recreates the isolate during a page refresh',
- () async {
- // This test is the same as one in reload_test, but runs here when there
- // is a connected client (DevTools) since it can behave differently.
- // https://github.com/dart-lang/webdev/pull/901#issuecomment-586438132
- final client = context.debugConnection.vmService;
- await client.streamListen('Isolate');
- context.makeEditToDartEntryFile(
- toReplace: 'Hello World!',
- replaceWith: 'Bonjour le monde!',
- );
- await context.waitForSuccessfulBuild(propagateToBrowser: true);
+ test(
+ 'destroys and recreates the isolate during a page refresh',
+ () async {
+ // This test is the same as one in reload_test, but runs here when there
+ // is a connected client (DevTools) since it can behave differently.
+ // https://github.com/dart-lang/webdev/pull/901#issuecomment-586438132
+ final client = context.debugConnection.vmService;
+ await client.streamListen('Isolate');
+ context.makeEditToDartEntryFile(
+ toReplace: 'Hello World!',
+ replaceWith: 'Bonjour le monde!',
+ );
+ await context.waitForSuccessfulBuild(propagateToBrowser: true);
- final eventsDone = expectLater(
- client.onIsolateEvent,
- emitsThrough(
- emitsInOrder([
- _hasKind(EventKind.kIsolateExit),
- _hasKind(EventKind.kIsolateStart),
- _hasKind(EventKind.kIsolateRunnable),
- ]),
- ),
- );
+ final eventsDone = expectLater(
+ client.onIsolateEvent,
+ emitsThrough(
+ emitsInOrder([
+ _hasKind(EventKind.kIsolateExit),
+ _hasKind(EventKind.kIsolateStart),
+ _hasKind(EventKind.kIsolateRunnable),
+ ]),
+ ),
+ );
- await context.webDriver.driver.refresh();
+ await context.webDriver.driver.refresh();
- await eventsDone;
- // Re-set the edited file:
- context.makeEditToDartEntryFile(
- toReplace: 'Bonjour le monde!',
- replaceWith: 'Hello World!',
- );
- },
- skip: 'https://github.com/dart-lang/webdev/issues/1888',
- );
- });
+ await eventsDone;
+ // Re-set the edited file:
+ context.makeEditToDartEntryFile(
+ toReplace: 'Bonjour le monde!',
+ replaceWith: 'Hello World!',
+ );
+ },
+ skip: 'https://github.com/dart-lang/webdev/issues/1888',
+ );
+ },
+ timeout: Timeout.factor(2),
+ );
group('Injected client without a DevTools server', () {
setUp(() async {
@@ -193,6 +198,7 @@
},
tags: ['extension'],
skip: 'https://github.com/dart-lang/webdev/issues/2114',
+ timeout: Timeout.factor(2),
);
}
diff --git a/dwds/test/evaluate_common.dart b/dwds/test/evaluate_common.dart
index 61025b5..7c3c9c9 100644
--- a/dwds/test/evaluate_common.dart
+++ b/dwds/test/evaluate_common.dart
@@ -71,6 +71,7 @@
await context.setUp(
testSettings: TestSettings(
compilationMode: compilationMode,
+ moduleFormat: provider.ddcModuleFormat,
enableExpressionEvaluation: true,
useDebuggerModuleNames: useDebuggerModuleNames,
verboseCompiler: debug,
@@ -821,6 +822,7 @@
await context.setUp(
testSettings: TestSettings(
compilationMode: compilationMode,
+ moduleFormat: provider.ddcModuleFormat,
enableExpressionEvaluation: false,
verboseCompiler: debug,
),
diff --git a/dwds/test/expression_compiler_service_test.dart b/dwds/test/expression_compiler_service_test.dart
index d791aeb..0531764 100644
--- a/dwds/test/expression_compiler_service_test.dart
+++ b/dwds/test/expression_compiler_service_test.dart
@@ -80,7 +80,7 @@
);
final compilerOptions = CompilerOptions(
- moduleFormat: 'amd',
+ moduleFormat: ModuleFormat.amd,
soundNullSafety: true,
canaryFeatures: false,
experiments: const <String>[],
diff --git a/dwds/test/fixtures/context.dart b/dwds/test/fixtures/context.dart
index 3842aa0..34a45e7 100644
--- a/dwds/test/fixtures/context.dart
+++ b/dwds/test/fixtures/context.dart
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'dart:async';
import 'dart:convert';
import 'dart:io';
@@ -9,15 +10,16 @@
import 'package:build_daemon/data/build_status.dart';
import 'package:build_daemon/data/build_target.dart';
import 'package:dwds/asset_reader.dart';
-import 'package:dwds/expression_compiler.dart';
import 'package:dwds/src/connections/app_connection.dart';
import 'package:dwds/src/connections/debug_connection.dart';
import 'package:dwds/src/debugging/webkit_debugger.dart';
import 'package:dwds/src/loaders/build_runner_require.dart';
+import 'package:dwds/src/loaders/frontend_server_legacy.dart';
import 'package:dwds/src/loaders/frontend_server_require.dart';
-import 'package:dwds/src/loaders/require.dart';
+import 'package:dwds/src/loaders/strategy.dart';
import 'package:dwds/src/readers/proxy_server_asset_reader.dart';
import 'package:dwds/src/services/chrome_proxy_service.dart';
+import 'package:dwds/src/services/expression_compiler.dart';
import 'package:dwds/src/services/expression_compiler_service.dart';
import 'package:dwds/src/utilities/dart_uri.dart';
import 'package:dwds/src/utilities/server.dart';
@@ -204,7 +206,7 @@
ExpressionCompiler? expressionCompiler;
AssetReader assetReader;
Stream<BuildResults> buildResults;
- RequireStrategy requireStrategy;
+ LoadStrategy loadStrategy;
String basePath = '';
String filePathToServe = project.filePathToServe;
@@ -268,7 +270,7 @@
expressionCompiler = ddcService;
}
- requireStrategy = BuildRunnerRequireStrategyProvider(
+ loadStrategy = BuildRunnerRequireStrategyProvider(
assetHandler,
testSettings.reloadConfiguration,
assetReader,
@@ -301,6 +303,7 @@
nullSafety: project.nullSafety,
experiments: buildSettings.experiments,
canaryFeatures: buildSettings.canaryFeatures,
+ moduleFormat: testSettings.moduleFormat,
);
_webRunner = ResidentWebRunner(
@@ -332,14 +335,25 @@
basePath = webRunner.devFS.assetServer.basePath;
assetReader = webRunner.devFS.assetServer;
_assetHandler = webRunner.devFS.assetServer.handleRequest;
- requireStrategy = FrontendServerRequireStrategyProvider(
- testSettings.reloadConfiguration,
- assetReader,
- packageUriMapper,
- () async => {},
- buildSettings,
- ).strategy;
-
+ loadStrategy = switch (testSettings.moduleFormat) {
+ ModuleFormat.amd => FrontendServerRequireStrategyProvider(
+ testSettings.reloadConfiguration,
+ assetReader,
+ packageUriMapper,
+ () async => {},
+ buildSettings,
+ ).strategy,
+ ModuleFormat.ddc => FrontendServerLegacyStrategyProvider(
+ testSettings.reloadConfiguration,
+ assetReader,
+ packageUriMapper,
+ () async => {},
+ buildSettings,
+ ).strategy,
+ _ => throw Exception(
+ 'Unsupported DDC module format ${testSettings.moduleFormat.name}.',
+ )
+ };
buildResults = const Stream<BuildResults>.empty();
}
break;
@@ -380,6 +394,11 @@
),
);
}
+
+ // The debugger tab must be enabled and connected before certain
+ // listeners in DWDS or `main` is run.
+ final tabConnectionCompleter = Completer();
+ final appConnectionCompleter = Completer();
final connection = ChromeConnection('localhost', debugPort);
_testServer = await TestServer.start(
@@ -389,13 +408,27 @@
port: port,
assetHandler: assetHandler,
assetReader: assetReader,
- strategy: requireStrategy,
+ strategy: loadStrategy,
target: project.directoryToServe,
buildResults: buildResults,
chromeConnection: () async => connection,
- autoRun: testSettings.autoRun,
);
+ _testServer!.dwds.connectedApps.listen((connection) async {
+ // Ensure that we've established a tab connection before running main.
+ await tabConnectionCompleter.future;
+ if (testSettings.autoRun) {
+ connection.runMain();
+ }
+
+ // We may reuse the app connection, so only save it the first time
+ // it's encountered.
+ if (!appConnectionCompleter.isCompleted) {
+ appConnection = connection;
+ appConnectionCompleter.complete();
+ }
+ });
+
_appUrl = basePath.isEmpty
? 'http://localhost:$port/$filePathToServe'
: 'http://localhost:$port/$basePath/$filePathToServe';
@@ -406,7 +439,9 @@
if (tab != null) {
_tabConnection = await tab.connect();
await tabConnection.runtime.enable();
- await tabConnection.debugger.enable();
+ await tabConnection.debugger
+ .enable()
+ .then((_) => tabConnectionCompleter.complete());
} else {
throw StateError('Unable to connect to tab.');
}
@@ -417,10 +452,13 @@
await extensionConnection.runtime.enable();
}
- appConnection = await testServer.dwds.connectedApps.first;
+ await appConnectionCompleter.future;
if (debugSettings.enableDebugging && !testSettings.waitToDebug) {
await startDebugging();
}
+ } else {
+ // No tab needs to be dicovered, so fulfill the relevant completer.
+ tabConnectionCompleter.complete();
}
} catch (e, s) {
_logger.severe('Failed to setup the service, $e:$s');
diff --git a/dwds/test/fixtures/server.dart b/dwds/test/fixtures/server.dart
index 88562e7..9de66c3 100644
--- a/dwds/test/fixtures/server.dart
+++ b/dwds/test/fixtures/server.dart
@@ -9,7 +9,7 @@
import 'package:dwds/dart_web_debug_service.dart';
import 'package:dwds/data/build_result.dart';
import 'package:dwds/src/config/tool_configuration.dart';
-import 'package:dwds/src/loaders/require.dart';
+import 'package:dwds/src/loaders/strategy.dart';
import 'package:dwds/src/utilities/server.dart';
import 'package:logging/logging.dart';
import 'package:shelf/shelf.dart';
@@ -39,15 +39,8 @@
this._server,
this.dwds,
this.buildResults,
- bool autoRun,
this.assetReader,
- ) {
- if (autoRun) {
- dwds.connectedApps.listen((connection) {
- connection.runMain();
- });
- }
- }
+ );
String get host => _server.address.host;
int get port => _server.port;
@@ -62,11 +55,10 @@
required AppMetadata appMetadata,
required Handler assetHandler,
required AssetReader assetReader,
- required RequireStrategy strategy,
+ required LoadStrategy strategy,
required String target,
required Stream<daemon.BuildResults> buildResults,
required Future<ChromeConnection> Function() chromeConnection,
- required bool autoRun,
int? port,
}) async {
var pipeline = const Pipeline();
@@ -121,7 +113,6 @@
server,
dwds,
filteredBuildResults,
- autoRun,
assetReader,
);
}
diff --git a/dwds/test/fixtures/utilities.dart b/dwds/test/fixtures/utilities.dart
index 5c722e0..45c508a 100644
--- a/dwds/test/fixtures/utilities.dart
+++ b/dwds/test/fixtures/utilities.dart
@@ -242,6 +242,7 @@
// Build settings.
final CompilationMode compilationMode;
+ final ModuleFormat moduleFormat;
final bool canaryFeatures;
final bool isFlutterApp;
final List<String> experiments;
@@ -255,6 +256,7 @@
this.verboseCompiler = false,
this.launchChrome = true,
this.compilationMode = CompilationMode.buildDaemon,
+ this.moduleFormat = ModuleFormat.amd,
this.canaryFeatures = false,
this.isFlutterApp = false,
this.experiments = const <String>[],
@@ -296,8 +298,8 @@
required NullSafety nullSafety,
required super.canaryFeatures,
required List<String> experiments,
+ super.moduleFormat = ModuleFormat.amd,
}) : super(
- moduleFormat: 'amd',
soundNullSafety: nullSafety == NullSafety.sound,
experiments: const <String>[],
);
diff --git a/dwds/test/frontend_server_ddc_evaluate_sound_test.dart b/dwds/test/frontend_server_ddc_evaluate_sound_test.dart
new file mode 100644
index 0000000..8506896
--- /dev/null
+++ b/dwds/test/frontend_server_ddc_evaluate_sound_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@Tags(['daily'])
+@TestOn('vm')
+@Timeout(Duration(minutes: 5))
+
+import 'dart:io';
+
+import 'package:dwds/expression_compiler.dart';
+import 'package:test/test.dart';
+import 'package:test_common/test_sdk_configuration.dart';
+
+import 'evaluate_common.dart';
+import 'fixtures/context.dart';
+import 'fixtures/project.dart';
+
+void main() async {
+ // Enable verbose logging for debugging.
+ final debug = false;
+
+ final provider = TestSdkConfigurationProvider(
+ verbose: debug,
+ ddcModuleFormat: ModuleFormat.ddc,
+ );
+ tearDownAll(provider.dispose);
+
+ for (var useDebuggerModuleNames in [false, true]) {
+ group('Debugger module names: $useDebuggerModuleNames |', () {
+ final nullSafety = NullSafety.sound;
+ group('${nullSafety.name} null safety | DDC module system |', () {
+ for (var indexBaseMode in IndexBaseMode.values) {
+ group(
+ 'with ${indexBaseMode.name} |',
+ () {
+ testAll(
+ provider: provider,
+ compilationMode: CompilationMode.frontendServer,
+ indexBaseMode: indexBaseMode,
+ nullSafety: nullSafety,
+ useDebuggerModuleNames: useDebuggerModuleNames,
+ debug: debug,
+ );
+ },
+ // https://github.com/dart-lang/sdk/issues/49277
+ skip: indexBaseMode == IndexBaseMode.base && Platform.isWindows,
+ );
+ }
+ });
+ });
+ }
+}
diff --git a/dwds/test/reload_test.dart b/dwds/test/reload_test.dart
index 6c425ea..8a0d8eb 100644
--- a/dwds/test/reload_test.dart
+++ b/dwds/test/reload_test.dart
@@ -42,71 +42,104 @@
);
}
- group('Injected client with live reload', () {
- group('and with debugging', () {
+ group(
+ 'Injected client with live reload',
+ () {
+ group('and with debugging', () {
+ setUp(() async {
+ setCurrentLogWriter(debug: debug);
+ await context.setUp(
+ testSettings: TestSettings(
+ reloadConfiguration: ReloadConfiguration.liveReload,
+ ),
+ );
+ });
+
+ tearDown(() async {
+ undoEdit();
+ await context.tearDown();
+ });
+
+ test('can live reload changes ', () async {
+ await makeEditAndWaitForRebuild();
+ final source = await context.webDriver.pageSource;
+
+ // A full reload should clear the state.
+ expect(source.contains(originalString), isFalse);
+ expect(source.contains(newString), isTrue);
+ });
+ });
+
+ group('and without debugging', () {
+ setUp(() async {
+ setCurrentLogWriter(debug: debug);
+ await context.setUp(
+ testSettings: TestSettings(
+ reloadConfiguration: ReloadConfiguration.liveReload,
+ ),
+ debugSettings: TestDebugSettings.noDevTools().copyWith(
+ enableDebugging: false,
+ ),
+ );
+ });
+
+ tearDown(() async {
+ undoEdit();
+ await context.tearDown();
+ });
+
+ test('can live reload changes ', () async {
+ await makeEditAndWaitForRebuild();
+
+ final source = await context.webDriver.pageSource;
+
+ // A full reload should clear the state.
+ expect(source.contains(originalString), isFalse);
+ expect(source.contains(newString), isTrue);
+ });
+ });
+
+ group('and without debugging using WebSockets', () {
+ setUp(() async {
+ setCurrentLogWriter(debug: debug);
+ await context.setUp(
+ testSettings: TestSettings(
+ reloadConfiguration: ReloadConfiguration.liveReload,
+ ),
+ debugSettings: TestDebugSettings.noDevTools().copyWith(
+ enableDebugging: false,
+ useSse: false,
+ ),
+ );
+ });
+
+ tearDown(() async {
+ await context.tearDown();
+ undoEdit();
+ });
+
+ test('can live reload changes ', () async {
+ await makeEditAndWaitForRebuild();
+
+ final source = await context.webDriver.pageSource;
+
+ // A full reload should clear the state.
+ expect(source.contains(originalString), isFalse);
+ expect(source.contains(newString), isTrue);
+ });
+ });
+ },
+ timeout: Timeout.factor(2),
+ );
+
+ group(
+ 'Injected client',
+ () {
setUp(() async {
setCurrentLogWriter(debug: debug);
await context.setUp(
testSettings: TestSettings(
- reloadConfiguration: ReloadConfiguration.liveReload,
- ),
- );
- });
-
- tearDown(() async {
- undoEdit();
- await context.tearDown();
- });
-
- test('can live reload changes ', () async {
- await makeEditAndWaitForRebuild();
- final source = await context.webDriver.pageSource;
-
- // A full reload should clear the state.
- expect(source.contains(originalString), isFalse);
- expect(source.contains(newString), isTrue);
- });
- });
-
- group('and without debugging', () {
- setUp(() async {
- setCurrentLogWriter(debug: debug);
- await context.setUp(
- testSettings: TestSettings(
- reloadConfiguration: ReloadConfiguration.liveReload,
- ),
- debugSettings: TestDebugSettings.noDevTools().copyWith(
- enableDebugging: false,
- ),
- );
- });
-
- tearDown(() async {
- undoEdit();
- await context.tearDown();
- });
-
- test('can live reload changes ', () async {
- await makeEditAndWaitForRebuild();
-
- final source = await context.webDriver.pageSource;
-
- // A full reload should clear the state.
- expect(source.contains(originalString), isFalse);
- expect(source.contains(newString), isTrue);
- });
- });
-
- group('and without debugging using WebSockets', () {
- setUp(() async {
- setCurrentLogWriter(debug: debug);
- await context.setUp(
- testSettings: TestSettings(
- reloadConfiguration: ReloadConfiguration.liveReload,
- ),
- debugSettings: TestDebugSettings.noDevTools().copyWith(
- enableDebugging: false,
- useSse: false,
+ enableExpressionEvaluation: true,
),
);
});
@@ -116,364 +149,10 @@
undoEdit();
});
- test('can live reload changes ', () async {
- await makeEditAndWaitForRebuild();
-
- final source = await context.webDriver.pageSource;
-
- // A full reload should clear the state.
- expect(source.contains(originalString), isFalse);
- expect(source.contains(newString), isTrue);
- });
- });
- });
-
- group('Injected client', () {
- setUp(() async {
- setCurrentLogWriter(debug: debug);
- await context.setUp(
- testSettings: TestSettings(
- enableExpressionEvaluation: true,
- ),
- );
- });
-
- tearDown(() async {
- await context.tearDown();
- undoEdit();
- });
-
- test('destroys and recreates the isolate during a hot restart', () async {
- final client = context.debugConnection.vmService;
- await client.streamListen('Isolate');
- await makeEditAndWaitForRebuild();
-
- final eventsDone = expectLater(
- client.onIsolateEvent,
- emitsThrough(
- emitsInOrder([
- _hasKind(EventKind.kIsolateExit),
- _hasKind(EventKind.kIsolateStart),
- _hasKind(EventKind.kIsolateRunnable),
- ]),
- ),
- );
-
- expect(
- await client.callServiceExtension('hotRestart'),
- const TypeMatcher<Success>(),
- );
-
- await eventsDone;
- });
-
- test('can execute simultaneous hot restarts', () async {
- final client = context.debugConnection.vmService;
- await client.streamListen('Isolate');
- await makeEditAndWaitForRebuild();
-
- final eventsDone = expectLater(
- client.onIsolateEvent,
- emitsThrough(
- emitsInOrder([
- _hasKind(EventKind.kIsolateExit),
- _hasKind(EventKind.kIsolateStart),
- _hasKind(EventKind.kIsolateRunnable),
- ]),
- ),
- );
-
- // Execute two hot restart calls in parallel.
- final done = Future.wait([
- client.callServiceExtension('hotRestart'),
- client.callServiceExtension('hotRestart'),
- ]);
- expect(
- await done,
- [const TypeMatcher<Success>(), const TypeMatcher<Success>()],
- );
-
- // The debugger is still working.
- final vm = await client.getVM();
- final isolateId = vm.isolates!.first.id!;
- final isolate = await client.getIsolate(isolateId);
- final library = isolate.rootLib!.uri!;
-
- final result = await client.evaluate(isolateId, library, 'true');
- expect(
- result,
- isA<InstanceRef>().having(
- (instance) => instance.valueAsString,
- 'valueAsString',
- 'true',
- ),
- );
-
- await eventsDone;
- });
-
- test('destroys and recreates the isolate during a page refresh', () async {
- final client = context.debugConnection.vmService;
- await client.streamListen('Isolate');
- await makeEditAndWaitForRebuild();
-
- final eventsDone = expectLater(
- client.onIsolateEvent,
- emitsThrough(
- emitsInOrder([
- _hasKind(EventKind.kIsolateExit),
- _hasKind(EventKind.kIsolateStart),
- _hasKind(EventKind.kIsolateRunnable),
- ]),
- ),
- );
-
- await context.webDriver.driver.refresh();
-
- await eventsDone;
- });
-
- test('can hot restart via the service extension', () async {
- final client = context.debugConnection.vmService;
- await client.streamListen('Isolate');
- await makeEditAndWaitForRebuild();
-
- final eventsDone = expectLater(
- client.onIsolateEvent,
- emitsThrough(
- emitsInOrder([
- _hasKind(EventKind.kIsolateExit),
- _hasKind(EventKind.kIsolateStart),
- _hasKind(EventKind.kIsolateRunnable),
- ]),
- ),
- );
-
- expect(
- await client.callServiceExtension('hotRestart'),
- const TypeMatcher<Success>(),
- );
-
- await eventsDone;
-
- final source = await context.webDriver.pageSource;
- // Main is re-invoked which shouldn't clear the state.
- expect(source, contains(originalString));
- expect(source, contains(newString));
- });
-
- test('can send events before and after hot restart', () async {
- final client = context.debugConnection.vmService;
- await client.streamListen('Isolate');
-
- // The event just before hot restart might never be received,
- // but the injected client continues to work and send events
- // after hot restart.
- final eventsDone = expectLater(
- client.onIsolateEvent,
- emitsThrough(
- _hasKind(EventKind.kServiceExtensionAdded)
- .having((e) => e.extensionRPC, 'service', 'ext.bar'),
- ),
- );
-
- var vm = await client.getVM();
- var isolateId = vm.isolates!.first.id!;
- var isolate = await client.getIsolate(isolateId);
- var library = isolate.rootLib!.uri!;
-
- final String callback =
- '(_, __) async => ServiceExtensionResponse.result("")';
-
- await client.evaluate(
- isolateId,
- library,
- "registerExtension('ext.foo', $callback)",
- );
-
- expect(
- await client.callServiceExtension('hotRestart'),
- const TypeMatcher<Success>(),
- );
-
- vm = await client.getVM();
- isolateId = vm.isolates!.first.id!;
- isolate = await client.getIsolate(isolateId);
- library = isolate.rootLib!.uri!;
-
- await client.evaluate(
- isolateId,
- library,
- "registerExtension('ext.bar', $callback)",
- );
-
- await eventsDone;
-
- final source = await context.webDriver.pageSource;
- // Main is re-invoked which shouldn't clear the state.
- expect(source, contains('Hello World!'));
- });
-
- test('can refresh the page via the fullReload service extension', () async {
- final client = context.debugConnection.vmService;
- await client.streamListen('Isolate');
- await makeEditAndWaitForRebuild();
-
- final eventsDone = expectLater(
- client.onIsolateEvent,
- emitsThrough(
- emitsInOrder([
- _hasKind(EventKind.kIsolateExit),
- _hasKind(EventKind.kIsolateStart),
- _hasKind(EventKind.kIsolateRunnable),
- ]),
- ),
- );
-
- expect(await client.callServiceExtension('fullReload'), isA<Success>());
-
- await eventsDone;
-
- final source = await context.webDriver.pageSource;
- // Should see only the new text
- expect(source.contains(originalString), isFalse);
- expect(source.contains(newString), isTrue);
- });
-
- test('can hot restart while paused', () async {
- final client = context.debugConnection.vmService;
- var vm = await client.getVM();
- var isolateId = vm.isolates!.first.id!;
- await client.streamListen('Debug');
- final stream = client.onEvent('Debug');
- final scriptList = await client.getScripts(isolateId);
- final main = scriptList.scripts!
- .firstWhere((script) => script.uri!.contains('main.dart'));
- final bpLine =
- await context.findBreakpointLine('printCount', isolateId, main);
- await client.addBreakpoint(isolateId, main.id!, bpLine);
- await stream
- .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint);
-
- await makeEditAndWaitForRebuild();
- await client.callServiceExtension('hotRestart');
- final source = await context.webDriver.pageSource;
-
- // Main is re-invoked which shouldn't clear the state.
- expect(source.contains(originalString), isTrue);
- expect(source.contains(newString), isTrue);
-
- vm = await client.getVM();
- isolateId = vm.isolates!.first.id!;
- final isolate = await client.getIsolate(isolateId);
-
- // Previous breakpoint should still exist.
- expect(isolate.breakpoints!.isNotEmpty, isTrue);
- final bp = isolate.breakpoints!.first;
-
- // Should pause eventually.
- await stream
- .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint);
-
- expect(
- await client.removeBreakpoint(isolate.id!, bp.id!),
- isA<Success>(),
- );
- expect(await client.resume(isolate.id!), isA<Success>());
- });
-
- test('can evaluate expressions after hot restart ', () async {
- final client = context.debugConnection.vmService;
- var vm = await client.getVM();
- var isolateId = vm.isolates!.first.id!;
- await client.streamListen('Debug');
- final stream = client.onEvent('Debug');
- final scriptList = await client.getScripts(isolateId);
- final main = scriptList.scripts!
- .firstWhere((script) => script.uri!.contains('main.dart'));
- final bpLine =
- await context.findBreakpointLine('printCount', isolateId, main);
- await client.addBreakpoint(isolateId, main.id!, bpLine);
- await stream
- .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint);
-
- await client.callServiceExtension('hotRestart');
-
- vm = await client.getVM();
- isolateId = vm.isolates!.first.id!;
- final isolate = await client.getIsolate(isolateId);
- final library = isolate.rootLib!.uri!;
- final bp = isolate.breakpoints!.first;
-
- // Should pause eventually.
- final event = await stream
- .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint);
-
- // Expression evaluation while paused on a breakpoint should work.
- var result = await client.evaluateInFrame(
- isolate.id!,
- event.topFrame!.index!,
- 'count',
- );
- expect(
- result,
- isA<InstanceRef>().having(
- (instance) => instance.valueAsString,
- 'valueAsString',
- greaterThanOrEqualTo('0'),
- ),
- );
-
- await client.removeBreakpoint(isolateId, bp.id!);
- await client.resume(isolateId);
-
- // Expression evaluation while running should work.
- result = await client.evaluate(isolateId, library, 'true');
- expect(
- result,
- isA<InstanceRef>().having(
- (instance) => instance.valueAsString,
- 'valueAsString',
- 'true',
- ),
- );
- });
- });
-
- group('Injected client with hot restart', () {
- group('and with debugging', () {
- setUp(() async {
- setCurrentLogWriter(debug: debug);
- await context.setUp(
- testSettings: TestSettings(
- reloadConfiguration: ReloadConfiguration.hotRestart,
- ),
- );
- });
-
- tearDown(() async {
- await context.tearDown();
- undoEdit();
- });
-
- test('can hot restart changes ', () async {
- await makeEditAndWaitForRebuild();
-
- final source = await context.webDriver.pageSource;
-
- // Main is re-invoked which shouldn't clear the state.
- expect(source.contains(originalString), isTrue);
- expect(source.contains(newString), isTrue);
- // The ext.flutter.disassemble callback is invoked and waited for.
- expect(
- source,
- contains('start disassemble end disassemble $newString'),
- );
- });
-
- test('fires isolate create/destroy events during hot restart', () async {
+ test('destroys and recreates the isolate during a hot restart', () async {
final client = context.debugConnection.vmService;
await client.streamListen('Isolate');
+ await makeEditAndWaitForRebuild();
final eventsDone = expectLater(
client.onIsolateEvent,
@@ -486,45 +165,381 @@
),
);
- await makeEditAndWaitForRebuild();
+ expect(
+ await client.callServiceExtension('hotRestart'),
+ const TypeMatcher<Success>(),
+ );
await eventsDone;
});
- });
- group('and without debugging', () {
- setUp(() async {
- setCurrentLogWriter(debug: debug);
- await context.setUp(
- testSettings: TestSettings(
- reloadConfiguration: ReloadConfiguration.hotRestart,
- ),
- debugSettings:
- TestDebugSettings.noDevTools().copyWith(enableDebugging: false),
- );
- });
-
- tearDown(() async {
- await context.tearDown();
- undoEdit();
- });
-
- test('can hot restart changes ', () async {
+ test('can execute simultaneous hot restarts', () async {
+ final client = context.debugConnection.vmService;
+ await client.streamListen('Isolate');
await makeEditAndWaitForRebuild();
+ final eventsDone = expectLater(
+ client.onIsolateEvent,
+ emitsThrough(
+ emitsInOrder([
+ _hasKind(EventKind.kIsolateExit),
+ _hasKind(EventKind.kIsolateStart),
+ _hasKind(EventKind.kIsolateRunnable),
+ ]),
+ ),
+ );
+
+ // Execute two hot restart calls in parallel.
+ final done = Future.wait([
+ client.callServiceExtension('hotRestart'),
+ client.callServiceExtension('hotRestart'),
+ ]);
+ expect(
+ await done,
+ [const TypeMatcher<Success>(), const TypeMatcher<Success>()],
+ );
+
+ // The debugger is still working.
+ final vm = await client.getVM();
+ final isolateId = vm.isolates!.first.id!;
+ final isolate = await client.getIsolate(isolateId);
+ final library = isolate.rootLib!.uri!;
+
+ final result = await client.evaluate(isolateId, library, 'true');
+ expect(
+ result,
+ isA<InstanceRef>().having(
+ (instance) => instance.valueAsString,
+ 'valueAsString',
+ 'true',
+ ),
+ );
+
+ await eventsDone;
+ });
+
+ test('destroys and recreates the isolate during a page refresh',
+ () async {
+ final client = context.debugConnection.vmService;
+ await client.streamListen('Isolate');
+ await makeEditAndWaitForRebuild();
+
+ final eventsDone = expectLater(
+ client.onIsolateEvent,
+ emitsThrough(
+ emitsInOrder([
+ _hasKind(EventKind.kIsolateExit),
+ _hasKind(EventKind.kIsolateStart),
+ _hasKind(EventKind.kIsolateRunnable),
+ ]),
+ ),
+ );
+
+ await context.webDriver.driver.refresh();
+
+ await eventsDone;
+ });
+
+ test('can hot restart via the service extension', () async {
+ final client = context.debugConnection.vmService;
+ await client.streamListen('Isolate');
+ await makeEditAndWaitForRebuild();
+
+ final eventsDone = expectLater(
+ client.onIsolateEvent,
+ emitsThrough(
+ emitsInOrder([
+ _hasKind(EventKind.kIsolateExit),
+ _hasKind(EventKind.kIsolateStart),
+ _hasKind(EventKind.kIsolateRunnable),
+ ]),
+ ),
+ );
+
+ expect(
+ await client.callServiceExtension('hotRestart'),
+ const TypeMatcher<Success>(),
+ );
+
+ await eventsDone;
+
+ final source = await context.webDriver.pageSource;
+ // Main is re-invoked which shouldn't clear the state.
+ expect(source, contains(originalString));
+ expect(source, contains(newString));
+ });
+
+ test('can send events before and after hot restart', () async {
+ final client = context.debugConnection.vmService;
+ await client.streamListen('Isolate');
+
+ // The event just before hot restart might never be received,
+ // but the injected client continues to work and send events
+ // after hot restart.
+ final eventsDone = expectLater(
+ client.onIsolateEvent,
+ emitsThrough(
+ _hasKind(EventKind.kServiceExtensionAdded)
+ .having((e) => e.extensionRPC, 'service', 'ext.bar'),
+ ),
+ );
+
+ var vm = await client.getVM();
+ var isolateId = vm.isolates!.first.id!;
+ var isolate = await client.getIsolate(isolateId);
+ var library = isolate.rootLib!.uri!;
+
+ final String callback =
+ '(_, __) async => ServiceExtensionResponse.result("")';
+
+ await client.evaluate(
+ isolateId,
+ library,
+ "registerExtension('ext.foo', $callback)",
+ );
+
+ expect(
+ await client.callServiceExtension('hotRestart'),
+ const TypeMatcher<Success>(),
+ );
+
+ vm = await client.getVM();
+ isolateId = vm.isolates!.first.id!;
+ isolate = await client.getIsolate(isolateId);
+ library = isolate.rootLib!.uri!;
+
+ await client.evaluate(
+ isolateId,
+ library,
+ "registerExtension('ext.bar', $callback)",
+ );
+
+ await eventsDone;
+
+ final source = await context.webDriver.pageSource;
+ // Main is re-invoked which shouldn't clear the state.
+ expect(source, contains('Hello World!'));
+ });
+
+ test('can refresh the page via the fullReload service extension',
+ () async {
+ final client = context.debugConnection.vmService;
+ await client.streamListen('Isolate');
+ await makeEditAndWaitForRebuild();
+
+ final eventsDone = expectLater(
+ client.onIsolateEvent,
+ emitsThrough(
+ emitsInOrder([
+ _hasKind(EventKind.kIsolateExit),
+ _hasKind(EventKind.kIsolateStart),
+ _hasKind(EventKind.kIsolateRunnable),
+ ]),
+ ),
+ );
+
+ expect(await client.callServiceExtension('fullReload'), isA<Success>());
+
+ await eventsDone;
+
+ final source = await context.webDriver.pageSource;
+ // Should see only the new text
+ expect(source.contains(originalString), isFalse);
+ expect(source.contains(newString), isTrue);
+ });
+
+ test('can hot restart while paused', () async {
+ final client = context.debugConnection.vmService;
+ var vm = await client.getVM();
+ var isolateId = vm.isolates!.first.id!;
+ await client.streamListen('Debug');
+ final stream = client.onEvent('Debug');
+ final scriptList = await client.getScripts(isolateId);
+ final main = scriptList.scripts!
+ .firstWhere((script) => script.uri!.contains('main.dart'));
+ final bpLine =
+ await context.findBreakpointLine('printCount', isolateId, main);
+ await client.addBreakpoint(isolateId, main.id!, bpLine);
+ await stream
+ .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint);
+
+ await makeEditAndWaitForRebuild();
+ await client.callServiceExtension('hotRestart');
final source = await context.webDriver.pageSource;
// Main is re-invoked which shouldn't clear the state.
expect(source.contains(originalString), isTrue);
expect(source.contains(newString), isTrue);
- // The ext.flutter.disassemble callback is invoked and waited for.
+
+ vm = await client.getVM();
+ isolateId = vm.isolates!.first.id!;
+ final isolate = await client.getIsolate(isolateId);
+
+ // Previous breakpoint should still exist.
+ expect(isolate.breakpoints!.isNotEmpty, isTrue);
+ final bp = isolate.breakpoints!.first;
+
+ // Should pause eventually.
+ await stream
+ .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint);
+
expect(
- source,
- contains('start disassemble end disassemble $newString'),
+ await client.removeBreakpoint(isolate.id!, bp.id!),
+ isA<Success>(),
+ );
+ expect(await client.resume(isolate.id!), isA<Success>());
+ });
+
+ test('can evaluate expressions after hot restart ', () async {
+ final client = context.debugConnection.vmService;
+ var vm = await client.getVM();
+ var isolateId = vm.isolates!.first.id!;
+ await client.streamListen('Debug');
+ final stream = client.onEvent('Debug');
+ final scriptList = await client.getScripts(isolateId);
+ final main = scriptList.scripts!
+ .firstWhere((script) => script.uri!.contains('main.dart'));
+ final bpLine =
+ await context.findBreakpointLine('printCount', isolateId, main);
+ await client.addBreakpoint(isolateId, main.id!, bpLine);
+ await stream
+ .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint);
+
+ await client.callServiceExtension('hotRestart');
+
+ vm = await client.getVM();
+ isolateId = vm.isolates!.first.id!;
+ final isolate = await client.getIsolate(isolateId);
+ final library = isolate.rootLib!.uri!;
+ final bp = isolate.breakpoints!.first;
+
+ // Should pause eventually.
+ final event = await stream
+ .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint);
+
+ // Expression evaluation while paused on a breakpoint should work.
+ var result = await client.evaluateInFrame(
+ isolate.id!,
+ event.topFrame!.index!,
+ 'count',
+ );
+ expect(
+ result,
+ isA<InstanceRef>().having(
+ (instance) => instance.valueAsString,
+ 'valueAsString',
+ greaterThanOrEqualTo('0'),
+ ),
+ );
+
+ await client.removeBreakpoint(isolateId, bp.id!);
+ await client.resume(isolateId);
+
+ // Expression evaluation while running should work.
+ result = await client.evaluate(isolateId, library, 'true');
+ expect(
+ result,
+ isA<InstanceRef>().having(
+ (instance) => instance.valueAsString,
+ 'valueAsString',
+ 'true',
+ ),
);
});
- });
- });
+ },
+ timeout: Timeout.factor(2),
+ );
+
+ group(
+ 'Injected client with hot restart',
+ () {
+ group('and with debugging', () {
+ setUp(() async {
+ setCurrentLogWriter(debug: debug);
+ await context.setUp(
+ testSettings: TestSettings(
+ reloadConfiguration: ReloadConfiguration.hotRestart,
+ ),
+ );
+ });
+
+ tearDown(() async {
+ await context.tearDown();
+ undoEdit();
+ });
+
+ test('can hot restart changes ', () async {
+ await makeEditAndWaitForRebuild();
+
+ final source = await context.webDriver.pageSource;
+
+ // Main is re-invoked which shouldn't clear the state.
+ expect(source.contains(originalString), isTrue);
+ expect(source.contains(newString), isTrue);
+ // The ext.flutter.disassemble callback is invoked and waited for.
+ expect(
+ source,
+ contains('start disassemble end disassemble $newString'),
+ );
+ });
+
+ test('fires isolate create/destroy events during hot restart',
+ () async {
+ final client = context.debugConnection.vmService;
+ await client.streamListen('Isolate');
+
+ final eventsDone = expectLater(
+ client.onIsolateEvent,
+ emitsThrough(
+ emitsInOrder([
+ _hasKind(EventKind.kIsolateExit),
+ _hasKind(EventKind.kIsolateStart),
+ _hasKind(EventKind.kIsolateRunnable),
+ ]),
+ ),
+ );
+
+ await makeEditAndWaitForRebuild();
+
+ await eventsDone;
+ });
+ });
+
+ group('and without debugging', () {
+ setUp(() async {
+ setCurrentLogWriter(debug: debug);
+ await context.setUp(
+ testSettings: TestSettings(
+ reloadConfiguration: ReloadConfiguration.hotRestart,
+ ),
+ debugSettings:
+ TestDebugSettings.noDevTools().copyWith(enableDebugging: false),
+ );
+ });
+
+ tearDown(() async {
+ await context.tearDown();
+ undoEdit();
+ });
+
+ test('can hot restart changes ', () async {
+ await makeEditAndWaitForRebuild();
+
+ final source = await context.webDriver.pageSource;
+
+ // Main is re-invoked which shouldn't clear the state.
+ expect(source.contains(originalString), isTrue);
+ expect(source.contains(newString), isTrue);
+ // The ext.flutter.disassemble callback is invoked and waited for.
+ expect(
+ source,
+ contains('start disassemble end disassemble $newString'),
+ );
+ });
+ });
+ },
+ timeout: Timeout.factor(2),
+ );
}
TypeMatcher<Event> _hasKind(String kind) =>
diff --git a/dwds/test/run_request_test.dart b/dwds/test/run_request_test.dart
index 89db646..8efd4f0 100644
--- a/dwds/test/run_request_test.dart
+++ b/dwds/test/run_request_test.dart
@@ -24,51 +24,57 @@
final context = TestContext(TestProject.testWithSoundNullSafety, provider);
- group('while debugger is attached', () {
- late VmServiceInterface service;
- setUp(() async {
- setCurrentLogWriter(debug: debug);
- await context.setUp(
- testSettings: TestSettings(
- autoRun: false,
- verboseCompiler: debug,
- ),
- );
- service = context.service;
- });
+ group(
+ 'while debugger is attached',
+ () {
+ late VmServiceInterface service;
+ setUp(() async {
+ setCurrentLogWriter(debug: debug);
+ await context.setUp(
+ testSettings: TestSettings(
+ autoRun: false,
+ verboseCompiler: debug,
+ ),
+ );
+ service = context.service;
+ });
- tearDown(() async {
- await context.tearDown();
- });
+ tearDown(() async {
+ await context.tearDown();
+ });
- test('can resume while paused at the start', () async {
- final vm = await service.getVM();
- final isolate = await service.getIsolate(vm.isolates!.first.id!);
- expect(isolate.pauseEvent!.kind, EventKind.kPauseStart);
- final stream = service.onEvent('Debug');
- final resumeCompleter = Completer();
- // The underlying stream is a broadcast stream so we need to add a
- // listener before calling resume so that we don't miss events.
- unawaited(
- stream.firstWhere((event) => event.kind == EventKind.kResume).then((_) {
- resumeCompleter.complete();
- }),
- );
- await service.resume(isolate.id!);
- await resumeCompleter.future;
- expect(isolate.pauseEvent!.kind, EventKind.kResume);
- });
+ test('can resume while paused at the start', () async {
+ final vm = await service.getVM();
+ final isolate = await service.getIsolate(vm.isolates!.first.id!);
+ expect(isolate.pauseEvent!.kind, EventKind.kPauseStart);
+ final stream = service.onEvent('Debug');
+ final resumeCompleter = Completer();
+ // The underlying stream is a broadcast stream so we need to add a
+ // listener before calling resume so that we don't miss events.
+ unawaited(
+ stream
+ .firstWhere((event) => event.kind == EventKind.kResume)
+ .then((_) {
+ resumeCompleter.complete();
+ }),
+ );
+ await service.resume(isolate.id!);
+ await resumeCompleter.future;
+ expect(isolate.pauseEvent!.kind, EventKind.kResume);
+ });
- test('correctly sets the isolate pauseEvent', () async {
- final vm = await service.getVM();
- final isolate = await service.getIsolate(vm.isolates!.first.id!);
- expect(isolate.pauseEvent!.kind, EventKind.kPauseStart);
- final stream = service.onEvent('Debug');
- context.appConnection.runMain();
- await stream.firstWhere((event) => event.kind == EventKind.kResume);
- expect(isolate.pauseEvent!.kind, EventKind.kResume);
- });
- });
+ test('correctly sets the isolate pauseEvent', () async {
+ final vm = await service.getVM();
+ final isolate = await service.getIsolate(vm.isolates!.first.id!);
+ expect(isolate.pauseEvent!.kind, EventKind.kPauseStart);
+ final stream = service.onEvent('Debug');
+ context.appConnection.runMain();
+ await stream.firstWhere((event) => event.kind == EventKind.kResume);
+ expect(isolate.pauseEvent!.kind, EventKind.kResume);
+ });
+ },
+ timeout: Timeout.factor(2),
+ );
group('while debugger is not attached', () {
setUp(() async {
diff --git a/frontend_server_common/lib/src/bootstrap.dart b/frontend_server_common/lib/src/bootstrap.dart
index a5d1ba0..206e73e 100644
--- a/frontend_server_common/lib/src/bootstrap.dart
+++ b/frontend_server_common/lib/src/bootstrap.dart
@@ -4,6 +4,78 @@
// Note: this is a copy from flutter tools, updated to work with dwds tests
+/// JavaScript snippet to determine the base URL of the current path.
+const String _baseUrlScript = '''
+var baseUrl = (function () {
+ // Attempt to detect --precompiled mode for tests, and set the base url
+ // appropriately, otherwise set it to '/'.
+ var pathParts = location.pathname.split("/");
+ if (pathParts[0] == "") {
+ pathParts.shift();
+ }
+ if (pathParts.length > 1 && pathParts[1] == "test") {
+ return "/" + pathParts.slice(0, 2).join("/") + "/";
+ }
+ // Attempt to detect base url using <base href> html tag
+ // base href should start and end with "/"
+ if (typeof document !== 'undefined') {
+ var el = document.getElementsByTagName('base');
+ if (el && el[0] && el[0].getAttribute("href") && el[0].getAttribute
+ ("href").startsWith("/") && el[0].getAttribute("href").endsWith("/")){
+ return el[0].getAttribute("href");
+ }
+ }
+ // return default value
+ return "/";
+}());
+var _trimmedBaseUrl = baseUrl.endsWith('/') ? baseUrl.substring(0, baseUrl.length - 1) : baseUrl;
+var _currentDirectory = window.location.origin + _trimmedBaseUrl;
+''';
+
+/// Used to load prerequisite scripts such as ddc_module_loader.js
+const String _simpleLoaderScript = r'''
+window.$dartCreateScript = (function() {
+ // Find the nonce value. (Note, this is only computed once.)
+ var scripts = Array.from(document.getElementsByTagName("script"));
+ var nonce;
+ scripts.some(
+ script => (nonce = script.nonce || script.getAttribute("nonce")));
+ // If present, return a closure that automatically appends the nonce.
+ if (nonce) {
+ return function() {
+ var script = document.createElement("script");
+ script.nonce = nonce;
+ return script;
+ };
+ } else {
+ return function() {
+ return document.createElement("script");
+ };
+ }
+})();
+
+// Loads a module [relativeUrl] relative to [root].
+//
+// If not specified, [root] defaults to the directory serving the main app.
+var forceLoadModule = function (relativeUrl, root) {
+ var actualRoot = root ?? _currentDirectory;
+ var trimmedRoot = actualRoot.endsWith('/') ? actualRoot.substring(0, actualRoot.length - 1) : actualRoot;
+ return new Promise(function(resolve, reject) {
+ var script = self.$dartCreateScript();
+ let policy = {
+ createScriptURL: function(src) {return src;}
+ };
+ if (self.trustedTypes && self.trustedTypes.createPolicy) {
+ policy = self.trustedTypes.createPolicy('dartDdcModuleUrl', policy);
+ }
+ script.onload = resolve;
+ script.onerror = reject;
+ script.src = policy.createScriptURL(trimmedRoot + "/" + relativeUrl);
+ document.head.appendChild(script);
+ });
+};
+''';
+
/// The JavaScript bootstrap script to support in-browser hot restart.
///
/// The [requireUrl] loads our cached RequireJS script file. The [mapperUrl]
@@ -68,3 +140,244 @@
});
''';
}
+
+String generateDDCBootstrapScript({
+ required String ddcModuleLoaderUrl,
+ required String mapperUrl,
+ required String entrypoint,
+ required String bootstrapUrl,
+}) {
+ return '''
+$_baseUrlScript
+$_simpleLoaderScript
+
+(function() {
+ let appName = "$entrypoint";
+
+ // A uuid that identifies a subapp.
+ let uuid = "00000000-0000-0000-0000-000000000000";
+
+ window.postMessage(
+ {type: "DDC_STATE_CHANGE", state: "initial_load", targetUuid: uuid}, "*");
+
+ // Load pre-requisite DDC scripts. We intentionally use invalid names to avoid namespace clashes.
+ let prerequisiteScripts = [
+ {
+ "src": "$ddcModuleLoaderUrl",
+ "id": "dart_library \x00"
+ },
+ {
+ "src": "$mapperUrl",
+ "id": "dart_stack_trace_mapper \x00"
+ }
+ ];
+
+ // Load ddc_module_loader.js to access DDC's module loader API.
+ let prerequisiteLoads = [];
+ for (let i = 0; i < prerequisiteScripts.length; i++) {
+ prerequisiteLoads.push(forceLoadModule(prerequisiteScripts[i].src));
+ }
+ Promise.all(prerequisiteLoads).then((_) => afterPrerequisiteLogic());
+
+ // Save the current script so we can access it in a closure.
+ var _currentScript = document.currentScript;
+
+ var afterPrerequisiteLogic = function() {
+ window.\$dartLoader.rootDirectories.push(_currentDirectory);
+ let scripts = [
+ {
+ "src": "dart_sdk.js",
+ "id": "dart_sdk"
+ },
+ {
+ "src": "$bootstrapUrl",
+ "id": "data-main"
+ }
+ ];
+ let loadConfig = new window.\$dartLoader.LoadConfiguration();
+ loadConfig.root = _currentDirectory;
+ loadConfig.bootstrapScript = scripts[scripts.length - 1];
+
+ if (window.\$dartJITModules) {
+ loadConfig.loadScriptFn = function(loader) {
+ // Loads just the entrypoint module and required SDK modules.
+ let moduleSet = new Set();
+ // This cache is populated by ddc_module_loader.js
+ let libraryCache = JSON.parse(window.localStorage.getItem(`dartLibraryCache:\${appName}`));
+ if (libraryCache) {
+ // TODO(b/165021238) - when should this be invalidated?
+ moduleSet = new Set(libraryCache["modules"])
+ }
+ loader.addScriptsToQueue(scripts, function(script) {
+ // Preemptively load the ddc module loader and previously executed modules.
+ return moduleSet.size == 0
+ || script.id.includes("dart_library")
+ // We preemptively load the stack_trace_mapper module so that we can
+ // translate JS errors to Dart.
+ || script.id.includes("stack_trace_mapper")
+ || moduleSet.has(script.id);
+ });
+ loader.loadEnqueuedModules();
+ }
+ loadConfig.ddcEventForLoadStart = /* LOAD_ENTRYPOINT_MODULES_START */ 4;
+ loadConfig.ddcEventForLoadedOk = /* LOAD_ENTRYPOINT_MODULES_END_OK */ 5;
+ loadConfig.ddcEventForLoadedError = /* LOAD_ENTRYPOINT_MODULES_END_ERROR */ 6;
+ } else {
+ loadConfig.loadScriptFn = function(loader) {
+ loader.addScriptsToQueue(scripts, null);
+ loader.loadEnqueuedModules();
+ }
+ loadConfig.ddcEventForLoadStart = /* LOAD_ALL_MODULES_START */ 1;
+ loadConfig.ddcEventForLoadedOk = /* LOAD_ALL_MODULES_END_OK */ 2;
+ loadConfig.ddcEventForLoadedError = /* LOAD_ALL_MODULES_END_ERROR */ 3;
+ }
+
+ let loader = new window.\$dartLoader.DDCLoader(loadConfig);
+
+ // Record prerequisite scripts' fully resolved URLs.
+ prerequisiteScripts.forEach(script => loader.registerScript(script));
+
+ // Note: these variables should only be used in non-multi-app scenarios since
+ // they can be arbitrarily overridden based on multi-app load order.
+ window.\$dartLoader.loadConfig = loadConfig;
+ window.\$dartLoader.loader = loader;
+ loader.nextAttempt();
+
+ let currentUri = _currentScript.src;
+ let fetchEtagsUri;
+ if (currentUri.indexOf("?") == -1) {
+ fetchEtagsUri = currentUri + "?fetch-etags=true";
+ } else {
+ fetchEtagsUri = currentUri + "&fetch-etags=true";
+ }
+
+ if (!window.\$dartAppNameToMetadata) {
+ window.\$dartAppNameToMetadata = new Map();
+ }
+ window.\$dartAppNameToMetadata.set(appName, {
+ currentDirectory: _currentDirectory,
+ currentUri: currentUri,
+ fetchEtagsUri: fetchEtagsUri,
+ });
+
+ if (!window.\$dartReloadModifiedModules) {
+ window.\$dartReloadModifiedModules = (function(appName, callback) {
+ function cb() {
+ window.postMessage(
+ {
+ type: "DDC_STATE_CHANGE",
+ state: "restart_end",
+ targetUuid: uuid,
+ },
+ "*");
+ callback();
+ }
+ window.postMessage(
+ {
+ type: "DDC_STATE_CHANGE",
+ state: "restart_begin",
+ targetUuid: uuid,
+ },
+ "*");
+ var xhttp = new XMLHttpRequest();
+ xhttp.withCredentials = true;
+ xhttp.onreadystatechange = function() {
+ // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState
+ if (this.readyState == 4 && this.status == 200 || this.status == 304) {
+ var scripts = JSON.parse(this.responseText);
+ var numToLoad = 0;
+ var numLoaded = 0;
+ for (var i = 0; i < scripts.length; i++) {
+ var script = scripts[i];
+ if (script.id == null) continue;
+ var src =
+ window.\$dartAppNameToMetadata.get(appName).currentDirectory +
+ script.src.toString();
+ var oldSrc = window.\$dartLoader.moduleIdToUrl.get(script.id);
+ // Only compare the search parameters which contain the cache
+ // busting portion of the uri. The path might be different if the
+ // script is loaded from a different application on the page.
+ if (new URL(oldSrc).search == new URL(src).search) continue;
+
+ // We might actually load from a different uri, delete the old one
+ // just to be sure.
+ window.\$dartLoader.urlToModuleId.delete(oldSrc);
+
+ window.\$dartLoader.moduleIdToUrl.set(script.id, src);
+ window.\$dartLoader.urlToModuleId.set(src, script.id);
+
+ if (window.\$dartJITModules) {
+ // Simply invalidate the import and the corresponding module will
+ // be lazily loaded.
+ dart_library.invalidateImport(script.id);
+ continue;
+ } else {
+ numToLoad++;
+ }
+
+ var el = document.getElementById(script.id);
+ if (el) el.remove();
+ el = window.\$dartCreateScript();
+ el.src = policy.createScriptURL(src);
+ el.async = false;
+ el.defer = true;
+ el.id = script.id;
+ el.onload = function() {
+ numLoaded++;
+ if (numToLoad == numLoaded) cb();
+ };
+ document.head.appendChild(el);
+ }
+ // Call `cb` right away if we found no updated scripts.
+ if (numToLoad == 0) cb();
+ }
+ };
+ xhttp.open("GET",
+ window.\$dartAppNameToMetadata.get(appName).fetchEtagsUri, true);
+ let sdk = dart_library.import("dart_sdk", appName);
+ let developer = sdk.developer;
+ if (developer._extensions.containsKey("ext.flutter.disassemble")) {
+ developer.invokeExtension("ext.flutter.disassemble", "{}").then(() => {
+ // TODO(b/204210914): we should really be clearing all statics for all
+ // apps, but for now we just do it for flutter apps which we recognize
+ // based on this extension.
+ sdk.dart.hotRestart();
+ xhttp.send();
+ });
+ } else {
+ xhttp.send();
+ }
+ });
+ }
+ }
+})();
+''';
+}
+
+String generateDDCMainModule(
+ {required String entrypoint, String? exportedMain}) {
+ final exportedMainName = exportedMain ?? entrypoint.split('.')[0];
+ return '''/* ENTRYPOINT_EXTENTION_MARKER */
+
+(function() {
+ let appName = "$entrypoint";
+
+ // A uuid that identifies a subapp.
+ let uuid = "00000000-0000-0000-0000-000000000000";
+
+ let dart_sdk = dart_library.import('dart_sdk', appName);
+
+ dart_sdk.dart.setStartAsyncSynchronously(true);
+ dart_sdk._debugger.registerDevtoolsFormatter();
+ dart_sdk._isolate_helper.startRootIsolate(() => {}, []);
+
+ let child = {};
+ child.main = function() {
+ dart_library.start(appName, uuid, "$entrypoint", "$exportedMainName");
+ }
+
+ /* MAIN_EXTENSION_MARKER */
+ child.main();
+})();
+''';
+}
diff --git a/frontend_server_common/lib/src/devfs.dart b/frontend_server_common/lib/src/devfs.dart
index 64e3e45..51a8fed 100644
--- a/frontend_server_common/lib/src/devfs.dart
+++ b/frontend_server_common/lib/src/devfs.dart
@@ -6,6 +6,8 @@
import 'package:dwds/asset_reader.dart';
import 'package:dwds/config.dart';
+import 'package:dwds/expression_compiler.dart';
+import 'package:dwds/utilities.dart';
import 'package:file/file.dart';
import 'package:path/path.dart' as p;
import 'package:test_common/test_sdk_layout.dart';
@@ -25,6 +27,7 @@
required this.soundNullSafety,
this.urlTunneler,
required this.sdkLayout,
+ required this.ddcModuleFormat,
});
final FileSystem fileSystem;
@@ -37,6 +40,7 @@
final UrlEncoder? urlTunneler;
final bool soundNullSafety;
final TestSdkLayout sdkLayout;
+ final ModuleFormat ddcModuleFormat;
late final Directory _savedCurrentDirectory;
Future<Uri> create() async {
@@ -44,8 +48,15 @@
fileSystem.currentDirectory = projectDirectory.toFilePath();
- assetServer = await TestAssetServer.start(sdkLayout.sdkDirectory,
- fileSystem, index, hostname, port, urlTunneler, packageUriMapper);
+ assetServer = await TestAssetServer.start(
+ sdkLayout.sdkDirectory,
+ fileSystem,
+ index,
+ hostname,
+ port,
+ urlTunneler,
+ packageUriMapper,
+ );
return Uri.parse('http://$hostname:$port');
}
@@ -64,6 +75,7 @@
final outputDirectoryPath = fileSystem.file(mainPath).parent.path;
final entryPoint = mainUri.toString();
+ var ddcModuleLoader = 'ddc_module_loader.js';
var require = 'require.js';
var stackMapper = 'stack_trace_mapper.js';
var main = 'main.dart.js';
@@ -73,6 +85,7 @@
// to store all files, so the paths match the requests.
if (assetServer.basePath.isEmpty) {
final directory = p.dirname(entryPoint);
+ ddcModuleLoader = '$directory/ddc_module_loader.js';
require = '$directory/require.js';
stackMapper = '$directory/stack_trace_mapper.js';
main = '$directory/main.dart.js';
@@ -81,22 +94,51 @@
assetServer.writeFile(
entryPoint, fileSystem.file(mainPath).readAsStringSync());
- assetServer.writeFile(require, requireJS.readAsStringSync());
assetServer.writeFile(stackMapper, stackTraceMapper.readAsStringSync());
- assetServer.writeFile(
- main,
- generateBootstrapScript(
- requireUrl: 'require.js',
- mapperUrl: 'stack_trace_mapper.js',
- entrypoint: entryPoint,
- ),
- );
- assetServer.writeFile(
- bootstrap,
- generateMainModule(
- entrypoint: entryPoint,
- ),
- );
+
+ switch (ddcModuleFormat) {
+ case ModuleFormat.amd:
+ assetServer.writeFile(require, requireJS.readAsStringSync());
+ assetServer.writeFile(
+ main,
+ generateBootstrapScript(
+ requireUrl: 'require.js',
+ mapperUrl: 'stack_trace_mapper.js',
+ entrypoint: entryPoint,
+ ),
+ );
+ assetServer.writeFile(
+ bootstrap,
+ generateMainModule(
+ entrypoint: entryPoint,
+ ),
+ );
+ break;
+ case ModuleFormat.ddc:
+ assetServer.writeFile(
+ ddcModuleLoader, ddcModuleLoaderJS.readAsStringSync());
+ assetServer.writeFile(
+ main,
+ generateDDCBootstrapScript(
+ ddcModuleLoaderUrl: ddcModuleLoader,
+ mapperUrl: stackMapper,
+ entrypoint: entryPoint,
+ bootstrapUrl: bootstrap,
+ ),
+ );
+ // DDC uses a simple heuristic to determine exported identifier names.
+ // The module name (entrypoint name here) has its extension removed, and
+ // special path elements like '/', '\', and '..' are replaced with '__'.
+ final exportedMainName = pathToJSIdentifier(entryPoint.split('.')[0]);
+ assetServer.writeFile(
+ bootstrap,
+ generateDDCMainModule(
+ entrypoint: entryPoint, exportedMain: exportedMainName),
+ );
+ break;
+ default:
+ throw Exception('Unsupported DDC module format $ddcModuleFormat.');
+ }
assetServer.writeFile('main_module.digests', '{}');
@@ -144,11 +186,29 @@
)..invalidatedModules = modules;
}
+ File get ddcModuleLoaderJS =>
+ fileSystem.file(sdkLayout.ddcModuleLoaderJsPath);
File get requireJS => fileSystem.file(sdkLayout.requireJsPath);
- File get dartSdkWeak => fileSystem.file(sdkLayout.weakJsPath);
- File get dartSdk => fileSystem.file(sdkLayout.soundJsPath);
- File get dartSdkSourcemapWeak => fileSystem.file(sdkLayout.weakJsMapPath);
- File get dartSdkSourcemap => fileSystem.file(sdkLayout.soundJsMapPath);
+ File get dartSdkWeak => fileSystem.file(switch (ddcModuleFormat) {
+ ModuleFormat.amd => sdkLayout.weakAmdJsPath,
+ ModuleFormat.ddc => sdkLayout.weakDdcJsPath,
+ _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.')
+ });
+ File get dartSdk => fileSystem.file(switch (ddcModuleFormat) {
+ ModuleFormat.amd => sdkLayout.soundAmdJsPath,
+ ModuleFormat.ddc => sdkLayout.soundDdcJsPath,
+ _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.')
+ });
+ File get dartSdkSourcemapWeak => fileSystem.file(switch (ddcModuleFormat) {
+ ModuleFormat.amd => sdkLayout.weakAmdJsMapPath,
+ ModuleFormat.ddc => sdkLayout.weakDdcJsMapPath,
+ _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.')
+ });
+ File get dartSdkSourcemap => fileSystem.file(switch (ddcModuleFormat) {
+ ModuleFormat.amd => sdkLayout.soundAmdJsMapPath,
+ ModuleFormat.ddc => sdkLayout.soundDdcJsMapPath,
+ _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.')
+ });
File get stackTraceMapper => fileSystem.file(sdkLayout.stackTraceMapperPath);
}
diff --git a/frontend_server_common/lib/src/frontend_server_client.dart b/frontend_server_common/lib/src/frontend_server_client.dart
index 18b15b5..6576a0b 100644
--- a/frontend_server_common/lib/src/frontend_server_client.dart
+++ b/frontend_server_common/lib/src/frontend_server_client.dart
@@ -394,6 +394,8 @@
'--enable-experiment=$experiment',
if (compilerOptions.canaryFeatures) '--dartdevc-canary',
if (verbose) '--verbose',
+ if (compilerOptions.moduleFormat == ModuleFormat.ddc)
+ '--dartdevc-module-format=ddc'
];
_logger.info(args.join(' '));
diff --git a/frontend_server_common/lib/src/resident_runner.dart b/frontend_server_common/lib/src/resident_runner.dart
index 86f1427..f57954b 100644
--- a/frontend_server_common/lib/src/resident_runner.dart
+++ b/frontend_server_common/lib/src/resident_runner.dart
@@ -81,6 +81,7 @@
urlTunneler: urlTunneler,
soundNullSafety: compilerOptions.soundNullSafety,
sdkLayout: sdkLayout,
+ ddcModuleFormat: compilerOptions.moduleFormat,
);
uri = await devFS.create();
diff --git a/test_common/lib/sdk_asset_generator.dart b/test_common/lib/sdk_asset_generator.dart
index 16dc7be..bcf6d79 100644
--- a/test_common/lib/sdk_asset_generator.dart
+++ b/test_common/lib/sdk_asset_generator.dart
@@ -1,6 +1,7 @@
import 'dart:convert';
import 'dart:io';
+import 'package:dwds/expression_compiler.dart';
import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:logging/logging.dart';
@@ -18,6 +19,7 @@
final FileSystem fileSystem;
final bool canaryFeatures;
+ final ModuleFormat ddcModuleFormat;
final bool verbose;
late final TestSdkLayout sdkLayout;
@@ -26,6 +28,7 @@
this.fileSystem = const LocalFileSystem(),
required this.sdkLayout,
required this.canaryFeatures,
+ required this.ddcModuleFormat,
this.verbose = false,
});
@@ -52,6 +55,42 @@
}
}
+ String resolveSdkJsPath({
+ required bool soundNullSafety,
+ required bool canaryFeatures,
+ }) =>
+ switch ((soundNullSafety, ddcModuleFormat)) {
+ (true, ModuleFormat.amd) => sdkLayout.soundAmdJsPath,
+ (false, ModuleFormat.amd) => sdkLayout.weakAmdJsPath,
+ (true, ModuleFormat.ddc) => sdkLayout.soundDdcJsPath,
+ (false, ModuleFormat.ddc) => sdkLayout.weakDdcJsPath,
+ _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.')
+ };
+
+ String resolveSdkSourcemapPath({
+ required bool soundNullSafety,
+ required bool canaryFeatures,
+ }) =>
+ switch ((soundNullSafety, ddcModuleFormat)) {
+ (true, ModuleFormat.amd) => sdkLayout.soundAmdJsMapPath,
+ (false, ModuleFormat.amd) => sdkLayout.weakAmdJsMapPath,
+ (true, ModuleFormat.ddc) => sdkLayout.soundDdcJsMapPath,
+ (false, ModuleFormat.ddc) => sdkLayout.weakDdcJsMapPath,
+ _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.')
+ };
+
+ String resolveSdkJsFilename({
+ required bool soundNullSafety,
+ required bool canaryFeatures,
+ }) =>
+ switch ((soundNullSafety, ddcModuleFormat)) {
+ (true, ModuleFormat.amd) => sdkLayout.soundAmdJsFileName,
+ (false, ModuleFormat.amd) => sdkLayout.weakAmdJsFileName,
+ (true, ModuleFormat.ddc) => sdkLayout.soundDdcJsFileName,
+ (false, ModuleFormat.ddc) => sdkLayout.weakDdcJsFileName,
+ _ => throw Exception('Unsupported DDC module format $ddcModuleFormat.')
+ };
+
Future<void> _generateSdkJavaScript({
required bool soundNullSafety,
required bool canaryFeatures,
@@ -59,10 +98,10 @@
Directory? outputDir;
try {
// Files to copy generated files to.
- final outputJsPath =
- soundNullSafety ? sdkLayout.soundJsPath : sdkLayout.weakJsPath;
- final outputJsMapPath =
- soundNullSafety ? sdkLayout.soundJsMapPath : sdkLayout.weakJsMapPath;
+ final outputJsPath = resolveSdkJsPath(
+ soundNullSafety: soundNullSafety, canaryFeatures: canaryFeatures);
+ final outputJsMapPath = resolveSdkSourcemapPath(
+ soundNullSafety: soundNullSafety, canaryFeatures: canaryFeatures);
final outputFullDillPath = soundNullSafety
? sdkLayout.soundFullDillPath
: sdkLayout.weakFullDillPath;
@@ -79,9 +118,11 @@
outputDir = fileSystem.systemTempDirectory.createTempSync();
// Files to generate
- final jsPath = soundNullSafety
- ? p.join(outputDir.path, sdkLayout.soundJsFileName)
- : p.join(outputDir.path, sdkLayout.weakJsFileName);
+ final jsPath = p.join(
+ outputDir.path,
+ resolveSdkJsFilename(
+ soundNullSafety: soundNullSafety,
+ canaryFeatures: canaryFeatures));
final jsMapPath = p.setExtension(jsPath, '.js.map');
final fullDillPath = p.setExtension(jsPath, '.dill');
@@ -98,7 +139,7 @@
'--libraries-file',
'org-dartlang-sdk:///lib/libraries.json',
'--modules',
- 'amd',
+ ddcModuleFormat.name,
soundNullSafety ? '--sound-null-safety' : '--no-sound-null-safety',
'dart:core',
'-o',
@@ -241,12 +282,17 @@
Future<void> _moveAndValidate(String from, String to) async {
_logger.fine('Renaming $from to $to');
+ if (!_exists(from)) {
+ _logger.severe('Failed to generate SDK asset at $to');
+ throw Exception('File "$from" does not exist.');
+ }
+
if (_exists(to)) _delete(to);
await fileSystem.file(from).rename(to);
if (!_exists(to)) {
_logger.severe('Failed to generate SDK asset at $to');
- throw Exception('File does not exist.');
+ throw Exception('File "$to" does not exist.');
}
}
}
diff --git a/test_common/lib/test_sdk_configuration.dart b/test_common/lib/test_sdk_configuration.dart
index dbc6918..1fb9ec0 100644
--- a/test_common/lib/test_sdk_configuration.dart
+++ b/test_common/lib/test_sdk_configuration.dart
@@ -4,6 +4,7 @@
import 'dart:io';
+import 'package:dwds/expression_compiler.dart';
import 'package:dwds/sdk_configuration.dart';
import 'package:logging/logging.dart';
@@ -25,6 +26,7 @@
final bool _verbose;
final bool canaryFeatures;
+ final ModuleFormat ddcModuleFormat;
late final Directory _sdkDirectory;
SdkConfiguration? _configuration;
@@ -33,6 +35,7 @@
TestSdkConfigurationProvider({
this.canaryFeatures = false,
bool verbose = false,
+ this.ddcModuleFormat = ModuleFormat.amd,
}) : _verbose = verbose {
_sdkDirectory = Directory.systemTemp.createTempSync('sdk copy');
sdkLayout = TestSdkLayout.createDefault(_sdkDirectory.path);
@@ -62,6 +65,7 @@
sdkLayout: sdkLayout,
canaryFeatures: canaryFeatures,
verbose: _verbose,
+ ddcModuleFormat: ddcModuleFormat,
);
await assetGenerator.generateSdkAssets();
diff --git a/test_common/lib/test_sdk_layout.dart b/test_common/lib/test_sdk_layout.dart
index 9064ce8..8d90c48 100644
--- a/test_common/lib/test_sdk_layout.dart
+++ b/test_common/lib/test_sdk_layout.dart
@@ -13,8 +13,10 @@
/// We keep all the path constants in one place for ease of update.
class TestSdkLayout {
static final defaultSdkDirectory = SdkLayout.defaultSdkDirectory;
+
static TestSdkLayout defaultSdkLayout =
TestSdkLayout.createDefault(defaultSdkDirectory);
+
static SdkConfiguration defaultSdkConfiguration =
createConfiguration(defaultSdkLayout);
@@ -32,7 +34,7 @@
'_internal',
'ddc_platform.dill',
),
- soundJsPath: p.join(
+ soundAmdJsPath: p.join(
sdkLayout.sdkDirectory,
'lib',
'dev_compiler',
@@ -40,7 +42,7 @@
'amd',
'dart_sdk.js',
),
- soundJsMapPath: p.join(
+ soundAmdJsMapPath: p.join(
sdkLayout.sdkDirectory,
'lib',
'dev_compiler',
@@ -48,6 +50,22 @@
'amd',
'dart_sdk.js.map',
),
+ soundDdcJsPath: p.join(
+ sdkLayout.sdkDirectory,
+ 'lib',
+ 'dev_compiler',
+ 'kernel',
+ 'ddc',
+ 'dart_sdk.js',
+ ),
+ soundDdcJsMapPath: p.join(
+ sdkLayout.sdkDirectory,
+ 'lib',
+ 'dev_compiler',
+ 'kernel',
+ 'ddc',
+ 'dart_sdk.js.map',
+ ),
weakSummaryPath: sdkLayout.weakSummaryPath,
weakFullDillPath: p.join(
sdkLayout.sdkDirectory,
@@ -55,7 +73,7 @@
'_internal',
'ddc_platform_unsound.dill',
),
- weakJsPath: p.join(
+ weakAmdJsPath: p.join(
sdkLayout.sdkDirectory,
'lib',
'dev_compiler',
@@ -63,7 +81,7 @@
'amd',
'dart_sdk_unsound.js',
),
- weakJsMapPath: p.join(
+ weakAmdJsMapPath: p.join(
sdkLayout.sdkDirectory,
'lib',
'dev_compiler',
@@ -71,6 +89,29 @@
'amd',
'dart_sdk_unsound.js.map',
),
+ weakDdcJsPath: p.join(
+ sdkLayout.sdkDirectory,
+ 'lib',
+ 'dev_compiler',
+ 'kernel',
+ 'ddc',
+ 'dart_sdk_unsound.js',
+ ),
+ weakDdcJsMapPath: p.join(
+ sdkLayout.sdkDirectory,
+ 'lib',
+ 'dev_compiler',
+ 'kernel',
+ 'ddc',
+ 'dart_sdk_unsound.js.map',
+ ),
+ ddcModuleLoaderJsPath: p.join(
+ sdkLayout.sdkDirectory,
+ 'lib',
+ 'dev_compiler',
+ 'ddc',
+ 'ddc_module_loader.js',
+ ),
requireJsPath: p.join(
sdkLayout.sdkDirectory,
'lib',
@@ -118,26 +159,35 @@
final String sdkDirectory;
- String get soundJsFileName => p.basename(soundJsPath);
- String get soundJsMapFileName => p.basename(soundJsMapPath);
+ String get soundAmdJsFileName => p.basename(soundAmdJsPath);
+ String get soundAmdJsMapFileName => p.basename(soundAmdJsMapPath);
+ String get soundDdcJsFileName => p.basename(soundDdcJsPath);
+ String get soundDdcJsMapFileName => p.basename(soundDdcJsMapPath);
String get soundSummaryFileName => p.basename(soundSummaryPath);
String get soundFullDillFileName => p.basename(soundFullDillPath);
- final String soundJsPath;
- final String soundJsMapPath;
+ final String soundAmdJsPath;
+ final String soundAmdJsMapPath;
+ final String soundDdcJsPath;
+ final String soundDdcJsMapPath;
final String soundSummaryPath;
final String soundFullDillPath;
- String get weakJsFileName => p.basename(weakJsPath);
- String get weakJsMapFileName => p.basename(weakJsMapPath);
+ String get weakAmdJsFileName => p.basename(weakAmdJsPath);
+ String get weakAmdJsMapFileName => p.basename(weakAmdJsMapPath);
+ String get weakDdcJsFileName => p.basename(weakDdcJsPath);
+ String get weakDdcJsMapFileName => p.basename(weakDdcJsMapPath);
String get weakSummaryFileName => p.basename(weakSummaryPath);
String get weakFullDillFileName => p.basename(weakFullDillPath);
- final String weakJsPath;
- final String weakJsMapPath;
+ final String weakAmdJsPath;
+ final String weakAmdJsMapPath;
+ final String weakDdcJsPath;
+ final String weakDdcJsMapPath;
final String weakSummaryPath;
final String weakFullDillPath;
+ final String ddcModuleLoaderJsPath;
final String requireJsPath;
final String stackTraceMapperPath;
@@ -150,14 +200,19 @@
const TestSdkLayout({
required this.sdkDirectory,
- required this.soundJsPath,
- required this.soundJsMapPath,
+ required this.soundAmdJsPath,
+ required this.soundAmdJsMapPath,
+ required this.soundDdcJsPath,
+ required this.soundDdcJsMapPath,
required this.soundSummaryPath,
required this.soundFullDillPath,
- required this.weakJsPath,
- required this.weakJsMapPath,
+ required this.weakAmdJsPath,
+ required this.weakAmdJsMapPath,
+ required this.weakDdcJsPath,
+ required this.weakDdcJsMapPath,
required this.weakSummaryPath,
required this.weakFullDillPath,
+ required this.ddcModuleLoaderJsPath,
required this.requireJsPath,
required this.stackTraceMapperPath,
required this.dartPath,
diff --git a/test_common/test/sdk_asset_generator_test.dart b/test_common/test/sdk_asset_generator_test.dart
index fcbcfa3..2d45cd0 100644
--- a/test_common/test/sdk_asset_generator_test.dart
+++ b/test_common/test/sdk_asset_generator_test.dart
@@ -7,6 +7,7 @@
import 'dart:io';
+import 'package:dwds/expression_compiler.dart';
import 'package:test/test.dart';
import 'package:test_common/logging.dart';
import 'package:test_common/sdk_asset_generator.dart';
@@ -23,14 +24,18 @@
// Missing sound assets
late String soundSdkFullDillPath;
- late String soundSdkJsPath;
- late String soundSdkJsMapPath;
+ late String soundAmdSdkJsPath;
+ late String soundAmdSdkJsMapPath;
+ late String soundDdcSdkJsPath;
+ late String soundDdcSdkJsMapPath;
// Missing weak assets
late String weakSdkSummaryPath;
late String weakSdkFullDillPath;
- late String weakSdkJsPath;
- late String weakSdkJsMapPath;
+ late String weakAmdSdkJsPath;
+ late String weakAmdSdkJsMapPath;
+ late String weakDdcSdkJsPath;
+ late String weakDdcSdkJsMapPath;
setUp(() async {
setCurrentLogWriter(debug: debug);
@@ -47,30 +52,39 @@
// Simulate missing sound assets.
soundSdkFullDillPath = copySdkLayout.soundFullDillPath;
- soundSdkJsPath = copySdkLayout.soundJsPath;
- soundSdkJsMapPath = copySdkLayout.soundJsMapPath;
+ soundAmdSdkJsPath = copySdkLayout.soundAmdJsPath;
+ soundAmdSdkJsMapPath = copySdkLayout.soundAmdJsMapPath;
+ soundDdcSdkJsPath = copySdkLayout.soundDdcJsPath;
+ soundDdcSdkJsMapPath = copySdkLayout.soundDdcJsMapPath;
_deleteIfExists(soundSdkFullDillPath);
- _deleteIfExists(soundSdkJsPath);
- _deleteIfExists(soundSdkJsMapPath);
+ _deleteIfExists(soundAmdSdkJsPath);
+ _deleteIfExists(soundAmdSdkJsMapPath);
+ _deleteIfExists(soundDdcSdkJsPath);
+ _deleteIfExists(soundDdcSdkJsMapPath);
// Simulate missing weak assets.
weakSdkSummaryPath = copySdkLayout.weakSummaryPath;
weakSdkFullDillPath = copySdkLayout.weakFullDillPath;
- weakSdkJsPath = copySdkLayout.weakJsPath;
- weakSdkJsMapPath = copySdkLayout.weakJsMapPath;
+ weakAmdSdkJsPath = copySdkLayout.weakAmdJsPath;
+ weakAmdSdkJsMapPath = copySdkLayout.weakAmdJsMapPath;
+ weakDdcSdkJsPath = copySdkLayout.weakDdcJsPath;
+ weakDdcSdkJsMapPath = copySdkLayout.weakDdcJsMapPath;
_deleteIfExists(weakSdkSummaryPath);
_deleteIfExists(weakSdkFullDillPath);
- _deleteIfExists(weakSdkJsPath);
- _deleteIfExists(weakSdkJsMapPath);
+ _deleteIfExists(weakAmdSdkJsPath);
+ _deleteIfExists(weakAmdSdkJsMapPath);
+ _deleteIfExists(weakDdcSdkJsPath);
+ _deleteIfExists(weakDdcSdkJsMapPath);
});
tearDown(() {
tempDir.deleteSync(recursive: true);
});
- test('Can generate missing SDK assets and validate SDK configuration',
+ test(
+ 'Can generate missing SDK assets and validate SDK configuration for the AMD module system',
() async {
final sdkLayout = TestSdkLayout.createDefault(sdkDirectory);
final configuration = TestSdkLayout.createConfiguration(sdkLayout);
@@ -79,6 +93,7 @@
sdkLayout: sdkLayout,
verbose: true,
canaryFeatures: false,
+ ddcModuleFormat: ModuleFormat.amd,
);
await assetGenerator.generateSdkAssets();
@@ -88,13 +103,13 @@
expect(sdkLayout.soundSummaryPath, equals(soundSdkSummaryPath));
expect(sdkLayout.soundFullDillPath, equals(soundSdkFullDillPath));
- expect(sdkLayout.soundJsPath, equals(soundSdkJsPath));
- expect(sdkLayout.soundJsMapPath, equals(soundSdkJsMapPath));
+ expect(sdkLayout.soundAmdJsPath, equals(soundAmdSdkJsPath));
+ expect(sdkLayout.soundAmdJsMapPath, equals(soundAmdSdkJsMapPath));
expect(sdkLayout.weakSummaryPath, equals(weakSdkSummaryPath));
expect(sdkLayout.weakFullDillPath, equals(weakSdkFullDillPath));
- expect(sdkLayout.weakJsPath, equals(weakSdkJsPath));
- expect(sdkLayout.weakJsMapPath, equals(weakSdkJsMapPath));
+ expect(sdkLayout.weakAmdJsPath, equals(weakAmdSdkJsPath));
+ expect(sdkLayout.weakAmdJsMapPath, equals(weakAmdSdkJsMapPath));
// Validate that configuration files exist.
configuration.validateSdkDir();
@@ -103,13 +118,57 @@
// Validate all assets exist.
expect(sdkLayout.soundSummaryPath, _exists);
expect(sdkLayout.soundFullDillPath, _exists);
- expect(sdkLayout.soundJsPath, _exists);
- expect(sdkLayout.soundJsMapPath, _exists);
+ expect(sdkLayout.soundAmdJsPath, _exists);
+ expect(sdkLayout.soundAmdJsMapPath, _exists);
expect(sdkLayout.weakSummaryPath, _exists);
expect(sdkLayout.weakFullDillPath, _exists);
- expect(sdkLayout.weakJsPath, _exists);
- expect(sdkLayout.weakJsMapPath, _exists);
+ expect(sdkLayout.weakAmdJsPath, _exists);
+ expect(sdkLayout.weakAmdJsMapPath, _exists);
+ });
+
+ test(
+ 'Can generate missing SDK assets and validate SDK configuration for the DDC module system',
+ () async {
+ final sdkLayout = TestSdkLayout.createDefault(sdkDirectory);
+ final configuration = TestSdkLayout.createConfiguration(sdkLayout);
+
+ final assetGenerator = SdkAssetGenerator(
+ sdkLayout: sdkLayout,
+ verbose: true,
+ canaryFeatures: false,
+ ddcModuleFormat: ModuleFormat.ddc,
+ );
+ await assetGenerator.generateSdkAssets();
+
+ // Make sure SDK configuration and asset generator agree on the file paths.
+ expect(configuration.sdkDirectory, equals(sdkDirectory));
+ expect(configuration.compilerWorkerPath, equals(compilerWorkerPath));
+
+ expect(sdkLayout.soundSummaryPath, equals(soundSdkSummaryPath));
+ expect(sdkLayout.soundFullDillPath, equals(soundSdkFullDillPath));
+ expect(sdkLayout.soundDdcJsPath, equals(soundDdcSdkJsPath));
+ expect(sdkLayout.soundDdcJsMapPath, equals(soundDdcSdkJsMapPath));
+
+ expect(sdkLayout.weakSummaryPath, equals(weakSdkSummaryPath));
+ expect(sdkLayout.weakFullDillPath, equals(weakSdkFullDillPath));
+ expect(sdkLayout.weakDdcJsPath, equals(weakDdcSdkJsPath));
+ expect(sdkLayout.weakDdcJsMapPath, equals(weakDdcSdkJsMapPath));
+
+ // Validate that configuration files exist.
+ configuration.validateSdkDir();
+ configuration.validate();
+
+ // Validate all assets exist.
+ expect(sdkLayout.soundSummaryPath, _exists);
+ expect(sdkLayout.soundFullDillPath, _exists);
+ expect(sdkLayout.soundDdcJsPath, _exists);
+ expect(sdkLayout.soundDdcJsMapPath, _exists);
+
+ expect(sdkLayout.weakSummaryPath, _exists);
+ expect(sdkLayout.weakFullDillPath, _exists);
+ expect(sdkLayout.weakDdcJsPath, _exists);
+ expect(sdkLayout.weakDdcJsMapPath, _exists);
});
test('Can generate missing SDK assets with canary features enabled',
@@ -120,13 +179,34 @@
sdkLayout: sdkLayout,
verbose: true,
canaryFeatures: true,
+ ddcModuleFormat: ModuleFormat.amd,
);
await assetGenerator.generateSdkAssets();
- final soundSdk = File(soundSdkJsPath).readAsStringSync();
+ final soundSdk = File(soundAmdSdkJsPath).readAsStringSync();
expect(soundSdk, contains('canary'));
- final weakSdk = File(weakSdkJsPath).readAsStringSync();
+ final weakSdk = File(weakAmdSdkJsPath).readAsStringSync();
+ expect(weakSdk, contains('canary'));
+ });
+
+ test(
+ 'Can generate missing SDK assets with canary features enabled for the DDC module system',
+ () async {
+ final sdkLayout = TestSdkLayout.createDefault(sdkDirectory);
+
+ final assetGenerator = SdkAssetGenerator(
+ sdkLayout: sdkLayout,
+ verbose: true,
+ canaryFeatures: true,
+ ddcModuleFormat: ModuleFormat.ddc,
+ );
+ await assetGenerator.generateSdkAssets();
+
+ final soundSdk = File(soundDdcSdkJsPath).readAsStringSync();
+ expect(soundSdk, contains('canary'));
+
+ final weakSdk = File(weakDdcSdkJsPath).readAsStringSync();
expect(weakSdk, contains('canary'));
});
});
diff --git a/test_common/test/test_sdk_configuration_test.dart b/test_common/test/test_sdk_configuration_test.dart
index 1ff60dd..3e95ac6 100644
--- a/test_common/test/test_sdk_configuration_test.dart
+++ b/test_common/test/test_sdk_configuration_test.dart
@@ -7,6 +7,7 @@
import 'dart:io';
+import 'package:dwds/expression_compiler.dart';
import 'package:test/test.dart';
import 'package:test_common/logging.dart';
import 'package:test_common/test_sdk_configuration.dart';
@@ -40,7 +41,45 @@
});
});
- group('Test SDK configuration |', () {
+ group('Test SDK configuration | DDC with DDC modules |', () {
+ setCurrentLogWriter(debug: debug);
+ final provider = TestSdkConfigurationProvider(
+ verbose: debug, ddcModuleFormat: ModuleFormat.ddc);
+ tearDownAll(provider.dispose);
+
+ test('Can validate configuration with generated assets', () async {
+ final sdkConfiguration = await provider.configuration;
+ sdkConfiguration.validateSdkDir();
+ sdkConfiguration.validate();
+ });
+
+ test('SDK layout exists', () async {
+ await provider.configuration;
+ final sdkLayout = provider.sdkLayout;
+
+ expect(sdkLayout.sdkDirectory, _directoryExists);
+ expect(sdkLayout.soundDdcJsPath, _fileExists);
+ expect(sdkLayout.soundDdcJsMapPath, _fileExists);
+ expect(sdkLayout.soundSummaryPath, _fileExists);
+ expect(sdkLayout.soundFullDillPath, _fileExists);
+
+ expect(sdkLayout.weakDdcJsPath, _fileExists);
+ expect(sdkLayout.weakDdcJsMapPath, _fileExists);
+ expect(sdkLayout.weakSummaryPath, _fileExists);
+ expect(sdkLayout.weakFullDillPath, _fileExists);
+
+ expect(sdkLayout.ddcModuleLoaderJsPath, _fileExists);
+ expect(sdkLayout.stackTraceMapperPath, _fileExists);
+
+ expect(sdkLayout.dartPath, _fileExists);
+ expect(sdkLayout.frontendServerSnapshotPath, _fileExists);
+ expect(sdkLayout.dartdevcSnapshotPath, _fileExists);
+ expect(sdkLayout.kernelWorkerSnapshotPath, _fileExists);
+ expect(sdkLayout.devToolsDirectory, _directoryExists);
+ });
+ });
+
+ group('Test SDK configuration | DDC with AMD modules |', () {
setCurrentLogWriter(debug: debug);
final provider = TestSdkConfigurationProvider(verbose: debug);
tearDownAll(provider.dispose);
@@ -56,13 +95,13 @@
final sdkLayout = provider.sdkLayout;
expect(sdkLayout.sdkDirectory, _directoryExists);
- expect(sdkLayout.soundJsPath, _fileExists);
- expect(sdkLayout.soundJsMapPath, _fileExists);
+ expect(sdkLayout.soundAmdJsPath, _fileExists);
+ expect(sdkLayout.soundAmdJsMapPath, _fileExists);
expect(sdkLayout.soundSummaryPath, _fileExists);
expect(sdkLayout.soundFullDillPath, _fileExists);
- expect(sdkLayout.weakJsPath, _fileExists);
- expect(sdkLayout.weakJsMapPath, _fileExists);
+ expect(sdkLayout.weakAmdJsPath, _fileExists);
+ expect(sdkLayout.weakAmdJsMapPath, _fileExists);
expect(sdkLayout.weakSummaryPath, _fileExists);
expect(sdkLayout.weakFullDillPath, _fileExists);