diff --git a/pkg/unittest/html_config.dart b/pkg/unittest/html_config.dart index 28e16ab12e0..3f74e2f804e 100644 --- a/pkg/unittest/html_config.dart +++ b/pkg/unittest/html_config.dart @@ -20,22 +20,35 @@ class HtmlConfiguration extends Configuration { // TODO(rnystrom): Get rid of this if we get canonical closures for methods. EventListener _onErrorClosure; + void _installErrorHandler() { + if (_onErrorClosure == null) { + _onErrorClosure = + (e) => handleExternalError(e, '(DOM callback has errors)'); + // Listen for uncaught errors. + window.on.error.add(_onErrorClosure); + } + } + + void _uninstallErrorHandler() { + if (_onErrorClosure != null) { + window.on.error.remove(_onErrorClosure); + _onErrorClosure = null; + } + } + void onInit() { - _onErrorClosure = - (e) => handleExternalError(e, '(DOM callback has errors)'); + _installErrorHandler(); } void onStart() { window.postMessage('unittest-suite-wait-for-done', '*'); - // Listen for uncaught errors. - window.on.error.add(_onErrorClosure); } void onTestResult(TestCase testCase) {} void onDone(int passed, int failed, int errors, List results, String uncaughtError) { - window.on.error.remove(_onErrorClosure); + _uninstallErrorHandler(); _showResultsInPage(passed, failed, errors, results, _isLayoutTest, uncaughtError); window.postMessage('unittest-suite-done', '*'); diff --git a/pkg/unittest/html_enhanced_config.dart b/pkg/unittest/html_enhanced_config.dart index 558ef4a9d05..d24671f97d2 100644 --- a/pkg/unittest/html_enhanced_config.dart +++ b/pkg/unittest/html_enhanced_config.dart @@ -22,7 +22,24 @@ class HtmlEnhancedConfiguration extends Configuration { // TODO(rnystrom): Get rid of this if we get canonical closures for methods. EventListener _onErrorClosure; + void _installErrorHandler() { + if (_onErrorClosure == null) { + _onErrorClosure = + (e) => handleExternalError(e, '(DOM callback has errors)'); + // Listen for uncaught errors. + window.on.error.add(_onErrorClosure); + } + } + + void _uninstallErrorHandler() { + if (_onErrorClosure != null) { + window.on.error.remove(_onErrorClosure); + _onErrorClosure = null; + } + } + void onInit() { + _installErrorHandler(); //initialize and load CSS final String _CSSID = '_unittestcss_'; @@ -34,9 +51,6 @@ class HtmlEnhancedConfiguration extends Configuration { } cssElement.innerHTML = _htmlTestCSS; - - _onErrorClosure = - (e) => handleExternalError(e, '(DOM callback has errors)'); } void onStart() { @@ -49,7 +63,7 @@ class HtmlEnhancedConfiguration extends Configuration { void onDone(int passed, int failed, int errors, List results, String uncaughtError) { - window.on.error.remove(_onErrorClosure); + _uninstallErrorHandler(); _showInteractiveResultsInPage(passed, failed, errors, results, _isLayoutTest, uncaughtError); diff --git a/pkg/unittest/interactive_html_config.dart b/pkg/unittest/interactive_html_config.dart index 3443ab85aeb..3780ea14228 100644 --- a/pkg/unittest/interactive_html_config.dart +++ b/pkg/unittest/interactive_html_config.dart @@ -51,15 +51,35 @@ class _Message { String toString() => text(messageType, elapsed, body); } + +class HtmlConfiguration extends Configuration { + // TODO(rnystrom): Get rid of this if we get canonical closures for methods. + EventListener _onErrorClosure; + + void _installErrorHandler() { + if (_onErrorClosure == null) { + _onErrorClosure = + (e) => handleExternalError(e, '(DOM callback has errors)'); + // Listen for uncaught errors. + window.on.error.add(_onErrorClosure); + } + } + + void _uninstallErrorHandler() { + if (_onErrorClosure != null) { + window.on.error.remove(_onErrorClosure); + _onErrorClosure = null; + } + } +} + /** * The child configuration that is used to run individual tests in * an IFrame and post the results back to the parent. In principle * this can run more than one test in the IFrame but currently only * one is used. */ -class ChildInteractiveHtmlConfiguration extends Configuration { - // TODO(rnystrom): Get rid of this if we get canonical closures for methods. - EventListener _onErrorClosure; +class ChildInteractiveHtmlConfiguration extends HtmlConfiguration { /** The window to which results must be posted. */ Window parentWindow; @@ -74,8 +94,7 @@ class ChildInteractiveHtmlConfiguration extends Configuration { get autoStart => false; void onInit() { - _onErrorClosure = - (e) => handleExternalError(e, '(DOM callback has errors)'); + _installErrorHandler(); /** * The parent posts a 'start' message to kick things off, @@ -99,8 +118,7 @@ class ChildInteractiveHtmlConfiguration extends Configuration { } void onStart() { - // Listen for uncaught errors. - window.on.error.add(_onErrorClosure); + _installErrorHandler(); } /** Record the start time of the test. */ @@ -145,7 +163,7 @@ class ChildInteractiveHtmlConfiguration extends Configuration { void onDone(int passed, int failed, int errors, List results, String uncaughtError) { - window.on.error.remove(_onErrorClosure); + _uninstallErrorHandler(); } } @@ -153,10 +171,9 @@ class ChildInteractiveHtmlConfiguration extends Configuration { * The parent configuration runs in the top-level window; it wraps the tests * in new functions that create child IFrames and run the real tests. */ -class ParentInteractiveHtmlConfiguration extends Configuration { +class ParentInteractiveHtmlConfiguration extends HtmlConfiguration { Map _testStarts; - // TODO(rnystrom): Get rid of this if we get canonical closures for methods. - EventListener _onErrorClosure; + /** The stack that was posted back from the child, if any. */ String _stack; @@ -223,15 +240,13 @@ class ParentInteractiveHtmlConfiguration extends Configuration { } void onInit() { + _installErrorHandler(); _messageHandler = _handleMessage; // We need to make just one closure. - _onErrorClosure = - (e) => handleExternalError(e, '(DOM callback has errors)'); document.query('#group-divs').innerHTML = ""; } void onStart() { - // Listen for uncaught errors. - window.on.error.add(_onErrorClosure); + _installErrorHandler(); if (!_doneWrap) { _doneWrap = true; for (int i = 0; i < testCases.length; i++) { @@ -395,7 +410,7 @@ class ParentInteractiveHtmlConfiguration extends Configuration { void onDone(int passed, int failed, int errors, List results, String uncaughtError) { window.on.message.remove(_messageHandler); - window.on.error.remove(_onErrorClosure); + _uninstallErrorHandler(); document.query('#busy').style.display = 'none'; InputElement startButton = document.query('#start'); startButton.disabled = false;