fix(reporters): correctly handle missing stdout.columns (#12016)

When columns are not available, do not trim the output.
This commit is contained in:
Dmitry Gozman 2022-02-11 08:33:56 -08:00 committed by GitHub
parent 979fa2b2f0
commit d8db785c0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 31 additions and 17 deletions

View File

@ -478,7 +478,7 @@ class Worker extends EventEmitter {
detached: false, detached: false,
env: { env: {
FORCE_COLOR: '1', FORCE_COLOR: '1',
DEBUG_COLORS: process.stdout.isTTY ? '1' : '0', DEBUG_COLORS: '1',
TEST_WORKER_INDEX: String(this.workerIndex), TEST_WORKER_INDEX: String(this.workerIndex),
TEST_PARALLEL_INDEX: String(this.parallelIndex), TEST_PARALLEL_INDEX: String(this.parallelIndex),
...process.env ...process.env

View File

@ -107,8 +107,13 @@ export class BaseReporter implements Reporter {
this.result = result; this.result = result;
} }
protected ttyWidth() { protected fitToScreen(line: string, suffix?: string): string {
return this._ttyWidthForTest || (process.env.PWTEST_SKIP_TEST_OUTPUT ? 80 : process.stdout.columns || 0); const ttyWidth = this._ttyWidthForTest || (process.env.PWTEST_SKIP_TEST_OUTPUT ? 80 : process.stdout.columns || 0);
if (!ttyWidth) {
// Guard against the case where we cannot determine available width.
return line;
}
return fitToWidth(line, ttyWidth, suffix);
} }
protected generateStartingMessage() { protected generateStartingMessage() {
@ -431,7 +436,7 @@ export function stripAnsiEscapes(str: string): string {
} }
// Leaves enough space for the "suffix" to also fit. // Leaves enough space for the "suffix" to also fit.
export function fitToScreen(line: string, width: number, suffix?: string): string { function fitToWidth(line: string, width: number, suffix?: string): string {
const suffixLength = suffix ? stripAnsiEscapes(suffix).length : 0; const suffixLength = suffix ? stripAnsiEscapes(suffix).length : 0;
width -= suffixLength; width -= suffixLength;
if (line.length <= width) if (line.length <= width)

View File

@ -15,7 +15,7 @@
*/ */
import colors from 'colors/safe'; import colors from 'colors/safe';
import { BaseReporter, fitToScreen, formatFailure, formatTestTitle } from './base'; import { BaseReporter, formatFailure, formatTestTitle } from './base';
import { FullConfig, TestCase, Suite, TestResult, FullResult } from '../../types/testReporter'; import { FullConfig, TestCase, Suite, TestResult, FullResult } from '../../types/testReporter';
class LineReporter extends BaseReporter { class LineReporter extends BaseReporter {
@ -51,7 +51,7 @@ class LineReporter extends BaseReporter {
if (test && this._lastTest !== test) { if (test && this._lastTest !== test) {
// Write new header for the output. // Write new header for the output.
const title = colors.gray(formatTestTitle(this.config, test)); const title = colors.gray(formatTestTitle(this.config, test));
stream.write(fitToScreen(title, this.ttyWidth()) + `\n`); stream.write(this.fitToScreen(title) + `\n`);
this._lastTest = test; this._lastTest = test;
} }
@ -69,7 +69,7 @@ class LineReporter extends BaseReporter {
if (process.env.PWTEST_SKIP_TEST_OUTPUT) if (process.env.PWTEST_SKIP_TEST_OUTPUT)
process.stdout.write(`${title + suffix}\n`); process.stdout.write(`${title + suffix}\n`);
else else
process.stdout.write(`\u001B[1A\u001B[2K${fitToScreen(title, this.ttyWidth(), suffix) + colors.yellow(suffix)}\n`); process.stdout.write(`\u001B[1A\u001B[2K${this.fitToScreen(title, suffix) + colors.yellow(suffix)}\n`);
if (!this.willRetry(test) && (test.outcome() === 'flaky' || test.outcome() === 'unexpected')) { if (!this.willRetry(test) && (test.outcome() === 'flaky' || test.outcome() === 'unexpected')) {
if (!process.env.PWTEST_SKIP_TEST_OUTPUT) if (!process.env.PWTEST_SKIP_TEST_OUTPUT)

View File

@ -17,7 +17,7 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import colors from 'colors/safe'; import colors from 'colors/safe';
import milliseconds from 'ms'; import milliseconds from 'ms';
import { BaseReporter, fitToScreen, formatTestTitle } from './base'; import { BaseReporter, formatTestTitle } from './base';
import { FullConfig, FullResult, Suite, TestCase, TestResult, TestStep } from '../../types/testReporter'; import { FullConfig, FullResult, Suite, TestCase, TestResult, TestStep } from '../../types/testReporter';
// Allow it in the Visual Studio Code Terminal and the new Windows Terminal // Allow it in the Visual Studio Code Terminal and the new Windows Terminal
@ -55,7 +55,7 @@ class ListReporter extends BaseReporter {
} }
const line = ' ' + colors.gray(formatTestTitle(this.config, test)); const line = ' ' + colors.gray(formatTestTitle(this.config, test));
const suffix = this._retrySuffix(result); const suffix = this._retrySuffix(result);
process.stdout.write(this._fitToScreen(line, suffix) + suffix + '\n'); process.stdout.write(this.fitToScreen(line, suffix) + suffix + '\n');
} }
this._testRows.set(test, this._lastRow++); this._testRows.set(test, this._lastRow++);
} }
@ -142,7 +142,7 @@ class ListReporter extends BaseReporter {
process.stdout.write(`\u001B[${this._lastRow - testRow}A`); process.stdout.write(`\u001B[${this._lastRow - testRow}A`);
// Erase line, go to the start // Erase line, go to the start
process.stdout.write('\u001B[2K\u001B[0G'); process.stdout.write('\u001B[2K\u001B[0G');
process.stdout.write(this._fitToScreen(line, suffix) + suffix); process.stdout.write(this.fitToScreen(line, suffix) + suffix);
// Go down if needed. // Go down if needed.
if (testRow !== this._lastRow) if (testRow !== this._lastRow)
process.stdout.write(`\u001B[${this._lastRow - testRow}E`); process.stdout.write(`\u001B[${this._lastRow - testRow}E`);
@ -152,13 +152,6 @@ class ListReporter extends BaseReporter {
return (result.retry ? colors.yellow(` (retry #${result.retry})`) : ''); return (result.retry ? colors.yellow(` (retry #${result.retry})`) : '');
} }
private _fitToScreen(line: string, suffix?: string): string {
const ttyWidth = this.ttyWidth();
if (!ttyWidth)
return line;
return fitToScreen(line, ttyWidth, suffix);
}
private _updateTestLineForTest(test: TestCase, line: string, suffix: string) { private _updateTestLineForTest(test: TestCase, line: string, suffix: string) {
const testRow = this._testRows.get(test)!; const testRow = this._testRows.get(test)!;
process.stdout.write(testRow + ' : ' + line + suffix + '\n'); process.stdout.write(testRow + ' : ' + line + suffix + '\n');

View File

@ -66,3 +66,19 @@ test('should print flaky failures', async ({ runInlineTest }) => {
expect(result.flaky).toBe(1); expect(result.flaky).toBe(1);
expect(stripAnsi(result.output)).toContain('expect(testInfo.retry).toBe(1)'); expect(stripAnsi(result.output)).toContain('expect(testInfo.retry).toBe(1)');
}); });
test('should work without tty', async ({ runInlineTest }) => {
const result = await runInlineTest({
'a.test.js': `
const { test } = pwt;
test('one', async ({}) => {
expect(1).toBe(0);
});
`,
}, { reporter: 'line' }, { PWTEST_TTY_WIDTH: '0', PWTEST_SKIP_TEST_OUTPUT: undefined });
const text = stripAnsi(result.output);
expect(text).toContain('[1/1] a.test.js:6:7 one');
expect(text).toContain('1 failed');
expect(text).toContain('1) a.test');
expect(result.exitCode).toBe(1);
});