Skip to content

Commit

Permalink
chore: strip ansi from load errors (#554)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman authored Nov 13, 2024
1 parent 6e26030 commit 409036e
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 59 deletions.
55 changes: 17 additions & 38 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { SettingsModel } from './settingsModel';
import { SettingsView } from './settingsView';
import { TestModel, TestModelCollection } from './testModel';
import { TestTree } from './testTree';
import { NodeJSNotFoundError, ansiToHtml, getPlaywrightInfo } from './utils';
import { NodeJSNotFoundError, ansiToHtml, getPlaywrightInfo, stripAnsi, stripBabelFrame } from './utils';
import * as vscodeTypes from './vscodeTypes';
import { WorkspaceChange, WorkspaceObserver } from './workspaceObserver';
import { registerTerminalLinkProvider } from './terminalLinkProvider';
Expand Down Expand Up @@ -637,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: error.message!,
message: this._linkifyStack(stripBabelFrame(stripAnsi(error.message!))),
});
}
};
Expand Down Expand Up @@ -691,49 +691,28 @@ export class Extension implements RunHooks {

}

private _testMessageFromText(text: string): vscodeTypes.TestMessage {
let isLog = false;
const md: string[] = [];
const logMd: string[] = [];
private _linkifyStack(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')) {
if (line.startsWith(' at ')) {
// Render relative stack.
for (const workspaceFolder of this._vscode.workspace.workspaceFolders || []) {
const prefix1 = (' at ' + workspaceFolder.uri.fsPath + path.sep).toLowerCase();
const prefix2 = (' at fn (' + workspaceFolder.uri.fsPath + path.sep).toLowerCase();
const lowerLine = line.toLowerCase();
if (lowerLine.startsWith(prefix1)) {
line = ' at ' + line.substring(prefix1.length);
break;
}
if (lowerLine.startsWith(prefix2)) {
line = ' at ' + line.substring(prefix2.length, line.length - 1);
break;
}
const lowerLine = line.toLowerCase();
for (const prefix of prefixes) {
const index = lowerLine.indexOf(prefix);
if (index !== -1) {
line = line.substring(0, index) + line.substring(index + prefix.length);
break;
}
}
if (line.includes('=====') && line.includes('log')) {
isLog = true;
logMd.push('\n\n**Execution log**');
continue;
}
if (line.includes('=====')) {
isLog = false;
continue;
}
if (isLog) {
const [, indent, body] = line.match(/(\s*)(.*)/)!;
logMd.push(indent + ' - ' + ansiToHtml(body));
} else {
md.push(line);
}
result.push(line);
}
return result.join('\n');
}

private _testMessageFromText(text: string): vscodeTypes.TestMessage {
const markdownString = new this._vscode.MarkdownString();
markdownString.isTrusted = true;
markdownString.supportHtml = true;
markdownString.appendMarkdown(ansiToHtml(md.join('\n')));
if (logMd.length)
markdownString.appendMarkdown(logMd.join('\n'));
markdownString.appendMarkdown(ansiToHtml(this._linkifyStack(text)));
return new this._vscode.TestMessage(markdownString);
}

Expand Down
20 changes: 14 additions & 6 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,24 @@ import readline from 'readline';
import which from 'which';
import * as vscodeTypes from './vscodeTypes';

export function calculateSha1(buffer: Buffer | string): string {
const hash = crypto.createHash('sha1');
hash.update(buffer);
return hash.digest('hex');
}

export function createGuid(): string {
return crypto.randomBytes(16).toString('hex');
}

const ansiRegex = new RegExp('([\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~])))', 'g');
export function stripAnsi(str: string): string {
return str.replace(ansiRegex, '');
}

export function stripBabelFrame(text: string) {
const result: string[] = [];
for (const line of text.split('\n')) {
if (!line.trim().match(/>?\s*\d*\s*\|/))
result.push(line);
}
return result.join('\n').trim();
}

export function ansiToHtml(text: string): string {
let isOpen = false;
let hasTags = false;
Expand Down
2 changes: 1 addition & 1 deletion tests/auto-close.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ test('should reuse browsers', async ({ activate }) => {

const reusedBrowser = await vscode.extensions[0].reusedBrowserForTest();
const events: number[] = [];
reusedBrowser.onPageCountChanged(count => events.push(count));
reusedBrowser.onPageCountChanged((count: number) => events.push(count));
await testController.run();
await expect.poll(() => events).toEqual([1]);
expect(reusedBrowser._backend).toBeTruthy();
Expand Down
2 changes: 1 addition & 1 deletion tests/debug-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ test('should pass all args as string[] when debugging', async ({ activate }) =>
const onDidTerminateDebugSession = new Promise(resolve => vscode.debug.onDidTerminateDebugSession(resolve));
profile.run(testItems);
const session = await onDidStartDebugSession;
expect(session.configuration.args.filter(arg => typeof arg !== 'string')).toEqual([]);
expect(session.configuration.args.filter((arg: any) => typeof arg !== 'string')).toEqual([]);
await onDidTerminateDebugSession;
});

Expand Down
2 changes: 1 addition & 1 deletion tests/embedded-trace-viewer-legacy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ test('should show warning message again after refreshing test config', async ({
'Playwright v1.46+ is required for embedded trace viewer to work, v1.43 found'
]);

await testController.refreshHandler(null);
await testController.refreshHandler!(null);

await testController.run();

Expand Down
6 changes: 3 additions & 3 deletions tests/mock/vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,7 @@ export class VSCode {
readonly version: string;
readonly connectionLog: any[] = [];
readonly openExternalUrls: string[] = [];
readonly diagnosticsCollections: DiagnosticsCollection[] = [];

constructor(readonly versionNumber: number, baseDir: string, browser: Browser) {
this.version = String(versionNumber);
Expand Down Expand Up @@ -977,7 +978,6 @@ export class VSCode {
this._didShowInputBox,
);

const diagnosticsCollections: DiagnosticsCollection[] = [];
this.languages.registerHoverProvider = (language: string, provider: HoverProvider) => {
this._hoverProviders.set(language, provider);
return disposable;
Expand All @@ -990,15 +990,15 @@ export class VSCode {
};
this.languages.getDiagnostics = () => {
const result: Diagnostic[] = [];
for (const collection of diagnosticsCollections) {
for (const collection of this.diagnosticsCollections) {
for (const diagnostics of collection._entries.values())
result.push(...diagnostics);
}
return result;
};
this.languages.createDiagnosticCollection = () => {
const diagnosticsCollection = new DiagnosticsCollection();
diagnosticsCollections.push(diagnosticsCollection);
this.diagnosticsCollections.push(diagnosticsCollection);
return diagnosticsCollection;
};
this.tests.createTestController = this._createTestController.bind(this);
Expand Down
53 changes: 53 additions & 0 deletions tests/problems.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { expect, test } from './utils';

test('should list tests on expand', async ({ activate }) => {
const { vscode, testController } = await activate({
'playwright.config.js': `module.exports = { testDir: 'tests' }`,
'tests/test.spec.ts': `
import { test } from '@playwright/test';
test('one', async ({ page }) => {
const
await page.goto('http://example.com');
});
`,
});

await testController.expandTestItems(/test.spec.ts/);
await expect(testController).toHaveTestTree(`
- tests
- test.spec.ts
`);
expect(vscode.diagnosticsCollections.length).toBe(1);
expect([...vscode.diagnosticsCollections[0]._entries]).toEqual([
[
expect.stringContaining('test.spec.ts'),
[
{
message: expect.stringMatching(/^SyntaxError: tests[/\\]test.spec.ts: Unexpected reserved word 'await'. \(5:8\)$/),
range: {
end: { character: 0, line: 5 },
start: { character: 7, line: 4 }
},
severity: 'Error',
source: 'playwright'
}
]
]
]);
});
4 changes: 2 additions & 2 deletions tests/trace-viewer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { enableConfigs, expect, selectConfig, selectTestItem, test, traceViewerInfo } from './utils';

test.skip(({ showTrace }) => !showTrace);
test.skip(({ showTrace, overridePlaywrightVersion }) => overridePlaywrightVersion && showTrace === 'embedded');
test.skip(({ showTrace, overridePlaywrightVersion }) => !!overridePlaywrightVersion && showTrace === 'embedded');

test('@smoke should open trace viewer', async ({ activate, showTrace }) => {
const { vscode, testController } = await activate({
Expand Down Expand Up @@ -130,7 +130,7 @@ test('should close trace viewer if test configs refreshed', async ({ activate, s
traceFile: expect.stringContaining('pass'),
});

await testController.refreshHandler(null);
await testController.refreshHandler!(null);

await expect.poll(() => traceViewerInfo(vscode)).toMatchObject({
type: showTrace,
Expand Down
13 changes: 7 additions & 6 deletions tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import { expect as baseExpect, test as baseTest, Browser, chromium, Page } from '@playwright/test';
// @ts-ignore
import { Extension } from '../out/extension';
import { TestController, VSCode, WorkspaceFolder, TestRun, TestItem } from './mock/vscode';

Expand Down Expand Up @@ -58,7 +59,7 @@ export const expect = baseExpect.extend({
} catch (e) {
return {
pass: false,
message: () => e.toString()
message: () => String(e)
};
}
},
Expand All @@ -72,7 +73,7 @@ export const expect = baseExpect.extend({
} catch (e) {
return {
pass: false,
message: () => e.toString()
message: () => String(e)
};
}
},
Expand All @@ -84,7 +85,7 @@ export const expect = baseExpect.extend({
} catch (e) {
return {
pass: false,
message: () => e.toString()
message: () => String(e)
};
}
},
Expand All @@ -96,7 +97,7 @@ export const expect = baseExpect.extend({
} catch (e) {
return {
pass: false,
message: () => e.toString()
message: () => String(e)
};
}
},
Expand All @@ -114,7 +115,7 @@ export const expect = baseExpect.extend({
} catch (e) {
return {
pass: false,
message: () => e.toString()
message: () => String(e)
};
}
},
Expand Down Expand Up @@ -210,7 +211,7 @@ export async function enableConfigs(vscode: VSCode, labels: string[]) {
let success = false;
const webView = vscode.webViews.get('pw.extension.settingsView')!;
while (!success) {
vscode.window.mockQuickPick = async items => {
vscode.window.mockQuickPick = async (items: TestItem[]) => {
let allFound = true;
for (const label of labels) {
if (!items.find(i => i.label === label))
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
"esModuleInterop": true,
"noEmit": true
},
"include": ["src", "tests/mock"],
"include": ["src", "tests"],
"exclude": ["node_modules"]
}

0 comments on commit 409036e

Please sign in to comment.