diff --git a/src/test/reporters/list.ts b/src/test/reporters/list.ts index 6f3f3542c2..f5edf1f175 100644 --- a/src/test/reporters/list.ts +++ b/src/test/reporters/list.ts @@ -30,11 +30,13 @@ class ListReporter extends BaseReporter { private _lastRow = 0; private _testRows = new Map(); private _needNewLine = false; - private _liveTerminal: string | boolean | undefined; + private readonly _liveTerminal: string | boolean | undefined; + private readonly _ttyWidthForTest: number; constructor() { super(); - this._liveTerminal = process.stdout.isTTY || process.env.PWTEST_SKIP_TEST_OUTPUT; + this._ttyWidthForTest = parseInt(process.env.PWTEST_TTY_WIDTH || '', 10); + this._liveTerminal = process.stdout.isTTY || process.env.PWTEST_SKIP_TEST_OUTPUT || !!this._ttyWidthForTest; } override onBegin(config: FullConfig, suite: Suite) { @@ -49,7 +51,8 @@ class ListReporter extends BaseReporter { process.stdout.write('\n'); this._lastRow++; } - process.stdout.write(' ' + colors.gray(formatTestTitle(this.config, test)) + '\n'); + const line = ' ' + colors.gray(formatTestTitle(this.config, test)); + process.stdout.write(this._fitToScreen(line) + '\n'); } this._testRows.set(test, this._lastRow++); } @@ -134,12 +137,33 @@ class ListReporter extends BaseReporter { process.stdout.write(`\u001B[${this._lastRow - testRow}A`); // Erase line process.stdout.write('\u001B[2K'); - process.stdout.write(line); + process.stdout.write(this._fitToScreen(line)); // Go down if needed. if (testRow !== this._lastRow) process.stdout.write(`\u001B[${this._lastRow - testRow}E`); } + private _fitToScreen(line: string): string { + if (!this._ttyWidth() || line.length <= this._ttyWidth()) + return line; + // Matches '\u001b[2K\u001b[0G' and all color codes. + const re = /\u001b\[2K\u001b\[0G|\x1B\[\d+m/g; + let m; + let colorLen = 0; + while ((m = re.exec(line)) !== null) { + const visibleLen = m.index - colorLen; + if (visibleLen >= this._ttyWidth()) + break; + colorLen += m[0].length; + } + // Truncate and reset all colors. + return line.substr(0, this._ttyWidth() + colorLen) + '\u001b[0m'; + } + + private _ttyWidth(): number { + return this._ttyWidthForTest || process.stdout.columns || 0; + } + private _updateTestLineForTest(test: TestCase, line: string) { const testRow = this._testRows.get(test)!; process.stdout.write(testRow + ' : ' + line + '\n'); diff --git a/tests/playwright-test/list-reporter.spec.ts b/tests/playwright-test/list-reporter.spec.ts index 32aa33e1e3..d79ff830ac 100644 --- a/tests/playwright-test/list-reporter.spec.ts +++ b/tests/playwright-test/list-reporter.spec.ts @@ -82,3 +82,36 @@ test('render steps', async ({ runInlineTest }) => { '0 : a.test.ts:6:7 › passes', ]); }); + +test('should truncate long test names', async ({ runInlineTest }) => { + const result = await runInlineTest({ + 'playwright.config.ts': ` + module.exports = { projects: [ + { name: 'foo' }, + ] }; + `, + 'a.test.ts': ` + const { test } = pwt; + test('fails long name', async ({}) => { + expect(1).toBe(0); + }); + test('passes', async ({}) => { + }); + test('passes 2 long name', async () => { + }); + test.skip('skipped long name', async () => { + }); + `, + }, { reporter: 'list', retries: 0 }, { PWTEST_TTY_WIDTH: 40, PWTEST_SKIP_TEST_OUTPUT: undefined }); + const text = stripAscii(result.output); + const positiveStatusMarkPrefix = process.platform === 'win32' ? 'ok' : '✓ '; + const negativateStatusMarkPrefix = process.platform === 'win32' ? 'x ' : '✘ '; + expect(text).toContain(`${negativateStatusMarkPrefix} [foo] › a.test.ts:6:7 › fails long`); + expect(text).not.toContain(`${negativateStatusMarkPrefix} [foo] › a.test.ts:6:7 › fails long n`); + expect(text).toContain(`${positiveStatusMarkPrefix} [foo] › a.test.ts:9:7 › passes (`); + expect(text).toContain(`${positiveStatusMarkPrefix} [foo] › a.test.ts:11:7 › passes 2 l`); + expect(text).not.toContain(`${positiveStatusMarkPrefix} [foo] › a.test.ts:11:7 › passes 2 lo`); + expect(text).toContain(`- [foo] › a.test.ts:13:12 › skipped l`); + expect(text).not.toContain(`- [foo] › a.test.ts:13:12 › skipped lo`); + expect(result.exitCode).toBe(1); +});