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.
|
/// with an error.
|
||||||
Future<void> get onExit;
|
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
|
/// Closes the browser
|
||||||
///
|
///
|
||||||
/// Returns the same [Future] as [onExit], except that it won't emit
|
/// Returns the same [Future] as [onExit], except that it won't emit
|
||||||
|
@ -20,6 +20,8 @@ import 'common.dart';
|
|||||||
import 'environment.dart';
|
import 'environment.dart';
|
||||||
import 'package_lock.dart';
|
import 'package_lock.dart';
|
||||||
|
|
||||||
|
const String kBlankPageUrl = 'about:blank';
|
||||||
|
|
||||||
/// Provides an environment for desktop Chrome.
|
/// Provides an environment for desktop Chrome.
|
||||||
class ChromeEnvironment implements BrowserEnvironment {
|
class ChromeEnvironment implements BrowserEnvironment {
|
||||||
ChromeEnvironment({
|
ChromeEnvironment({
|
||||||
@ -82,6 +84,7 @@ class Chrome extends Browser {
|
|||||||
required bool useDwarf,
|
required bool useDwarf,
|
||||||
}) {
|
}) {
|
||||||
final Completer<Uri> remoteDebuggerCompleter = Completer<Uri>.sync();
|
final Completer<Uri> remoteDebuggerCompleter = Completer<Uri>.sync();
|
||||||
|
final Completer<String> exceptionCompleter = Completer<String>();
|
||||||
return Chrome._(BrowserProcess(() async {
|
return Chrome._(BrowserProcess(() async {
|
||||||
// A good source of various Chrome CLI options:
|
// A good source of various Chrome CLI options:
|
||||||
// https://peter.sh/experiments/chromium-command-line-switches/
|
// https://peter.sh/experiments/chromium-command-line-switches/
|
||||||
@ -98,7 +101,7 @@ class Chrome extends Browser {
|
|||||||
final String dir = await generateUserDirectory(installation, useDwarf);
|
final String dir = await generateUserDirectory(installation, useDwarf);
|
||||||
final List<String> args = <String>[
|
final List<String> args = <String>[
|
||||||
'--user-data-dir=$dir',
|
'--user-data-dir=$dir',
|
||||||
url.toString(),
|
kBlankPageUrl,
|
||||||
if (!debug)
|
if (!debug)
|
||||||
'--headless',
|
'--headless',
|
||||||
if (isChromeNoSandbox)
|
if (isChromeNoSandbox)
|
||||||
@ -139,6 +142,8 @@ class Chrome extends Browser {
|
|||||||
final Process process =
|
final Process process =
|
||||||
await _spawnChromiumProcess(installation.executable, args);
|
await _spawnChromiumProcess(installation.executable, args);
|
||||||
|
|
||||||
|
await setupChromiumTab(url, exceptionCompleter);
|
||||||
|
|
||||||
remoteDebuggerCompleter.complete(
|
remoteDebuggerCompleter.complete(
|
||||||
getRemoteDebuggerUrl(Uri.parse('http://localhost:$kDevtoolsPort')));
|
getRemoteDebuggerUrl(Uri.parse('http://localhost:$kDevtoolsPort')));
|
||||||
|
|
||||||
@ -146,10 +151,10 @@ class Chrome extends Browser {
|
|||||||
.then((_) => Directory(dir).deleteSync(recursive: true)));
|
.then((_) => Directory(dir).deleteSync(recursive: true)));
|
||||||
|
|
||||||
return process;
|
return process;
|
||||||
}), remoteDebuggerCompleter.future);
|
}), remoteDebuggerCompleter.future, exceptionCompleter.future);
|
||||||
}
|
}
|
||||||
|
|
||||||
Chrome._(this._process, this.remoteDebuggerUrl);
|
Chrome._(this._process, this.remoteDebuggerUrl, this._onUncaughtException);
|
||||||
|
|
||||||
static Future<String> generateUserDirectory(
|
static Future<String> generateUserDirectory(
|
||||||
BrowserInstallation installation,
|
BrowserInstallation installation,
|
||||||
@ -211,12 +216,17 @@ class Chrome extends Browser {
|
|||||||
|
|
||||||
final BrowserProcess _process;
|
final BrowserProcess _process;
|
||||||
|
|
||||||
|
final Future<String> _onUncaughtException;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final Future<Uri> remoteDebuggerUrl;
|
final Future<Uri> remoteDebuggerUrl;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> get onExit => _process.onExit;
|
Future<void> get onExit => _process.onExit;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String>? get onUncaughtException => _onUncaughtException;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() => _process.close();
|
Future<void> close() => _process.close();
|
||||||
|
|
||||||
@ -378,3 +388,28 @@ Future<Uri> getRemoteDebuggerUrl(Uri base) async {
|
|||||||
return base;
|
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!);
|
_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 (_) {
|
} catch (_) {
|
||||||
closeIframe();
|
closeIframe();
|
||||||
rethrow;
|
rethrow;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user