Skip to content

Re-enable reload_tests #1877

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion dwds/test/devtools_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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!',
);
});
});

Expand Down
58 changes: 30 additions & 28 deletions dwds/test/fixtures/context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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:
/// <project directory>/.dart_tool/package_config
Uri get _packageConfigFile =>
Expand Down Expand Up @@ -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<void> setUp({
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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();
Expand All @@ -487,20 +478,31 @@ class TestContext {
_outputDir = null;
}

Future<void> 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<void> 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<void> _buildDebugExtension() async {
Expand Down
88 changes: 55 additions & 33 deletions dwds/test/reload_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand All @@ -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);
});
});

Expand All @@ -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);
});
});

Expand All @@ -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);
});
});
});
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand All @@ -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!;
Expand Down Expand Up @@ -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 {
Expand All @@ -363,7 +369,7 @@ void main() {
_hasKind(EventKind.kIsolateRunnable),
])));

await context.changeInput();
await makeEditAndWaitForRebuild();

await eventsDone;
});
Expand All @@ -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<void> makeEditAndWaitForRebuild() async {
context.makeEditToDartEntryFile(
toReplace: originalString,
replaceWith: newString,
);
await context.waitForSuccessfulBuild(propogateToBrowser: true);
}

void undoEdit() {
context.makeEditToDartEntryFile(
toReplace: newString,
replaceWith: originalString,
);
}

TypeMatcher<Event> _hasKind(String kind) =>
isA<Event>().having((e) => e.kind, 'kind', kind);