diff --git a/test/shared/mocha-extensions.ts b/test/shared/mocha-extensions.ts index 83ff14ee1c..a1ef4e4a78 100644 --- a/test/shared/mocha-extensions.ts +++ b/test/shared/mocha-extensions.ts @@ -32,16 +32,6 @@ export async function takeScreenshots(): Promise<{target?: string, frontend?: st } } -async function takeScreenshotsForError(): Promise<{target?: string, frontend?: string}> { - if (getEnvVar('LUCI_CONTEXT')) { - const screenshots = await takeScreenshots(); - console.error('Screenshots will be uploaded to luci-milo invocation.'); - return screenshots; - } - console.error('Screenshots skipped because we are not running under rdb; did you run `npm run auto-e2etest-rdb`?'); - return {}; -} - function wrapSuiteFunction(fn: (this: Mocha.Suite) => void) { return function(this: Mocha.Suite): void { const hookCreationHook = (hook: Mocha.Hook) => { @@ -144,7 +134,7 @@ async function timeoutHook(this: Mocha.Runnable, done: Mocha.Done|undefined, err } } if (err && !getEnvVar('DEBUG_TEST') && !(err instanceof ScreenshotError)) { - const {target, frontend} = await takeScreenshotsForError(); + const {target, frontend} = await takeScreenshots(); err = ScreenshotError.fromBase64Images(err, target, frontend); } if (done) { @@ -227,7 +217,7 @@ function wrapMochaCall( async function onError(this: unknown, err?: unknown) { const isTimeoutError = err instanceof Error && err.message?.includes(TIMEOUT_ERROR_MESSAGE); if (err && !getEnvVar('DEBUG_TEST') && !(err instanceof ScreenshotError) && !isTimeoutError) { - const {target, frontend} = await takeScreenshotsForError(); + const {target, frontend} = await takeScreenshots(); err = ScreenshotError.fromBase64Images(err, target, frontend); } done.call(this, err); diff --git a/test/shared/mocha-resultsdb-reporter.ts b/test/shared/mocha-resultsdb-reporter.ts index c1b632b604..3699861108 100644 --- a/test/shared/mocha-resultsdb-reporter.ts +++ b/test/shared/mocha-resultsdb-reporter.ts @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import * as fs from 'fs'; import * as Mocha from 'mocha'; +import * as path from 'path'; import { ScreenshotError, @@ -49,6 +51,12 @@ class ResultsDbReporter extends Mocha.reporters.Spec { // the rest of the HTML formatting (e.g.
and). static readonly SUMMARY_LENGTH_CUTOFF = 3985; private suitePrefix?: string; + htmlResult: fs.WriteStream|undefined; + + localResultsPath() { + return !ResultsDb.available() && this.suitePrefix ? path.join(__dirname, '..', this.suitePrefix, 'results.html') : + undefined; + } constructor(runner: Mocha.Runner, options?: Mocha.MochaOptions) { super(runner, options); @@ -56,6 +64,12 @@ class ResultsDbReporter extends Mocha.reporters.Spec { // BUT, every module.exports is forwarded onto the options object. this.suitePrefix = (options as {suiteName: string} | undefined)?.suiteName; + const localResults = this.localResultsPath(); + + if (localResults) { + this.htmlResult = fs.createWriteStream(localResults, {}); + } + runner.on(EVENT_TEST_PASS, this.onTestPass.bind(this)); runner.on(EVENT_TEST_FAIL, this.onTestFail.bind(this)); runner.on(EVENT_TEST_RETRY, this.onTestFail.bind(this)); @@ -78,6 +92,16 @@ class ResultsDbReporter extends Mocha.reporters.Spec { } else { testResult.summaryHtml = `
${getErrorMessage(error).slice(0, ResultsDbReporter.SUMMARY_LENGTH_CUTOFF)}`;
}
+ if (this.htmlResult) {
+ this.htmlResult.write(testResult.summaryHtml);
+ if (testResult.artifacts) {
+ for (const screenshot in testResult.artifacts) {
+ this.htmlResult.write(`