Skip to content

Commit

Permalink
chore: populate stackTrace in test errors (#567)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman authored Dec 12, 2024
1 parent 2e0df2c commit 0d84a54
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 35 deletions.
61 changes: 39 additions & 22 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,6 @@ export class Extension implements RunHooks {
this._executionLinesChanged();
const include = request.include;

// Create a test run that potentially includes all the test items.
// This allows running setup tests that are outside of the scope of the
// selected test items.
const rootItems: vscodeTypes.TestItem[] = [];
this._testController.items.forEach(item => rootItems.push(item));

Expand Down Expand Up @@ -528,7 +525,7 @@ export class Extension implements RunHooks {
return;
}
testFailures.add(testItem);
testRun.failed(testItem, result.errors.map(error => this._testMessageForTestError(error, testItem)), result.duration);
testRun.failed(testItem, result.errors.map(error => this._testMessageForTestError(error)), result.duration);
},

onStepBegin: (test: reporterTypes.TestCase, result: reporterTypes.TestResult, testStep: reporterTypes.TestStep) => {
Expand Down Expand Up @@ -640,7 +637,7 @@ export class Extension implements RunHooks {
severity: this._vscode.DiagnosticSeverity.Error,
source: 'playwright',
range: new this._vscode.Range(Math.max(error.location!.line - 1, 0), Math.max(error.location!.column - 1, 0), error.location!.line, 0),
message: this._linkifyStack(stripBabelFrame(stripAnsi(error.message!))),
message: this._abbreviateStack(stripBabelFrame(stripAnsi(error.message!))),
});
}
};
Expand Down Expand Up @@ -694,7 +691,18 @@ export class Extension implements RunHooks {

}

