From e94a82316ca54e45f27025e5f44908a344b8f1a4 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Mon, 1 Apr 2024 09:07:16 -0700 Subject: [PATCH] chore: move debug to test server (#450) --- package-lock.json | 46 ++++++++--------- package.json | 2 +- src/debugHighlight.ts | 18 +++++-- src/extension.ts | 1 + src/playwrightTestCLI.ts | 57 +++++++++++++++++++- src/playwrightTestServer.ts | 75 ++++++++++++++++++++++++++- src/playwrightTestTypes.ts | 2 + src/testModel.ts | 77 ++++++++-------------------- src/upstream/testServerConnection.ts | 22 ++++---- src/upstream/testServerInterface.ts | 2 + tests/debug-tests.spec.ts | 3 +- tests/mock/vscode.ts | 12 ++++- 12 files changed, 217 insertions(+), 100 deletions(-) diff --git a/package-lock.json b/package-lock.json index c07f988b7..534c46733 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,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", @@ -857,12 +857,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.43.0-beta-1711554436000", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.0-beta-1711554436000.tgz", - "integrity": "sha512-j4tokWU1MZovN5US681d9MvW6eVJ0wtRyLzCYyxo5MiG+wJOnHUZSsZewPTXx3YKGVWqX+hX1dB6qCglSVV02A==", + "version": "1.43.0-beta-1711849714000", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.0-beta-1711849714000.tgz", + "integrity": "sha512-icFamqLUxKkoTEPwN+ZNIFWqUQ0WqfP5x8d6hdxZbpDmsngyPfp+J3iYKDmHbFfrLTI4SjW62TaILf/HKLjMfw==", "dev": true, "dependencies": { - "playwright": "1.43.0-beta-1711554436000" + "playwright": "1.43.0-beta-1711849714000" }, "bin": { "playwright": "cli.js" @@ -3749,12 +3749,12 @@ } }, "node_modules/playwright": { - "version": "1.43.0-beta-1711554436000", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.0-beta-1711554436000.tgz", - "integrity": "sha512-Oynd6RVx5iXPhBPZNeDSvhOg7PHghqdock3YGK1+j5jTMS/Lud830xCAMkPobtp0gUr38emWsW35RD9tUYaVvA==", + "version": "1.43.0-beta-1711849714000", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.0-beta-1711849714000.tgz", + "integrity": "sha512-BWA2VqEca1CwDZmxLmwwKI7OuWJBGi+b4RYF3lWwwN/WW5p79HiL6v/U1uB78PGAkRyn7Y6Rwpuhb0GUAnBIPQ==", "dev": true, "dependencies": { - "playwright-core": "1.43.0-beta-1711554436000" + "playwright-core": "1.43.0-beta-1711849714000" }, "bin": { "playwright": "cli.js" @@ -3767,9 +3767,9 @@ } }, "node_modules/playwright-core": { - "version": "1.43.0-beta-1711554436000", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0-beta-1711554436000.tgz", - "integrity": "sha512-jaDUmMC7tuRL4Qs19d9JN42hoQ4kFlvzFt94T8Dq5T5yVG5e7DUFoUguUmN+cxzcqBllYGRdDYgWu3X1gIkb/w==", + "version": "1.43.0-beta-1711849714000", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0-beta-1711849714000.tgz", + "integrity": "sha512-5o3VhdBqqgks1lJ70Gjyirx1yJtc6wNd+ZM+T4+m3DWwvyN0Ygh9mGv5qdwf3b5sdP3nd/zLO7emUywY4GkhfA==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -5295,12 +5295,12 @@ "optional": true }, "@playwright/test": { - "version": "1.43.0-beta-1711554436000", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.0-beta-1711554436000.tgz", - "integrity": "sha512-j4tokWU1MZovN5US681d9MvW6eVJ0wtRyLzCYyxo5MiG+wJOnHUZSsZewPTXx3YKGVWqX+hX1dB6qCglSVV02A==", + "version": "1.43.0-beta-1711849714000", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.0-beta-1711849714000.tgz", + "integrity": "sha512-icFamqLUxKkoTEPwN+ZNIFWqUQ0WqfP5x8d6hdxZbpDmsngyPfp+J3iYKDmHbFfrLTI4SjW62TaILf/HKLjMfw==", "dev": true, "requires": { - "playwright": "1.43.0-beta-1711554436000" + "playwright": "1.43.0-beta-1711849714000" } }, "@types/babel__core": { @@ -7315,19 +7315,19 @@ "dev": true }, "playwright": { - "version": "1.43.0-beta-1711554436000", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.0-beta-1711554436000.tgz", - "integrity": "sha512-Oynd6RVx5iXPhBPZNeDSvhOg7PHghqdock3YGK1+j5jTMS/Lud830xCAMkPobtp0gUr38emWsW35RD9tUYaVvA==", + "version": "1.43.0-beta-1711849714000", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.0-beta-1711849714000.tgz", + "integrity": "sha512-BWA2VqEca1CwDZmxLmwwKI7OuWJBGi+b4RYF3lWwwN/WW5p79HiL6v/U1uB78PGAkRyn7Y6Rwpuhb0GUAnBIPQ==", "dev": true, "requires": { "fsevents": "2.3.2", - "playwright-core": "1.43.0-beta-1711554436000" + "playwright-core": "1.43.0-beta-1711849714000" } }, "playwright-core": { - "version": "1.43.0-beta-1711554436000", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0-beta-1711554436000.tgz", - "integrity": "sha512-jaDUmMC7tuRL4Qs19d9JN42hoQ4kFlvzFt94T8Dq5T5yVG5e7DUFoUguUmN+cxzcqBllYGRdDYgWu3X1gIkb/w==", + "version": "1.43.0-beta-1711849714000", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0-beta-1711849714000.tgz", + "integrity": "sha512-5o3VhdBqqgks1lJ70Gjyirx1yJtc6wNd+ZM+T4+m3DWwvyN0Ygh9mGv5qdwf3b5sdP3nd/zLO7emUywY4GkhfA==", "dev": true }, "prebuild-install": { diff --git a/package.json b/package.json index c10a56a50..7b8cd5745 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/debugHighlight.ts b/src/debugHighlight.ts index a17786604..9ae0f4380 100644 --- a/src/debugHighlight.ts +++ b/src/debugHighlight.ts @@ -25,15 +25,19 @@ export type DebuggerError = { error: string, location: Location }; export class DebugHighlight { private _debugSessions = new Map(); - private _errorInDebugger: vscodeTypes.EventEmitter; + private _onErrorInDebuggerEmitter: vscodeTypes.EventEmitter; readonly onErrorInDebugger: vscodeTypes.Event; + private _onStdOutEmitter: vscodeTypes.EventEmitter; + readonly onStdOut: vscodeTypes.Event; 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 = [ @@ -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') { @@ -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! }); diff --git a/src/extension.ts b/src/extension.ts index cc90f2bc1..750d3979e 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -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); } diff --git a/src/playwrightTestCLI.ts b/src/playwrightTestCLI.ts index 9352d2fc1..09a95a9f1 100644 --- a/src/playwrightTestCLI.ts +++ b/src/playwrightTestCLI.ts @@ -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; @@ -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 { + 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 { const configFolder = path.dirname(this._config.configFile); const configFile = path.basename(this._config.configFile); diff --git a/src/playwrightTestServer.ts b/src/playwrightTestServer.ts index acd7c8654..879e58df5 100644 --- a/src/playwrightTestServer.ts +++ b/src/playwrightTestServer.ts @@ -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; @@ -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 { + const configFolder = path.dirname(this._config.configFile); + const configFile = path.basename(this._config.configFile); + const args = ['test-server', '-c', configFile]; + + const addressPromise = new Promise(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 { @@ -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; } diff --git a/src/playwrightTestTypes.ts b/src/playwrightTestTypes.ts index e8df13378..7f2925300 100644 --- a/src/playwrightTestTypes.ts +++ b/src/playwrightTestTypes.ts @@ -16,6 +16,7 @@ import { SettingsModel } from './settingsModel'; import { TestServerInterface } from './upstream/testServerInterface'; +import type * as vscodeTypes from './vscodeTypes'; export type TestConfig = { workspaceFolder: string; @@ -39,4 +40,5 @@ export type PlaywrightTestOptions = { isUnderTest: boolean; playwrightTestLog: string[]; envProvider: () => NodeJS.ProcessEnv; + onStdOut: vscodeTypes.Event; }; diff --git a/src/testModel.ts b/src/testModel.ts index c2b464583..eee974ea3 100644 --- a/src/testModel.ts +++ b/src/testModel.ts @@ -16,7 +16,7 @@ import { WorkspaceChange } from './workspaceObserver'; import * as vscodeTypes from './vscodeTypes'; -import { escapeRegex, pathSeparator, resolveSourceMap } from './utils'; +import { resolveSourceMap } from './utils'; import { ConfigListFilesReport, ProjectConfigWithFiles } from './listTests'; import * as reporterTypes from './upstream/reporter'; import { TeleSuite } from './upstream/teleReceiver'; @@ -25,8 +25,6 @@ import path from 'path'; import { DisposableBase } from './disposableBase'; import { MultiMap } from './multimap'; import { TestServerInterface } from './upstream/testServerInterface'; -import { ReporterServer } from './reporterServer'; -import { debugSessionName } from './debugSessionName'; import { PlaywrightTestServer } from './playwrightTestServer'; import type { RunHooks, TestConfig } from './playwrightTestTypes'; import { PlaywrightTestCLI } from './playwrightTestCLI'; @@ -47,6 +45,7 @@ export type TestModelOptions = { isUnderTest: boolean; playwrightTestLog: string[]; envProvider: () => NodeJS.ProcessEnv; + onStdOut: vscodeTypes.Event; }; type AllRunOptions = Parameters[0]; @@ -386,65 +385,29 @@ export class TestModel { async debugTests(projects: TestProject[], locations: string[] | null, reporter: reporterTypes.ReporterV2, parametrizedTestTitle: string | undefined, token: vscodeTypes.CancellationToken) { locations = locations || []; - const testDirs = projects.map(p => p.project.testDir); - const configFolder = path.dirname(this.config.configFile); - const configFile = path.basename(this.config.configFile); - locations = locations || []; - const escapedLocations = locations.map(escapeRegex); - const args = ['test', - '-c', configFile, - ...escapedLocations, - '--headed', - ...projects.map(p => p.name).filter(Boolean).map(p => `--project=${p}`), - '--repeat-each', '1', - '--retries', '0', - '--timeout', '0', - '--workers', '1' - ]; - if (parametrizedTestTitle) - args.push(`--grep=${escapeRegex(parametrizedTestTitle)}`); - - { - // 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); + const locationArg = locations ? locations : []; + if (token?.isCancellationRequested) + return; + const externalOptions = await this._options.runHooks.onWillRunTests(this.config, true); + const options: PlaywrightTestRunOptions = { + grep: parametrizedTestTitle, + projects: projects.length ? projects.map(p => p.name).filter(Boolean) : undefined, + headed: !this._options.isUnderTest, + workers: 1, + trace: 'off', + reuseContext: false, + connectWsEndpoint: externalOptions.connectWsEndpoint, + }; 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._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); + if (token?.isCancellationRequested) + return; + const testDirs = new Set(projects.map(p => p.project.testDir)); + await this._playwrightTest.debugTests(locationArg, [...testDirs], options, reporter, token); } finally { - await this._options.runHooks.onDidRunTests(true); + await this._options.runHooks.onDidRunTests(false); } } - private _log(line: string) { - this._options.playwrightTestLog.push(line); - } - private _mapFilesToSources(testDirs: string[], files: Set): string[] { const result = new Set(); for (const file of files) { diff --git a/src/upstream/testServerConnection.ts b/src/upstream/testServerConnection.ts index 1bb18692f..43fe3f206 100644 --- a/src/upstream/testServerConnection.ts +++ b/src/upstream/testServerConnection.ts @@ -117,11 +117,11 @@ export class TestServerConnection implements TestServerInterface, TestServerInte } async ping(params: Parameters[0]): ReturnType { - await this._sendMessage('ping'); + await this._sendMessage('ping', params); } async pingNoReply(params: Parameters[0]) { - this._sendMessageNoReply('ping'); + this._sendMessageNoReply('ping', params); } async watch(params: Parameters[0]): ReturnType { @@ -153,19 +153,19 @@ export class TestServerConnection implements TestServerInterface, TestServerInte } async checkBrowsers(params: Parameters[0]): ReturnType { - return await this._sendMessage('checkBrowsers'); + return await this._sendMessage('checkBrowsers', params); } async installBrowsers(params: Parameters[0]): ReturnType { - await this._sendMessage('installBrowsers'); + await this._sendMessage('installBrowsers', params); } async runGlobalSetup(params: Parameters[0]): ReturnType { - return await this._sendMessage('runGlobalSetup'); + return await this._sendMessage('runGlobalSetup', params); } async runGlobalTeardown(params: Parameters[0]): ReturnType { - return await this._sendMessage('runGlobalTeardown'); + return await this._sendMessage('runGlobalTeardown', params); } async listFiles(params: Parameters[0]): ReturnType { @@ -185,14 +185,18 @@ export class TestServerConnection implements TestServerInterface, TestServerInte } async stopTests(params: Parameters[0]): ReturnType { - await this._sendMessage('stopTests'); + await this._sendMessage('stopTests', params); } stopTestsNoReply(params: Parameters[0]) { - this._sendMessageNoReply('stopTests'); + this._sendMessageNoReply('stopTests', params); + } + + async setInterceptStdio(params: Parameters[0]): ReturnType { + await this._sendMessage('setInterceptStdio', params); } async closeGracefully(params: Parameters[0]): ReturnType { - await this._sendMessage('closeGracefully'); + await this._sendMessage('closeGracefully', params); } } diff --git a/src/upstream/testServerInterface.ts b/src/upstream/testServerInterface.ts index 523f442f4..2112f77fc 100644 --- a/src/upstream/testServerInterface.ts +++ b/src/upstream/testServerInterface.ts @@ -90,6 +90,8 @@ export interface TestServerInterface { stopTests(params: {}): Promise; + setInterceptStdio(params: { intercept: boolean }): Promise; + closeGracefully(params: {}): Promise; } diff --git a/tests/debug-tests.spec.ts b/tests/debug-tests.spec.ts index 13fefc385..7ecb9465c 100644 --- a/tests/debug-tests.spec.ts +++ b/tests/debug-tests.spec.ts @@ -97,8 +97,7 @@ test('should debug error', async ({ activate }, testInfo) => { profile.run(testItems); const testRun = await testRunPromise; - while (!vscode.debug.output.includes('READY TO BREAK')) - await new Promise(f => setTimeout(f, 100)); + await expect.poll(() => vscode.debug.output).toContain('READY TO BREAK'); vscode.debug.simulateStoppedOnError('Error on line 10', { file: testInfo.outputPath('tests/test.spec.ts'), line: 10 }); diff --git a/tests/mock/vscode.ts b/tests/mock/vscode.ts index 29d1f186c..91dcce2e1 100644 --- a/tests/mock/vscode.ts +++ b/tests/mock/vscode.ts @@ -650,7 +650,17 @@ class Debug { env: configuration.env, }); - subprocess.stdout.on('data', data => this.output += data.toString()); + subprocess.stdout.on('data', data => { + this.output += data.toString(); + this._dapSniffer.onDidSendMessage({ + type: 'event', + event: 'output', + body: { + category: 'stdout', + output: data.toString(), + } + }); + }); subprocess.stderr.on('data', data => this.output += data.toString()); return true; }