Listen for uncaught exceptions during loading of a web test suite in Chrome (flutter/engine#55166)
Without this the test runner will hang if the compiled test is invalid and unable to execute.
This commit is contained in:
parent
fdbad460a5
commit
96d24ff033
@ -75,6 +75,12 @@ abstract class Browser {
|
||||
/// with an error.
|
||||
Future<void> get onExit;
|
||||
|
||||
/// A future that completes if the browser is notified about an uncaught
|
||||
/// exception.
|
||||
///
|
||||
/// Returns `null` if the browser does not support this.
|
||||
Future<String>? get onUncaughtException => null;
|
||||
|
||||
/// Closes the browser
|
||||
///
|
||||
/// Returns the same [Future] as [onExit], except that it won't emit
|
||||
|
@ -20,6 +20,8 @@ import 'common.dart';
|
||||
import 'environment.dart';
|
||||
import 'package_lock.dart';
|
||||
|
||||
const String kBlankPageUrl = 'about:blank';
|
||||
|
||||
/// Provides an environment for desktop Chrome.
|
||||
class ChromeEnvironment implements BrowserEnvironment {
|
||||
ChromeEnvironment({
|
||||
@ -82,6 +84,7 @@ class Chrome extends Browser {
|
||||
required bool useDwarf,
|
||||
}) {
|
||||
final Completer<Uri> remoteDebuggerCompleter = Completer<Uri>.sync();
|
||||
final Completer<String> exceptionCompleter = Completer<String>();
|
||||
return Chrome._(BrowserProcess(() async {
|
||||
// A good source of various Chrome CLI options:
|
||||
// https://peter.sh/experiments/chromium-command-line-switches/
|
||||
@ -98,7 +101,7 @@ class Chrome extends Browser {
|
||||
final String dir = await generateUserDirectory(installation, useDwarf);
|
||||
final List<String> args = <String>[
|
||||
'--user-data-dir=$dir',
|
||||
url.toString(),
|
||||
kBlankPageUrl,
|
||||
if (!debug)
|
||||
'--headless',
|
||||
if (isChromeNoSandbox)
|
||||
@ -139,6 +142,8 @@ class Chrome extends Browser {
|
||||
final Process process =
|
||||
await _spawnChromiumProcess(installation.executable, args);
|
||||
|
||||
await setupChromiumTab(url, exceptionCompleter);
|
||||
|
||||
remoteDebuggerCompleter.complete(
|
||||
getRemoteDebuggerUrl(Uri.parse('http://localhost:$kDevtoolsPort')));
|
||||
|
||||
@ -146,10 +151,10 @@ class Chrome extends Browser {
|
||||
.then((_) => Directory(dir).deleteSync(recursive: true)));
|
||||
|
||||
return process;
|
||||
}), remoteDebuggerCompleter.future);
|
||||
}), remoteDebuggerCompleter.future, exceptionCompleter.future);
|
||||
}
|
||||
|
||||
Chrome._(this._process, this.remoteDebuggerUrl);
|
||||
Chrome._(this._process, this.remoteDebuggerUrl, this._onUncaughtException);
|
||||
|
||||
static Future<String> generateUserDirectory(
|
||||
BrowserInstallation installation,
|
||||
@ -211,12 +216,17 @@ class Chrome extends Browser {
|
||||
|
||||
final BrowserProcess _process;
|
||||
|
||||
final Future<String> _onUncaughtException;
|
||||
|
||||
@override
|
||||
final Future<Uri> remoteDebuggerUrl;
|
||||
|
||||
@override
|
||||
Future<void> get onExit => _process.onExit;
|
||||
|
||||
@override
|
||||
Future<String>? get onUncaughtException => _onUncaughtException;
|
||||
|
||||
@override
|
||||
Future<void> close() => _process.close();
|
||||
|
||||
@ -378,3 +388,28 @@ Future<Uri> getRemoteDebuggerUrl(Uri base) async {
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setupChromiumTab(
|
||||
Uri url, Completer<String> exceptionCompleter) async {
|
||||
final wip.ChromeConnection chromeConnection =
|
||||
wip.ChromeConnection('localhost', kDevtoolsPort);
|
||||
final wip.ChromeTab? chromeTab = await chromeConnection.getTab(
|
||||
(wip.ChromeTab chromeTab) => chromeTab.url == kBlankPageUrl);
|
||||
final wip.WipConnection wipConnection = await chromeTab!.connect();
|
||||
|
||||
await wipConnection.runtime.enable();
|
||||
|
||||
wipConnection.runtime.onExceptionThrown.listen(
|
||||
(wip.ExceptionThrownEvent event) {
|
||||
if (!exceptionCompleter.isCompleted) {
|
||||
final String text = event.exceptionDetails.text;
|
||||
final String? description = event.exceptionDetails.exception?.description;
|
||||
exceptionCompleter.complete('$text: $description');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
await wipConnection.page.enable();
|
||||
|
||||
await wipConnection.page.navigate(url.toString());
|
||||
}
|
||||
|
@ -1059,7 +1059,18 @@ class BrowserManager {
|
||||
}
|
||||
|
||||
_controllers.add(controller!);
|
||||
return await controller!.suite;
|
||||
|
||||
final List<Future<RunnerSuite>> futures = <Future<RunnerSuite>>[
|
||||
controller!.suite
|
||||
];
|
||||
if (_browser.onUncaughtException != null) {
|
||||
futures.add(_browser.onUncaughtException!.then<RunnerSuite>(
|
||||
(String error) =>
|
||||
throw Exception('Exception while loading suite: $error')));
|
||||
}
|
||||
|
||||
final RunnerSuite suite = await Future.any(futures);
|
||||
return suite;
|
||||
} catch (_) {
|
||||
closeIframe();
|
||||
rethrow;
|
||||
|
Loading…
x
Reference in New Issue
Block a user