diff --git a/src/reusedBrowser.ts b/src/reusedBrowser.ts
index 2508d0140..b39b6d18b 100644
--- a/src/reusedBrowser.ts
+++ b/src/reusedBrowser.ts
@@ -32,6 +32,7 @@ export class ReusedBrowser implements vscodeTypes.Disposable {
private _cancelRecording: (() => void) | undefined;
private _isRunningTests?: 'run' | 'debug';
private _insertedEditActionCount = 0;
+ private _keepBrowserAfterDebugRun = false;
private _envProvider: (configFile: string) => NodeJS.ProcessEnv;
private _disposables: vscodeTypes.Disposable[] = [];
private _pageCount = 0;
@@ -220,6 +221,10 @@ export class ReusedBrowser implements vscodeTypes.Disposable {
return;
if (pageCount)
return;
+ // The page may have been torn down with the debugged test process -
+ // keep the browser around so that the user can inspect and record it.
+ if (this._keepBrowserAfterDebugRun)
+ return;
this._stop();
}
@@ -365,6 +370,7 @@ export class ReusedBrowser implements vscodeTypes.Disposable {
}
async onWillRunTests(config: TestConfig, debug: boolean) {
+ this._keepBrowserAfterDebugRun = false;
if (!this._settingsModel.showBrowser.get() && !debug)
return;
if (!this._checkVersion(config, 'Show & reuse browser'))
@@ -376,10 +382,14 @@ export class ReusedBrowser implements vscodeTypes.Disposable {
}
async onDidRunTests() {
+ const wasDebug = this._isRunningTests === 'debug';
if (!this._settingsModel.showBrowser.get()) {
this._stop();
} else {
- if (!this._pageCount)
+ // Keep the browser around after debugging, so that the user can
+ // inspect and record it, e.g. after stopping at a breakpoint.
+ this._keepBrowserAfterDebugRun = wasDebug;
+ if (!this._pageCount && !this._keepBrowserAfterDebugRun)
this._stop();
}
this._isRunningTests = undefined;
@@ -398,6 +408,7 @@ export class ReusedBrowser implements vscodeTypes.Disposable {
private _resetExtensionState() {
this._insertedEditActionCount = 0;
+ this._keepBrowserAfterDebugRun = false;
this._cancelRecording?.();
this._cancelRecording = undefined;
}
diff --git a/tests/debug-tests.spec.ts b/tests/debug-tests.spec.ts
index f726bb96e..c8d176f60 100644
--- a/tests/debug-tests.spec.ts
+++ b/tests/debug-tests.spec.ts
@@ -175,6 +175,47 @@ test('should end test run when stopping the debugging', async ({ activate }, tes
testRun.token.source.cancel();
});
+test('should keep reused browser when stopping the debugging', async ({ activate, showBrowser }, testInfo) => {
+ test.skip(!showBrowser);
+
+ const { vscode, testController } = await activate({
+ 'playwright.config.js': `module.exports = { testDir: 'tests' }`,
+ 'tests/test.spec.ts': `
+ import { test } from '@playwright/test';
+ test('should fail', async ({ page }) => {
+ // Simulate breakpoint via stalling.
+ console.log('READY TO BREAK');
+ await page.setContent('');
+ await new Promise(() => {});
+ });
+ `,
+ });
+
+ await testController.expandTestItems(/test.spec/);
+ const testItems = testController.findTestItems(/fail/);
+
+ const profile = testController.debugProfile();
+ const testRunPromise = new Promise(f => testController.onDidCreateTestRun(f));
+ void profile.run(testItems);
+ const testRun = await testRunPromise;
+ await expect.poll(() => vscode.debug.output, { timeout: 10000 }).toContain('READY TO BREAK');
+
+ // The debug run has a page in the reused browser.
+ const extension = vscode.extensions[0];
+ await expect.poll(() => extension.reusedBrowserForTest().pageCount()).toBe(1);
+
+ const endPromise = new Promise(f => testRun.onDidEnd(f));
+ vscode.debug.stopDebugging();
+ await endPromise;
+
+ // Stopping the debugging should not tear down the reused browser backend,
+ // so that the user can inspect and record the browser afterwards.
+ await new Promise(f => setTimeout(f, 1000));
+ await expect.poll(() => extension.browserServerWSForTest()).toBeTruthy();
+
+ testRun.token.source.cancel();
+});
+
test('should end test run when stopping the debugging during config parsing', async ({ activate }) => {
const { vscode, testController } = await activate({
'package.json': JSON.stringify({ type: 'module' }),