mirror of
https://github.com/microsoft/playwright.git
synced 2025-01-05 19:04:43 +03:00
fix(list reporter): properly count new lines for long stdout (#17339)
This commit is contained in:
parent
a12112c24d
commit
8466c436c9
@ -107,8 +107,12 @@ export class BaseReporter implements ReporterInternal {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
protected ttyWidth() {
|
||||
return this._ttyWidthForTest || process.stdout.columns || 0;
|
||||
}
|
||||
|
||||
protected fitToScreen(line: string, prefix?: string): string {
|
||||
const ttyWidth = this._ttyWidthForTest || process.stdout.columns || 0;
|
||||
const ttyWidth = this.ttyWidth();
|
||||
if (!ttyWidth) {
|
||||
// Guard against the case where we cannot determine available width.
|
||||
return line;
|
||||
|
@ -26,6 +26,7 @@ const NEGATIVE_STATUS_MARK = DOES_NOT_SUPPORT_UTF8_IN_TERMINAL ? 'x' : '✘';
|
||||
|
||||
class ListReporter extends BaseReporter {
|
||||
private _lastRow = 0;
|
||||
private _lastColumn = 0;
|
||||
private _testRows = new Map<TestCase, number>();
|
||||
private _resultIndex = new Map<TestResult, number>();
|
||||
private _needNewLine = false;
|
||||
@ -93,9 +94,20 @@ class ListReporter extends BaseReporter {
|
||||
|
||||
private _updateLineCountAndNewLineFlagForOutput(text: string) {
|
||||
this._needNewLine = text[text.length - 1] !== '\n';
|
||||
if (this._liveTerminal) {
|
||||
const newLineCount = text.split('\n').length - 1;
|
||||
this._lastRow += newLineCount;
|
||||
const ttyWidth = this.ttyWidth();
|
||||
if (!this._liveTerminal || ttyWidth === 0)
|
||||
return;
|
||||
for (const ch of text) {
|
||||
if (ch === '\n') {
|
||||
this._lastColumn = 0;
|
||||
++this._lastRow;
|
||||
continue;
|
||||
}
|
||||
++this._lastColumn;
|
||||
if (this._lastColumn > ttyWidth) {
|
||||
this._lastColumn = 0;
|
||||
++this._lastRow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,26 @@ test('render steps', async ({ runInlineTest }) => {
|
||||
]);
|
||||
});
|
||||
|
||||
test('very long console line should not mess terminal', async ({ runInlineTest }) => {
|
||||
const TTY_WIDTH = 80;
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
test('passes', async ({}) => {
|
||||
console.log('a'.repeat(80) + 'b'.repeat(20));
|
||||
});
|
||||
`,
|
||||
}, { reporter: 'list' }, { PWTEST_TTY_WIDTH: TTY_WIDTH + '' });
|
||||
|
||||
const renderedText = simpleAnsiRenderer(result.output, TTY_WIDTH);
|
||||
if (process.platform === 'win32')
|
||||
expect(renderedText).toContain(' ok 1 a.test.ts:6:7 › passes');
|
||||
else
|
||||
expect(renderedText).toContain(' ✓ 1 a.test.ts:6:7 › passes');
|
||||
expect(renderedText).not.toContain(' 1 a.test.ts:6:7 › passes');
|
||||
expect(renderedText).toContain('a'.repeat(80) + '\n' + 'b'.repeat(20));
|
||||
});
|
||||
|
||||
test('render retries', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
@ -149,3 +169,63 @@ test('should truncate long test names', async ({ runInlineTest }) => {
|
||||
|
||||
expect(lines[7]).toBe(` - 4 …› a.test.ts:13:12 › skipped very long name`);
|
||||
});
|
||||
|
||||
function simpleAnsiRenderer(text, ttyWidth) {
|
||||
let lineNumber = 0;
|
||||
let columnNumber = 0;
|
||||
const screenLines = [];
|
||||
const ensureScreenSize = () => {
|
||||
if (lineNumber < 0)
|
||||
throw new Error('Bad terminal navigation!');
|
||||
while (lineNumber >= screenLines.length)
|
||||
screenLines.push(new Array(ttyWidth).fill(''));
|
||||
};
|
||||
const print = ch => {
|
||||
ensureScreenSize();
|
||||
if (ch === '\n') {
|
||||
columnNumber = 0;
|
||||
++lineNumber;
|
||||
} else {
|
||||
screenLines[lineNumber][columnNumber++] = ch;
|
||||
if (columnNumber === ttyWidth) {
|
||||
columnNumber = 0;
|
||||
++lineNumber;
|
||||
}
|
||||
}
|
||||
ensureScreenSize();
|
||||
};
|
||||
|
||||
let index = 0;
|
||||
|
||||
const ansiCodes = [...text.matchAll(/\u001B\[(\d*)(.)/g)];
|
||||
for (const ansiCode of ansiCodes) {
|
||||
const [matchText, codeValue, codeType] = ansiCode;
|
||||
const code = (codeValue + codeType).toUpperCase();
|
||||
while (index < ansiCode.index)
|
||||
print(text[index++]);
|
||||
if (codeType.toUpperCase() === 'E') {
|
||||
// Go X lines down
|
||||
lineNumber += +codeValue;
|
||||
ensureScreenSize();
|
||||
} else if (codeType.toUpperCase() === 'A') {
|
||||
// Go X lines up
|
||||
lineNumber -= +codeValue;
|
||||
ensureScreenSize();
|
||||
} else if (code === '2K') {
|
||||
// Erase full line
|
||||
ensureScreenSize();
|
||||
screenLines[lineNumber] = new Array(ttyWidth).fill('');
|
||||
} else if (code === '0G') {
|
||||
// Go to start
|
||||
columnNumber = 0;
|
||||
} else {
|
||||
// Unsupported ANSI code (e.g. all colors).
|
||||
}
|
||||
index += matchText.length;
|
||||
}
|
||||
while (index < text.length)
|
||||
print(text[index++]);
|
||||
|
||||
return screenLines.map(line => line.join('')).join('\n');
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user