diff --git a/dwds/test/devtools_test.dart b/dwds/test/devtools_test.dart index 66422ce7f..76dda874f 100644 --- a/dwds/test/devtools_test.dart +++ b/dwds/test/devtools_test.dart @@ -102,7 +102,11 @@ void main() { // https://github.com/dart-lang/webdev/pull/901#issuecomment-586438132 final client = context.debugConnection.vmService; await client.streamListen('Isolate'); - await context.changeInput(); + context.makeEditToDartEntryFile( + toReplace: 'Hello World!', + replaceWith: 'Bonjour le monde!', + ); + await context.waitForSuccessfulBuild(propogateToBrowser: true); final eventsDone = expectLater( client.onIsolateEvent, @@ -115,6 +119,11 @@ void main() { await context.webDriver.driver.refresh(); await eventsDone; + // Re-set the edited file: + context.makeEditToDartEntryFile( + toReplace: 'Bonjour le monde!', + replaceWith: 'Hello World!', + ); }); }); diff --git a/dwds/test/fixtures/context.dart b/dwds/test/fixtures/context.dart index ff62190ad..187e61979 100644 --- a/dwds/test/fixtures/context.dart +++ b/dwds/test/fixtures/context.dart @@ -77,19 +77,14 @@ class TestContext { return webCompatiblePath([...pathParts, htmlEntryFileName]); } - /// The entry file is the Dart entry file, e.g, + /// The path to the Dart entry file, e.g, /// "/workstation/webdev/fixtures/_testSound/example/hello_world/main.dart": - File get _entryFile => File( - absolutePath( - pathFromFixtures: p.joinAll( - [packageName, webAssetsPath, dartEntryFileName], - ), + String get _dartEntryFilePath => absolutePath( + pathFromFixtures: p.joinAll( + [packageName, webAssetsPath, dartEntryFileName], ), ); - /// The contents of the Dart entry file: - String get _entryContents => _entryFile.readAsStringSync(); - /// The URI for the package_config.json is located in: /// /.dart_tool/package_config Uri get _packageConfigFile => @@ -183,7 +178,7 @@ class TestContext { _logger.info('Serving: $directoryToServe/$filePathToServe'); _logger.info('Project: $workingDirectory'); _logger.info('Packages: $_packageConfigFile'); - _logger.info('Entry: ${_entryFile.path}'); + _logger.info('Entry: $_dartEntryFilePath'); } Future setUp({ @@ -291,10 +286,7 @@ class TestContext { DefaultBuildTarget((b) => b..target = directoryToServe)); daemonClient.startBuild(); - await daemonClient.buildResults - .firstWhere((results) => results.results - .any((result) => result.status == BuildStatus.succeeded)) - .timeout(const Duration(seconds: 60)); + await waitForSuccessfulBuild(); final assetServerPort = daemonPort(workingDirectory); _assetHandler = proxyHandler( @@ -467,7 +459,6 @@ class TestContext { await _webDriver?.quit(closeSession: true); _chromeDriver?.kill(); DartUri.currentDirectory = p.current; - _entryFile.writeAsStringSync(_entryContents); await _daemonClient?.close(); await ddcService?.stop(); await _webRunner?.stop(); @@ -487,20 +478,31 @@ class TestContext { _outputDir = null; } - Future changeInput() async { - _entryFile.writeAsStringSync( - _entryContents.replaceAll('Hello World!', 'Gary is awesome!')); - - // Wait for the build. - await _daemonClient?.buildResults.firstWhere((results) => results.results - .any((result) => result.status == BuildStatus.succeeded)); + void makeEditToDartEntryFile({ + required String toReplace, + required String replaceWith, + }) async { + final file = File(_dartEntryFilePath); + final fileContents = file.readAsStringSync(); + file.writeAsStringSync(fileContents.replaceAll(toReplace, replaceWith)); + } - // Allow change to propagate to the browser. - // Windows, or at least Travis on Windows, seems to need more time. - final delay = Platform.isWindows - ? const Duration(seconds: 5) - : const Duration(seconds: 2); - await Future.delayed(delay); + Future waitForSuccessfulBuild( + {Duration? timeout, bool propogateToBrowser = false}) async { + // Wait for the build until the timeout is reached: + await daemonClient.buildResults + .firstWhere((results) => results.results + .any((result) => result.status == BuildStatus.succeeded)) + .timeout(timeout ?? const Duration(seconds: 60)); + + if (propogateToBrowser) { + // Allow change to propagate to the browser. + // Windows, or at least Travis on Windows, seems to need more time. + final delay = Platform.isWindows + ? const Duration(seconds: 5) + : const Duration(seconds: 2); + await Future.delayed(delay); + } } Future _buildDebugExtension() async { diff --git a/dwds/test/reload_test.dart b/dwds/test/reload_test.dart index 9c0815fa1..d50f0d0fb 100644 --- a/dwds/test/reload_test.dart +++ b/dwds/test/reload_test.dart @@ -2,7 +2,6 @@ // 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. -@Skip('https://github.com/dart-lang/webdev/issues/1845 - Move to cron job.') @TestOn('vm') @Timeout(Duration(minutes: 5)) import 'package:dwds/src/loaders/strategy.dart'; @@ -19,6 +18,9 @@ final context = TestContext.withSoundNullSafety( htmlEntryFileName: 'index.html', ); +const originalString = 'Hello World!'; +const newString = 'Bonjour le monde!'; + void main() { // set to true for debug logging. final debug = false; @@ -32,17 +34,17 @@ void main() { }); tearDown(() async { + undoEdit(); await context.tearDown(); }); test('can live reload changes ', () async { - await context.changeInput(); - + await makeEditAndWaitForRebuild(); final source = await context.webDriver.pageSource; // A full reload should clear the state. - expect(source.contains('Hello World!'), isFalse); - expect(source.contains('Gary is awesome!'), isTrue); + expect(source.contains(originalString), isFalse); + expect(source.contains(newString), isTrue); }); }); @@ -56,17 +58,18 @@ void main() { }); tearDown(() async { + undoEdit(); await context.tearDown(); }); test('can live reload changes ', () async { - await context.changeInput(); + await makeEditAndWaitForRebuild(); final source = await context.webDriver.pageSource; // A full reload should clear the state. - expect(source.contains('Hello World!'), isFalse); - expect(source.contains('Gary is awesome!'), isTrue); + expect(source.contains(originalString), isFalse); + expect(source.contains(newString), isTrue); }); }); @@ -82,16 +85,17 @@ void main() { tearDown(() async { await context.tearDown(); + undoEdit(); }); test('can live reload changes ', () async { - await context.changeInput(); + await makeEditAndWaitForRebuild(); final source = await context.webDriver.pageSource; // A full reload should clear the state. - expect(source.contains('Hello World!'), isFalse); - expect(source.contains('Gary is awesome!'), isTrue); + expect(source.contains(originalString), isFalse); + expect(source.contains(newString), isTrue); }); }); }); @@ -104,12 +108,13 @@ void main() { 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 context.changeInput(); + await makeEditAndWaitForRebuild(); final eventsDone = expectLater( client.onIsolateEvent, @@ -128,7 +133,7 @@ void main() { test('destroys and recreates the isolate during a page refresh', () async { final client = context.debugConnection.vmService; await client.streamListen('Isolate'); - await context.changeInput(); + await makeEditAndWaitForRebuild(); final eventsDone = expectLater( client.onIsolateEvent, @@ -146,7 +151,7 @@ void main() { test('can hot restart via the service extension', () async { final client = context.debugConnection.vmService; await client.streamListen('Isolate'); - await context.changeInput(); + await makeEditAndWaitForRebuild(); final eventsDone = expectLater( client.onIsolateEvent, @@ -163,8 +168,8 @@ void main() { final source = await context.webDriver.pageSource; // Main is re-invoked which shouldn't clear the state. - expect(source, contains('Hello World!')); - expect(source, contains('Gary is awesome!')); + expect(source, contains(originalString)); + expect(source, contains(newString)); }); test('can send events before and after hot restart', () async { @@ -218,7 +223,7 @@ void main() { test('can refresh the page via the fullReload service extension', () async { final client = context.debugConnection.vmService; await client.streamListen('Isolate'); - await context.changeInput(); + await makeEditAndWaitForRebuild(); final eventsDone = expectLater( client.onIsolateEvent, @@ -234,8 +239,8 @@ void main() { final source = await context.webDriver.pageSource; // Should see only the new text - expect(source, isNot(contains('Hello World!'))); - expect(source, contains('Gary is awesome!')); + expect(source.contains(originalString), isFalse); + expect(source.contains(newString), isTrue); }); test('can hot restart while paused', () async { @@ -253,13 +258,13 @@ void main() { await stream .firstWhere((event) => event.kind == EventKind.kPauseBreakpoint); - await context.changeInput(); + 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('Hello World!'), isTrue); - expect(source.contains('Gary is awesome!'), isTrue); + expect(source.contains(originalString), isTrue); + expect(source.contains(newString), isTrue); vm = await client.getVM(); isolateId = vm.isolates!.first.id!; @@ -336,19 +341,20 @@ void main() { tearDown(() async { await context.tearDown(); + undoEdit(); }); test('can hot restart changes ', () async { - await context.changeInput(); + await makeEditAndWaitForRebuild(); final source = await context.webDriver.pageSource; // Main is re-invoked which shouldn't clear the state. - expect(source.contains('Hello World!'), isTrue); - expect(source.contains('Gary is awesome!'), isTrue); + 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 Gary is awesome')); + expect( + source, contains('start disassemble end disassemble $newString')); }); test('fires isolate create/destroy events during hot restart', () async { @@ -363,7 +369,7 @@ void main() { _hasKind(EventKind.kIsolateRunnable), ]))); - await context.changeInput(); + await makeEditAndWaitForRebuild(); await eventsDone; }); @@ -380,23 +386,39 @@ void main() { tearDown(() async { await context.tearDown(); + undoEdit(); }); test('can hot restart changes ', () async { - await context.changeInput(); + await makeEditAndWaitForRebuild(); final source = await context.webDriver.pageSource; // Main is re-invoked which shouldn't clear the state. - expect(source.contains('Hello World!'), isTrue); - expect(source.contains('Gary is awesome!'), isTrue); + 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 Gary is awesome')); + expect( + source, contains('start disassemble end disassemble $newString')); }); }); }); } +Future makeEditAndWaitForRebuild() async { + context.makeEditToDartEntryFile( + toReplace: originalString, + replaceWith: newString, + ); + await context.waitForSuccessfulBuild(propogateToBrowser: true); +} + +void undoEdit() { + context.makeEditToDartEntryFile( + toReplace: newString, + replaceWith: originalString, + ); +} + TypeMatcher _hasKind(String kind) => isA().having((e) => e.kind, 'kind', kind);