From 6106ef020fd921d022f516c573de3c3cb412698b Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Wed, 22 Jan 2025 07:53:36 +0000 Subject: [PATCH] cherry-pick(#34410): fix(list reporter): do not break after output without trailing eol (#34412) --- packages/playwright/src/reporters/list.ts | 3 ++ packages/playwright/src/worker/workerMain.ts | 8 +++- .../playwright-test-fixtures.ts | 1 + tests/playwright-test/reporter-list.spec.ts | 45 +++++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/packages/playwright/src/reporters/list.ts b/packages/playwright/src/reporters/list.ts index 4f885946e52ce..aef9fcbe2ff5b 100644 --- a/packages/playwright/src/reporters/list.ts +++ b/packages/playwright/src/reporters/list.ts @@ -129,6 +129,8 @@ class ListReporter extends TerminalReporter { if (this._needNewLine) { this._needNewLine = false; process.stdout.write('\n'); + ++this._lastRow; + this._lastColumn = 0; } } @@ -210,6 +212,7 @@ class ListReporter extends TerminalReporter { process.stdout.write('\n'); } ++this._lastRow; + this._lastColumn = 0; } private _updateLine(row: number, text: string, prefix: string) { diff --git a/packages/playwright/src/worker/workerMain.ts b/packages/playwright/src/worker/workerMain.ts index ed323a701bb94..b4878ff659708 100644 --- a/packages/playwright/src/worker/workerMain.ts +++ b/packages/playwright/src/worker/workerMain.ts @@ -75,16 +75,20 @@ export class WorkerMain extends ProcessRunner { process.on('unhandledRejection', reason => this.unhandledError(reason)); process.on('uncaughtException', error => this.unhandledError(error)); - process.stdout.write = (chunk: string | Buffer) => { + process.stdout.write = (chunk: string | Buffer, cb?: any) => { this.dispatchEvent('stdOut', stdioChunkToParams(chunk)); this._currentTest?._tracing.appendStdioToTrace('stdout', chunk); + if (typeof cb === 'function') + process.nextTick(cb); return true; }; if (!process.env.PW_RUNNER_DEBUG) { - process.stderr.write = (chunk: string | Buffer) => { + process.stderr.write = (chunk: string | Buffer, cb?: any) => { this.dispatchEvent('stdErr', stdioChunkToParams(chunk)); this._currentTest?._tracing.appendStdioToTrace('stderr', chunk); + if (typeof cb === 'function') + process.nextTick(cb); return true; }; } diff --git a/tests/playwright-test/playwright-test-fixtures.ts b/tests/playwright-test/playwright-test-fixtures.ts index 23c26a3e3c33e..5d6aab5b8e1f2 100644 --- a/tests/playwright-test/playwright-test-fixtures.ts +++ b/tests/playwright-test/playwright-test-fixtures.ts @@ -229,6 +229,7 @@ export function cleanEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv { // END: Reserved CI PW_TEST_HTML_REPORT_OPEN: undefined, PLAYWRIGHT_HTML_OPEN: undefined, + PW_TEST_DEBUG_REPORTERS: undefined, PW_TEST_REPORTER: undefined, PW_TEST_REPORTER_WS_ENDPOINT: undefined, PW_TEST_SOURCE_TRANSFORM: undefined, diff --git a/tests/playwright-test/reporter-list.spec.ts b/tests/playwright-test/reporter-list.spec.ts index 1d488cc253571..8e6128065ab66 100644 --- a/tests/playwright-test/reporter-list.spec.ts +++ b/tests/playwright-test/reporter-list.spec.ts @@ -258,6 +258,51 @@ for (const useIntermediateMergeReport of [false, true] as const) { expect(text).toContain('1) a.test.ts:3:15 › passes › outer 1.0 › inner 1.1 ──'); expect(result.exitCode).toBe(1); }); + + test('print stdio', async ({ runInlineTest }) => { + const result = await runInlineTest({ + 'a.test.ts': ` + import { test, expect } from '@playwright/test'; + test('passes', async ({}) => { + await new Promise(resolve => process.stdout.write('line1', () => resolve())); + await new Promise(resolve => process.stdout.write('line2\\n', () => resolve())); + await new Promise(resolve => process.stderr.write(Buffer.from(''), () => resolve())); + }); + + test('passes 2', async ({}) => { + await new Promise(resolve => process.stdout.write('partial', () => resolve())); + }); + + test('passes 3', async ({}) => { + await new Promise(resolve => process.stdout.write('full\\n', () => resolve())); + }); + + test('passes 4', async ({}) => { + }); + `, + }, { reporter: 'list' }, { PW_TEST_DEBUG_REPORTERS: '1', PLAYWRIGHT_FORCE_TTY: '80' }); + expect(result.exitCode).toBe(0); + expect(result.passed).toBe(4); + const expected = [ + '#0 : 1 a.test.ts:3:15 › passes', + 'line1line2', + `#0 : ${POSITIVE_STATUS_MARK} 1 a.test.ts:3:15 › passes`, + '', + '#3 : 2 a.test.ts:9:15 › passes 2', + `partial#3 : ${POSITIVE_STATUS_MARK} 2 a.test.ts:9:15 › passes 2`, + '', + '#5 : 3 a.test.ts:13:15 › passes 3', + 'full', + `#5 : ${POSITIVE_STATUS_MARK} 3 a.test.ts:13:15 › passes 3`, + '#7 : 4 a.test.ts:17:15 › passes 4', + `#7 : ${POSITIVE_STATUS_MARK} 4 a.test.ts:17:15 › passes 4`, + ]; + const lines = result.output.split('\n'); + const firstIndex = lines.indexOf(expected[0]); + expect(firstIndex, 'first line should be there').not.toBe(-1); + for (let i = 0; i < expected.length; ++i) + expect(lines[firstIndex + i]).toContain(expected[i]); + }); }); }