Skip to content

Commit

Permalink
chore: move debug to test server (#450)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman authored Apr 1, 2024
1 parent 4ad1834 commit e94a823
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 100 deletions.
46 changes: 23 additions & 23 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
},
"devDependencies": {
"@babel/preset-typescript": "^7.23.2",
"@playwright/test": "1.43.0-beta-1711554436000",
"@playwright/test": "1.43.0-beta-1711849714000",
"@types/babel__core": "^7.20.3",
"@types/babel__helper-plugin-utils": "^7.10.2",
"@types/babel__traverse": "^7.20.3",
Expand Down
18 changes: 14 additions & 4 deletions src/debugHighlight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,19 @@ export type DebuggerError = { error: string, location: Location };

export class DebugHighlight {
private _debugSessions = new Map<string, vscodeTypes.DebugSession>();
private _errorInDebugger: vscodeTypes.EventEmitter<DebuggerError>;
private _onErrorInDebuggerEmitter: vscodeTypes.EventEmitter<DebuggerError>;
readonly onErrorInDebugger: vscodeTypes.Event<DebuggerError>;
private _onStdOutEmitter: vscodeTypes.EventEmitter<string>;
readonly onStdOut: vscodeTypes.Event<string>;
private _disposables: vscodeTypes.Disposable[] = [];
private _reusedBrowser: ReusedBrowser;

constructor(vscode: vscodeTypes.VSCode, reusedBrowser: ReusedBrowser) {
this._reusedBrowser = reusedBrowser;
this._errorInDebugger = new vscode.EventEmitter();
this.onErrorInDebugger = this._errorInDebugger.event;
this._onErrorInDebuggerEmitter = new vscode.EventEmitter();
this.onErrorInDebugger = this._onErrorInDebuggerEmitter.event;
this._onStdOutEmitter = new vscode.EventEmitter();
this.onStdOut = this._onStdOutEmitter.event;

const self = this;
this._disposables = [
Expand Down Expand Up @@ -71,6 +75,12 @@ export class DebugHighlight {
let lastCatchLocation: Location | undefined;
return {
onDidSendMessage: async message => {
if (message.type === 'event' && message.event === 'output') {
if (message.body.category === 'stdout') {
const output = message.body.output;
self._onStdOutEmitter.fire(output);
}
}
if (!message.success)
return;
if (message.command === 'scopes' && message.type === 'response') {
Expand All @@ -88,7 +98,7 @@ export class DebugHighlight {
const errorVariable = message.body.variables.find((v: any) => v.name === 'playwrightError' && v.type && v.type.toLowerCase() === 'error');
if (errorVariable && lastCatchLocation) {
const error = errorVariable.value as string;
self._errorInDebugger.fire({
self._onErrorInDebuggerEmitter.fire({
error: error.replace(/\\n/g, '\n'),
location: lastCatchLocation!
});
Expand Down
1 change: 1 addition & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ export class Extension implements RunHooks {
runHooks: this,
isUnderTest: this._isUnderTest,
envProvider: this._envProvider.bind(this),
onStdOut: this._debugHighlight.onStdOut.bind(this._debugHighlight),
});
await this._models.addModel(model);
}
Expand Down
57 changes: 56 additions & 1 deletion src/playwrightTestCLI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import { spawn } from 'child_process';
import path from 'path';
import { ConfigFindRelatedTestFilesReport, ConfigListFilesReport } from './listTests';
import { ReporterServer } from './reporterServer';
import { escapeRegex, findNode, runNode } from './utils';
import { escapeRegex, findNode, pathSeparator, runNode } from './utils';
import * as vscodeTypes from './vscodeTypes';
import * as reporterTypes from './upstream/reporter';
import type { PlaywrightTestOptions, PlaywrightTestRunOptions, TestConfig } from './playwrightTestTypes';
import { debugSessionName } from './debugSessionName';

export class PlaywrightTestCLI {
private _vscode: vscodeTypes.VSCode;
Expand Down Expand Up @@ -128,6 +129,60 @@ export class PlaywrightTestCLI {
await reporterServer.wireTestListener(reporter, token);
}

async debugTests(locations: string[], testDirs: string[], options: PlaywrightTestRunOptions, reporter: reporterTypes.ReporterV2, token: vscodeTypes.CancellationToken): Promise<void> {
const configFolder = path.dirname(this._config.configFile);
const configFile = path.basename(this._config.configFile);
const escapedLocations = locations.map(escapeRegex);
const args = ['test',
'-c', configFile,
...escapedLocations,
options.headed ? '--headed' : '',
...(options.projects || []).map(p => `--project=${p}`),
'--repeat-each', '1',
'--retries', '0',
'--timeout', '0',
'--workers', options.workers,
].filter(Boolean);
if (options.grep)
args.push(`--grep=${escapeRegex(options.grep)}`);

{
// For tests.
const relativeLocations = locations.map(f => path.relative(configFolder, f)).map(escapeRegex);
this._log(`${escapeRegex(path.relative(this._config.workspaceFolder, configFolder))}> debug -c ${configFile}${relativeLocations.length ? ' ' + relativeLocations.join(' ') : ''}`);
}

const reporterServer = new ReporterServer(this._vscode);
const testOptions = await this._options.runHooks.onWillRunTests(this._config, true);
try {
await this._vscode.debug.startDebugging(undefined, {
type: 'pwa-node',
name: debugSessionName,
request: 'launch',
cwd: configFolder,
env: {
...process.env,
CI: this._options.isUnderTest ? undefined : process.env.CI,
...this._options.envProvider(),
PW_TEST_CONNECT_WS_ENDPOINT: testOptions.connectWsEndpoint,
...(await reporterServer.env()),
// Reset VSCode's options that affect nested Electron.
ELECTRON_RUN_AS_NODE: undefined,
FORCE_COLOR: '1',
PW_TEST_SOURCE_TRANSFORM: require.resolve('./debugTransform'),
PW_TEST_SOURCE_TRANSFORM_SCOPE: testDirs.join(pathSeparator),
PW_TEST_HTML_REPORT_OPEN: 'never',
PWDEBUG: 'console',
},
program: this._config.cli,
args,
});
await reporterServer.wireTestListener(reporter, token);
} finally {
await this._options.runHooks.onDidRunTests(true);
}
}

async findRelatedTestFiles(files: string[]): Promise<ConfigFindRelatedTestFilesReport> {
const configFolder = path.dirname(this._config.configFile);
const configFile = path.basename(this._config.configFile);
Expand Down
75 changes: 73 additions & 2 deletions src/playwrightTestServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import { TeleReporterReceiver } from './upstream/teleReceiver';
import { TestServerConnection } from './upstream/testServerConnection';
import { startBackend } from './backend';
import type { PlaywrightTestOptions, PlaywrightTestRunOptions, TestConfig } from './playwrightTestTypes';
import { escapeRegex } from './utils';
import { escapeRegex, pathSeparator } from './utils';
import { debugSessionName } from './debugSessionName';

export class PlaywrightTestServer {
private _vscode: vscodeTypes.VSCode;
Expand Down Expand Up @@ -109,13 +110,82 @@ export class PlaywrightTestServer {
token.onCancellationRequested(() => {
testServer.stopTestsNoReply({});
});
testServer.onStdio(params => {
const disposable = testServer.onStdio(params => {
if (params.type === 'stdout')
reporter.onStdOut?.(unwrapString(params));
if (params.type === 'stderr')
reporter.onStdErr?.(unwrapString(params));
});
await this._wireTestServer(testServer, reporter, token);
disposable.dispose();
}

async debugTests(locations: string[], testDirs: string[], options: PlaywrightTestRunOptions, reporter: reporterTypes.ReporterV2, token: vscodeTypes.CancellationToken): Promise<void> {
const configFolder = path.dirname(this._config.configFile);
const configFile = path.basename(this._config.configFile);
const args = ['test-server', '-c', configFile];

const addressPromise = new Promise<string>(f => {
const disposable = this._options.onStdOut(output => {
const match = output.match(/Listening on (.*)/);
if (match) {
disposable.dispose();
f(match[1]);
}
});
});

let testServer: TestServerConnection | undefined;
let disposable: vscodeTypes.Disposable | undefined;
try {
await this._vscode.debug.startDebugging(undefined, {
type: 'pwa-node',
name: debugSessionName,
request: 'launch',
cwd: configFolder,
env: {
...process.env,
CI: this._options.isUnderTest ? undefined : process.env.CI,
...this._options.envProvider(),
// Reset VSCode's options that affect nested Electron.
ELECTRON_RUN_AS_NODE: undefined,
FORCE_COLOR: '1',
PW_TEST_SOURCE_TRANSFORM: require.resolve('./debugTransform'),
PW_TEST_SOURCE_TRANSFORM_SCOPE: testDirs.join(pathSeparator),
PWDEBUG: 'console',
},
program: this._config.cli,
args,
});

if (token?.isCancellationRequested)
return;
const address = await addressPromise;
testServer = new TestServerConnection(address);
await testServer.connect();
await testServer.setSerializer({ serializer: require.resolve('./oopReporter') });
if (token?.isCancellationRequested)
return;

// Locations are regular expressions.
locations = locations.map(escapeRegex);
testServer.runTests({ locations, ...options });
token.onCancellationRequested(() => {
testServer!.stopTestsNoReply({});
});
disposable = testServer.onStdio(params => {
if (params.type === 'stdout')
reporter.onStdOut?.(unwrapString(params));
if (params.type === 'stderr')
reporter.onStdErr?.(unwrapString(params));
});
const testEndPromise = this._wireTestServer(testServer, reporter, token);
await testEndPromise;
} finally {
disposable?.dispose();
testServer?.closeGracefully({});
await this._options.runHooks.onDidRunTests(true);
}
}

async findRelatedTestFiles(files: string[]): Promise<ConfigFindRelatedTestFilesReport> {
Expand Down Expand Up @@ -155,6 +225,7 @@ export class PlaywrightTestServer {
return null;
const testServer = new TestServerConnection(wsEndpoint);
await testServer.connect();
await testServer.setInterceptStdio({ intercept: true });
await testServer.setSerializer({ serializer: require.resolve('./oopReporter') });
return testServer;
}
Expand Down
2 changes: 2 additions & 0 deletions src/playwrightTestTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import { SettingsModel } from './settingsModel';
import { TestServerInterface } from './upstream/testServerInterface';
import type * as vscodeTypes from './vscodeTypes';

export type TestConfig = {
workspaceFolder: string;
Expand All @@ -39,4 +40,5 @@ export type PlaywrightTestOptions = {
isUnderTest: boolean;
playwrightTestLog: string[];
envProvider: () => NodeJS.ProcessEnv;
onStdOut: vscodeTypes.Event<string>;
};
Loading

0 comments on commit e94a823

Please sign in to comment.