fix(test runner): account for errors with inconsistent stack/message (#8950)

This commit is contained in:
Dmitry Gozman 2021-09-15 21:28:36 -07:00 committed by GitHub
parent 9b08871b4d
commit 5379b2dcba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 13 deletions

View file

@ -243,22 +243,20 @@ export function formatError(error: TestError, file?: string) {
const tokens = []; const tokens = [];
if (stack) { if (stack) {
tokens.push(''); tokens.push('');
const message = error.message || ''; const lines = stack.split('\n');
const messageLocation = stack.indexOf(message); let firstStackLine = lines.findIndex(line => line.startsWith(' at '));
const preamble = stack.substring(0, messageLocation + message.length); if (firstStackLine === -1)
tokens.push(preamble); firstStackLine = lines.length;
const position = file ? positionInFile(stack, file) : null; tokens.push(lines.slice(0, firstStackLine).join('\n'));
const stackLines = lines.slice(firstStackLine);
const position = file ? positionInFile(stackLines, file) : null;
if (position) { if (position) {
const source = fs.readFileSync(file!, 'utf8'); const source = fs.readFileSync(file!, 'utf8');
tokens.push(''); tokens.push('');
tokens.push(codeFrameColumns(source, { tokens.push(codeFrameColumns(source, { start: position }, { highlightCode: colors.enabled }));
start: position,
},
{ highlightCode: colors.enabled }
));
} }
tokens.push(''); tokens.push('');
tokens.push(colors.dim(preamble.length > 0 ? stack.substring(preamble.length + 1) : stack)); tokens.push(colors.dim(stackLines.join('\n')));
} else if (error.message) { } else if (error.message) {
tokens.push(''); tokens.push('');
tokens.push(error.message); tokens.push(error.message);
@ -279,10 +277,10 @@ function indent(lines: string, tab: string) {
return lines.replace(/^(?=.+$)/gm, tab); return lines.replace(/^(?=.+$)/gm, tab);
} }
function positionInFile(stack: string, file: string): { column: number; line: number; } | undefined { function positionInFile(stackLines: string[], file: string): { column: number; line: number; } | undefined {
// Stack will have /private/var/folders instead of /var/folders on Mac. // Stack will have /private/var/folders instead of /var/folders on Mac.
file = fs.realpathSync(file); file = fs.realpathSync(file);
for (const line of stack.split('\n')) { for (const line of stackLines) {
const parsed = stackUtils.parseLine(line); const parsed = stackUtils.parseLine(line);
if (!parsed || !parsed.file) if (!parsed || !parsed.file)
continue; continue;

View file

@ -226,3 +226,24 @@ test('should print stack-less errors', async ({ runInlineTest }) => {
expect(result.failed).toBe(1); expect(result.failed).toBe(1);
expect(result.output).toContain('Hello'); expect(result.output).toContain('Hello');
}); });
test('should print errors with inconsistent message/stack', async ({ runInlineTest }) => {
const result = await runInlineTest({
'a.spec.ts': `
const { test } = pwt;
test('foobar', async function myTest({}) {
const e = new Error('Hello');
// Force stack to contain "Hello".
// Otherwise it is computed lazy and will get 'foo bar' instead.
e.stack;
e.message = 'foo bar';
e.stack = 'hi!' + e.stack;
throw e;
});
`
});
expect(result.exitCode).toBe(1);
expect(result.failed).toBe(1);
expect(result.output).toContain('hi!Error: Hello');
expect(result.output).toContain('at myTest');
});

View file

@ -231,3 +231,23 @@ test('should print expected/received before timeout', async ({ runInlineTest })
expect(stripAscii(result.output)).toContain('Expected string: "Text 2"'); expect(stripAscii(result.output)).toContain('Expected string: "Text 2"');
expect(stripAscii(result.output)).toContain('Received string: "Text content"'); expect(stripAscii(result.output)).toContain('Received string: "Text content"');
}); });
test('should print nice error for toHaveText', async ({ runInlineTest }) => {
const result = await runInlineTest({
'a.test.ts': `
const { test } = pwt;
test('fail', async ({ page }) => {
await page.setContent('<div id=node>Text content</div>');
await expect(page.locator('no-such-thing')).toHaveText('Text');
});
`,
}, { workers: 1, timeout: 2000 });
expect(result.failed).toBe(1);
expect(result.exitCode).toBe(1);
const output = stripAscii(result.output);
expect(output).toContain('Pending operations:');
expect(output).toContain('Error: expect(received).toHaveText(expected)');
expect(output).toContain('Expected string: "Text"');
expect(output).toContain('Received string: undefined');
});