private _linkifyStack(text: string): string {
private _trimStack(text: string): string {
const result: string[] = [];
for (const line of text.split('\n')) {
const frame = stackUtils.parseLine(line);
if (frame?.file && frame.line)
continue;
result.push(line);
}
return result.join('\n');
}

private _abbreviateStack(text: string): string {
const result: string[] = [];
const prefixes = (this._vscode.workspace.workspaceFolders || []).map(f => f.uri.fsPath.toLowerCase() + path.sep);
for (let line of text.split('\n')) {
Expand All @@ -715,7 +723,7 @@ export class Extension implements RunHooks {
const markdownString = new this._vscode.MarkdownString();
markdownString.isTrusted = true;
markdownString.supportHtml = true;
markdownString.appendMarkdown(ansi2html(this._linkifyStack(text)));
markdownString.appendMarkdown(ansi2html(this._trimStack(text)));
return new this._vscode.TestMessage(markdownString);
}

Expand All @@ -728,7 +736,7 @@ export class Extension implements RunHooks {
return new this._vscode.TestMessage(markdownString);
}

private _testMessageForTestError(error: reporterTypes.TestError, testItem?: vscodeTypes.TestItem): vscodeTypes.TestMessage {
private _testMessageForTestError(error: reporterTypes.TestError): vscodeTypes.TestMessage {
const text = this._formatError(error);
let testMessage: vscodeTypes.TestMessage;
if (text.includes('Looks like Playwright Test or Playwright')) {
Expand All @@ -744,11 +752,12 @@ export class Extension implements RunHooks {
} else {
testMessage = this._testMessageFromText(text);
}
const location = error.location || parseLocationFromStack(error.stack, testItem);
if (location) {
const position = new this._vscode.Position(location.line - 1, location.column - 1);
testMessage.location = new this._vscode.Location(this._vscode.Uri.file(location.file), position);
}
const stackTrace = error.stack ? parseStack(this._vscode, error.stack) : [];
const location = error.location ? parseLocation(this._vscode, error.location) : topStackFrame(this._vscode, stackTrace);
if (stackTrace.length)
testMessage.stackTrace = stackTrace;
if (location)
testMessage.location = location;
return testMessage;
}

Expand Down Expand Up @@ -794,21 +803,29 @@ export class Extension implements RunHooks {
}
}

function parseLocationFromStack(stack: string | undefined, testItem?: vscodeTypes.TestItem): reporterTypes.Location | undefined {
function parseLocation(vscode: vscodeTypes.VSCode, location: reporterTypes.Location): vscodeTypes.Location {
return new vscode.Location(
vscode.Uri.file(location.file),
new vscode.Position(location.line - 1, location.column - 1));
}

function topStackFrame(vscode: vscodeTypes.VSCode, stackTrace: vscodeTypes.TestMessageStackFrame[]): vscodeTypes.Location | undefined {
return stackTrace.length ? new vscode.Location(stackTrace[0].uri!, stackTrace[0].position!) : undefined;
}

function parseStack(vscode: vscodeTypes.VSCode, stack: string): vscodeTypes.TestMessageStackFrame[] {
const lines = stack?.split('\n') || [];
const result: vscodeTypes.TestMessageStackFrame[] = [];
for (const line of lines) {
const frame = stackUtils.parseLine(line);
if (!frame || !frame.file || !frame.line || !frame.column)
continue;
frame.file = frame.file.replace(/\//g, path.sep);
if (!testItem || testItem.uri!.fsPath === frame.file) {
return {
file: frame.file,
line: frame.line,
column: frame.column,
};
}
result.push(new vscode.TestMessageStackFrame(
frame.method || '',
vscode.Uri.file(frame.file),
new vscode.Position(frame.line - 1, frame.column - 1)));
}
return result;
}

class TreeItemObserver implements vscodeTypes.Disposable{
Expand Down
1 change: 1 addition & 0 deletions src/vscodeTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export type {
TestItem,
TestItemCollection,
TestMessage,
TestMessageStackFrame,
TestRun,
TestRunProfile,
TestRunRequest,
Expand Down
16 changes: 15 additions & 1 deletion tests/mock/vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,8 @@ export class TestMessage {
readonly message: MarkdownString,
readonly expectedOutput?: string,
readonly actualOutput?: string,
readonly location?: Location) {}
readonly location?: Location,
readonly stackTrace?: TestMessageStackFrame[]) {}

render(indent: string, result: string[]) {
if (this.location)
Expand All @@ -392,9 +393,21 @@ export class TestMessage {
line = line.replace(/\\/g, '/');
result.push(indent + line);
}
if (this.stackTrace?.length) {
result.push(indent + 'Stack trace:');
for (const frame of this.stackTrace)
result.push(`${indent} ${frame.label} (${path.basename(frame.uri.fsPath)}:${frame.position.line + 1})`);
}
}
}

export class TestMessageStackFrame {
constructor(
readonly label: string,
readonly uri: Uri,
readonly position: Position) {}
}

type LogEntry = { status: string, duration?: number, messages?: TestMessage | TestMessage[] };

const disposable = { dispose: () => {} };
Expand Down Expand Up @@ -891,6 +904,7 @@ export class VSCode {
Selection = Selection;
TestTag = TestTag;
TestMessage = TestMessage;
TestMessageStackFrame = TestMessageStackFrame;
TestRunProfileKind = TestRunProfileKind;
TestRunRequest = TestRunRequest;
Uri = Uri;
Expand Down
24 changes: 12 additions & 12 deletions tests/run-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,8 @@ test('should show error message', async ({ activate }) => {
Expected: <span style='color:#73c991;'>2</span>
<br>
Received: <span style='color:#f14c4c;'>1</span>
<br>
at tests/test.spec.ts:4:19
Stack trace:
(test.spec.ts:4)
`);
});

Expand Down Expand Up @@ -318,8 +318,8 @@ test('should show soft error messages', async ({ activate }) => {
Expected: <span style='color:#73c991;'>2</span>
<br>
Received: <span style='color:#f14c4c;'>1</span>
<br>
at tests/test.spec.ts:4:24
Stack trace:
(test.spec.ts:4)
test.spec.ts:[4:23 - 4:23]
Error: <span style='color:#666;'>expect(</span><span style='color:#f14c4c;'>received</span><span style='color:#666;'>).</span>toBe<span style='color:#666;'>(</span><span style='color:#73c991;'>expected</span><span style='color:#666;'>) // Object.is equality</span>
<br>
Expand All @@ -328,8 +328,8 @@ test('should show soft error messages', async ({ activate }) => {
Expected: <span style='color:#73c991;'>3</span>
<br>
Received: <span style='color:#f14c4c;'>2</span>
<br>
at tests/test.spec.ts:5:24
Stack trace:
(test.spec.ts:5)
`);
});

Expand Down Expand Up @@ -1018,24 +1018,24 @@ test('should report project-specific failures', async ({ activate }) => {
failed
test.spec.ts:[3:14 - 3:14]
Error: projectA
<br>
at tests/test.spec.ts:4:15
Stack trace:
(test.spec.ts:4)
tests > test.spec.ts > should pass > projectB [2:0]
enqueued
started
failed
test.spec.ts:[3:14 - 3:14]
Error: projectB
<br>
at tests/test.spec.ts:4:15
Stack trace:
(test.spec.ts:4)
tests > test.spec.ts > should pass > projectC [2:0]
enqueued
started
failed
test.spec.ts:[3:14 - 3:14]
Error: projectC
<br>
at tests/test.spec.ts:4:15
Stack trace:
(test.spec.ts:4)
`);
});

Expand Down

0 comments on commit 0d84a54

Please sign in to comment.