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 = [];
if (stack) {
tokens.push('');
const message = error.message || '';
const messageLocation = stack.indexOf(message);
const preamble = stack.substring(0, messageLocation + message.length);
tokens.push(preamble);
const position = file ? positionInFile(stack, file) : null;
const lines = stack.split('\n');
let firstStackLine = lines.findIndex(line => line.startsWith(' at '));
if (firstStackLine === -1)
firstStackLine = lines.length;
tokens.push(lines.slice(0, firstStackLine).join('\n'));
const stackLines = lines.slice(firstStackLine);
const position = file ? positionInFile(stackLines, file) : null;
if (position) {
const source = fs.readFileSync(file!, 'utf8');
tokens.push('');
tokens.push(codeFrameColumns(source, {
start: position,
},
{ highlightCode: colors.enabled }
));
tokens.push(codeFrameColumns(source, { start: position }, { highlightCode: colors.enabled }));
}
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) {
tokens.push('');
tokens.push(error.message);
@ -279,10 +277,10 @@ function indent(lines: string, tab: string) {
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.
file = fs.realpathSync(file);
for (const line of stack.split('\n')) {
for (const line of stackLines) {
const parsed = stackUtils.parseLine(line);
if (!parsed || !parsed.file)
continue;

View file

@ -226,3 +226,24 @@ test('should print stack-less errors', async ({ runInlineTest }) => {
expect(result.failed).toBe(1);
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('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');
});