| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview Mocha adapter for WebUI tests. |
| * 1) Uses `window.domAutomationController` to signal test completion |
| * (success or error) back to the WebUIMochaBrowserTest class instance. |
| * 2) Emits console messages as Mocha tests are making progress. |
| * |
| * To use, include mocha.js and mocha_adapter_simple.js along with the Mocha |
| * test code. |
| */ |
| |
| // Messages passed back to WebUIMochaBrowserTest C++ class. |
| enum TestStatus { |
| FAILURE = 'FAILURE', |
| SUCCESS = 'SUCCESS', |
| } |
| |
| function reportTestResult(test: Mocha.Test, err?: Error) { |
| // NOTE not using any particular schema |
| window.domAutomationController.send({ |
| fullTitle: test.fullTitle(), |
| duration: test.duration, |
| failureReason: err ? err.stack : undefined, |
| }); |
| } |
| |
| class WebUiMochaBrowserTestReporter extends Mocha.reporters.Base { |
| private indents_: number = 0; |
| |
| constructor(runner: Mocha.Runner, options: Mocha.MochaOptions) { |
| super(runner, options); |
| |
| const stats = runner.stats!; |
| |
| const constants = Mocha.Runner.constants; |
| runner |
| .once( |
| constants.EVENT_RUN_BEGIN, |
| () => { |
| console.info('start'); |
| }) |
| .on(constants.EVENT_SUITE_BEGIN, |
| () => { |
| this.increaseIndent_(); |
| }) |
| .on(constants.EVENT_SUITE_END, |
| () => { |
| this.decreaseIndent_(); |
| }) |
| .on(constants.EVENT_TEST_BEGIN, |
| test => { |
| console.info(`${this.indent_()}started: ${test.fullTitle()}`); |
| }) |
| .on(constants.EVENT_TEST_PASS, |
| test => { |
| console.info(`${this.indent_()} passed: ${test.fullTitle()}`); |
| |
| reportTestResult(test); |
| }) |
| .on(constants.EVENT_TEST_FAIL, |
| (test, err) => { |
| let message = `${this.indent_()} failed: ${test.fullTitle()}\n`; |
| |
| if (err.stack) { |
| message += err.stack; |
| } else { |
| message += err.toString(); |
| } |
| |
| console.info(message); |
| |
| reportTestResult(test, err); |
| }) |
| .once(constants.EVENT_RUN_END, () => { |
| console.info( |
| `end: ${stats.passes}/${stats.passes + stats.failures} ok`); |
| const success = stats.failures === 0 && stats.passes > 0; |
| console.info( |
| 'TEST all complete, status=' + (success ? 'PASS' : 'FAIL') + |
| ', duration=' + Math.round(stats.duration!) + 'ms'); |
| if (stats.failures + stats.passes === 0) { |
| console.info( |
| 'No tests were found. Look for any uncaught errors that might ' + |
| 'have caused this'); |
| } |
| window.domAutomationController.send( |
| success ? TestStatus.SUCCESS : TestStatus.FAILURE); |
| }); |
| } |
| |
| private indent_() { |
| return Array(this.indents_).join(' '); |
| } |
| |
| private increaseIndent_() { |
| this.indents_++; |
| } |
| |
| private decreaseIndent_() { |
| this.indents_--; |
| } |
| } |
| |
| // Helper function provided to make running a single Mocha test more robust. |
| function runMochaTest(suiteName: string, testName: string) { |
| const escapedTestName = testName.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); |
| mocha.grep(new RegExp('^' + suiteName + ' ' + escapedTestName + '$')).run(); |
| } |
| |
| // Helper function provided to make running a single Mocha suite more robust. |
| function runMochaSuite(suiteName: string) { |
| mocha.grep(new RegExp('^' + suiteName + ' ')).run(); |
| } |
| |
| Object.assign(window, {runMochaSuite, runMochaTest}); |
| |
| // Configure mocha. |
| mocha.setup({ |
| // Use TDD interface instead of BDD. |
| ui: 'tdd', |
| // Use custom reporter to interface with WebUIMochaBrowserTest C++ class. |
| reporter: WebUiMochaBrowserTestReporter, |
| // Mocha timeouts are set to 2 seconds initially. This isn't nearly enough for |
| // slower bots (e.g., Dr. Memory). Disable timeouts globally, because the C++ |
| // will handle it (and has scaled timeouts for slower bots). |
| timeout: '0', |
| }); |