From ded4a294f44b43ade0cd69056759b350dc403dfe Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Wed, 7 Jun 2023 23:00:57 -0700 Subject: [PATCH] fix(merge): populate TestResult.stdout/stderr when merging (#23587) --- .../src/isomorphic/teleReceiver.ts | 11 +++- .../src/reporters/teleEmitter.ts | 6 +- tests/playwright-test/reporter-blob.spec.ts | 63 ++++++++++++++++++- 3 files changed, 73 insertions(+), 7 deletions(-) diff --git a/packages/playwright-test/src/isomorphic/teleReceiver.ts b/packages/playwright-test/src/isomorphic/teleReceiver.ts index 40515f6469..8a99bf6f58 100644 --- a/packages/playwright-test/src/isomorphic/teleReceiver.ts +++ b/packages/playwright-test/src/isomorphic/teleReceiver.ts @@ -24,6 +24,8 @@ export type JsonLocation = Location; export type JsonError = string; export type JsonStackFrame = { file: string, line: number, column: number }; +export type JsonStdIOType = 'stdout' | 'stderr'; + export type JsonConfig = Pick & { listOnly: boolean; }; @@ -266,14 +268,17 @@ export class TeleReporterReceiver { this._reporter.onError?.(error); } - private _onStdIO(type: 'stdout' | 'stderr', testId: string | undefined, resultId: string | undefined, data: string, isBase64: boolean) { + private _onStdIO(type: JsonStdIOType, testId: string | undefined, resultId: string | undefined, data: string, isBase64: boolean) { const chunk = isBase64 ? ((globalThis as any).Buffer ? Buffer.from(data, 'base64') : atob(data)) : data; const test = testId ? this._tests.get(testId) : undefined; const result = test && resultId ? test.resultsMap.get(resultId) : undefined; - if (type === 'stdout') + if (type === 'stdout') { + result?.stdout.push(chunk); this._reporter.onStdOut?.(chunk, test, result); - else + } else { + result?.stderr.push(chunk); this._reporter.onStdErr?.(chunk, test, result); + } } private _onEnd(result: FullResult): Promise | undefined { diff --git a/packages/playwright-test/src/reporters/teleEmitter.ts b/packages/playwright-test/src/reporters/teleEmitter.ts index 5e9339d7b0..3a3eceac2c 100644 --- a/packages/playwright-test/src/reporters/teleEmitter.ts +++ b/packages/playwright-test/src/reporters/teleEmitter.ts @@ -20,7 +20,7 @@ import type { SuitePrivate } from '../../types/reporterPrivate'; import type { FullConfig, FullResult, Location, Reporter, TestError, TestResult, TestStep } from '../../types/testReporter'; import { FullConfigInternal, FullProjectInternal } from '../common/config'; import type { Suite, TestCase } from '../common/test'; -import type { JsonConfig, JsonEvent, JsonProject, JsonSuite, JsonTestCase, JsonTestEnd, JsonTestResultEnd, JsonTestResultStart, JsonTestStepEnd, JsonTestStepStart } from '../isomorphic/teleReceiver'; +import type { JsonConfig, JsonEvent, JsonProject, JsonStdIOType, JsonSuite, JsonTestCase, JsonTestEnd, JsonTestResultEnd, JsonTestResultStart, JsonTestStepEnd, JsonTestStepStart } from '../isomorphic/teleReceiver'; import { serializeRegexPatterns } from '../isomorphic/teleReceiver'; export class TeleReporterEmitter implements Reporter { @@ -95,14 +95,14 @@ export class TeleReporterEmitter implements Reporter { } onStdOut(chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void { - this._onStdIO('stdio', chunk, test, result); + this._onStdIO('stdout', chunk, test, result); } onStdErr(chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void { this._onStdIO('stderr', chunk, test, result); } - private _onStdIO(type: 'stdio' | 'stderr', chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void { + private _onStdIO(type: JsonStdIOType, chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void { const isBase64 = typeof chunk !== 'string'; const data = isBase64 ? chunk.toString('base64') : chunk; this._messageSink({ diff --git a/tests/playwright-test/reporter-blob.spec.ts b/tests/playwright-test/reporter-blob.spec.ts index 08100bff62..32d3226b23 100644 --- a/tests/playwright-test/reporter-blob.spec.ts +++ b/tests/playwright-test/reporter-blob.spec.ts @@ -314,7 +314,6 @@ test('total time is from test run not from merge', async ({ runInlineTest, merge expect(exitCode).toBe(0); expect(output).toContain('To open last HTML report run:'); - // console.log(output); await showReport(); @@ -886,6 +885,68 @@ test('preserve config fields', async ({ runInlineTest, mergeReports }) => { expect(json.quiet).toEqual(mergeConfig.quiet); }); +test('preserve stdout and stderr', async ({ runInlineTest, mergeReports }) => { + const reportDir = test.info().outputPath('blob-report'); + const files = { + 'echo-reporter.js': ` + import fs from 'fs'; + + class EchoReporter { + log = []; + onStdOut(chunk, test, result) { + this.log.push('onStdOut: ' + chunk); + this.log.push('result.stdout: ' + result.stdout); + } + onStdErr(chunk, test, result) { + this.log.push('onStdErr: ' + chunk); + this.log.push('result.stderr: ' + result.stderr); + } + onTestEnd(test, result) { + this.log.push('onTestEnd'); + this.log.push('result.stdout: ' + result.stdout); + this.log.push('result.stderr: ' + result.stderr); + } + onEnd() { + fs.writeFileSync('log.txt', this.log.join('\\n')); + } + } + module.exports = EchoReporter; + `, + 'playwright.config.js': ` + module.exports = { + reporter: [['blob']] + }; + `, + 'a.test.js': ` + import { test, expect } from '@playwright/test'; + test('a test', async ({}) => { + expect(1 + 1).toBe(2); + console.log('stdout text'); + console.error('stderr text'); + }); + `, + }; + + await runInlineTest(files); + + const { exitCode } = await mergeReports(reportDir, {}, { additionalArgs: ['--reporter', test.info().outputPath('echo-reporter.js')] }); + expect(exitCode).toBe(0); + const log = fs.readFileSync(test.info().outputPath('log.txt')).toString(); + expect(log).toBe(`onStdOut: stdout text + +result.stdout: stdout text + +onStdErr: stderr text + +result.stderr: stderr text + +onTestEnd +result.stdout: stdout text + +result.stderr: stderr text +`); +}); + test('preserve steps in html report', async ({ runInlineTest, mergeReports, showReport, page }) => { const reportDir = test.info().outputPath('blob-report'); const files = {