diff --git a/playwright.config.ts b/playwright.config.ts index 4ba15f36e..d540a6c8f 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -33,6 +33,7 @@ const config: PlaywrightTestConfig = { name: 'default', use: { showBrowser: false, + traceViewerMode: 'spawn', } }, { @@ -46,6 +47,7 @@ const config: PlaywrightTestConfig = { use: { overridePlaywrightVersion: 1.43, showBrowser: false, + traceViewerMode: 'spawn', } }, { diff --git a/tests/mock/vscode.ts b/tests/mock/vscode.ts index 4527eba1d..9898f7bdb 100644 --- a/tests/mock/vscode.ts +++ b/tests/mock/vscode.ts @@ -960,9 +960,16 @@ export class VSCode { this.window.createWebviewPanel = (viewType: string) => { const { webview, pagePromise } = this._createWebviewAndPage(); const didDispose = new EventEmitter(); + const didChangeViewState = new EventEmitter<{ webviewPanel: any }>(); const panel: any = {}; panel.onDidDispose = didDispose.event; + panel.onDidChangeViewState = didChangeViewState.event; panel.webview = webview; + panel.visible = true; + webview.onDidChangeVisibility(visibilityState => { + panel.visible = visibilityState === 'visible'; + didChangeViewState.fire({ webviewPanel: panel }); + }); pagePromise.then(webview => { webview.on('close', () => { panel.dispose(); @@ -1067,6 +1074,7 @@ export class VSCode { 'playwright.env': {}, 'playwright.reuseBrowser': false, 'playwright.showTrace': false, + 'playwright.embeddedTraceViewer': false, 'workbench.colorTheme': 'Dark Modern', }; this.workspace.getConfiguration = scope => { @@ -1108,12 +1116,21 @@ export class VSCode { return webviews ? [...webviews] : []; } + async changeVisibility(webview: Page, state: 'visible' | 'hidden') { + if (state === 'visible') + await webview.goto('http://localhost'); + else + await webview.goto('http://localhost/hidden'); + } + private _createWebviewAndPage() { let initializedPage: Page | undefined = undefined; const webview: any = {}; webview.asWebviewUri = uri => path.relative(this.context.extensionUri.fsPath, uri.fsPath).replace(/\\/g, '/'); - const eventEmitter = new EventEmitter(); - webview.onDidReceiveMessage = eventEmitter.event; + const didReceiveMessage = new EventEmitter(); + const didChangeVisibility = new EventEmitter<'visible' | 'hidden'>(); + webview.onDidReceiveMessage = didReceiveMessage.event; + webview.onDidChangeVisibility = didChangeVisibility.event; webview.cspSource = 'http://localhost/'; const pendingMessages: any[] = []; webview.postMessage = (data: any) => { @@ -1136,17 +1153,26 @@ export class VSCode { route.continue(); } else if (url === 'http://localhost/') { route.fulfill({ body: webview.html }); + } else if (url === 'http://localhost/hidden') { + route.fulfill({ body: 'hidden webview' }); } else { const suffix = url.substring('http://localhost/'.length); const buffer = fs.readFileSync(path.join(this.context.extensionUri.fsPath, suffix)); route.fulfill({ body: buffer }); } }); + page.on('load', () => { + const url = page.url(); + if (url === 'http://localhost/') + didChangeVisibility.fire('visible'); + else if (url === 'http://localhost/hidden') + didChangeVisibility.fire('hidden'); + }); await page.addInitScript(() => { globalThis.acquireVsCodeApi = () => globalThis; }); await page.goto('http://localhost'); - await page.exposeFunction('postMessage', (data: any) => eventEmitter.fire(data)); + await page.exposeFunction('postMessage', (data: any) => didReceiveMessage.fire(data)); this.context.subscriptions.push({ dispose: () => { context.close().catch(() => {}); diff --git a/tests/spawn-trace-viewer.spec.ts b/tests/trace-viewer.spec.ts similarity index 91% rename from tests/spawn-trace-viewer.spec.ts rename to tests/trace-viewer.spec.ts index e6b13ccaf..91a814606 100644 --- a/tests/spawn-trace-viewer.spec.ts +++ b/tests/trace-viewer.spec.ts @@ -16,15 +16,9 @@ import { enableConfigs, expect, selectConfig, selectTestItem, test, traceViewerInfo } from './utils'; -test.beforeEach(({ showBrowser }) => { - test.skip(showBrowser); - // prevents spawn trace viewer process from opening in browser - process.env.PWTEST_UNDER_TEST = '1'; -}); - -test.use({ showTrace: true, envRemoteName: 'ssh-remote' }); +test.skip(({ traceViewerMode }) => !traceViewerMode); -test('@smoke should open trace viewer', async ({ activate }) => { +test('@smoke should open trace viewer', async ({ activate, traceViewerMode }) => { const { vscode, testController } = await activate({ 'playwright.config.js': `module.exports = { testDir: 'tests' }`, 'tests/test.spec.ts': ` @@ -38,12 +32,12 @@ test('@smoke should open trace viewer', async ({ activate }) => { selectTestItem(testController.findTestItems(/pass/)[0]); await expect.poll(() => traceViewerInfo(vscode)).toMatchObject({ - type: 'spawn', + type: traceViewerMode, traceFile: expect.stringContaining('pass'), }); }); -test('should change opened file in trace viewer', async ({ activate }) => { +test('should change opened file in trace viewer', async ({ activate, traceViewerMode }) => { const { vscode, testController } = await activate({ 'playwright.config.js': `module.exports = { testDir: 'tests' }`, 'tests/test.spec.ts': ` @@ -59,14 +53,14 @@ test('should change opened file in trace viewer', async ({ activate }) => { selectTestItem(testController.findTestItems(/one/)[0]); await expect.poll(() => traceViewerInfo(vscode)).toMatchObject({ - type: 'spawn', + type: traceViewerMode, traceFile: expect.stringContaining('one'), }); selectTestItem(testController.findTestItems(/two/)[0]); await expect.poll(() => traceViewerInfo(vscode)).toMatchObject({ - type: 'spawn', + type: traceViewerMode, traceFile: expect.stringContaining('two'), }); }); @@ -86,7 +80,7 @@ test('should not open trace viewer if test did not run', async ({ activate }) => await expect.poll(() => traceViewerInfo(vscode)).toBeUndefined(); }); -test('should refresh trace viewer while test is running', async ({ activate, createLatch }) => { +test('should refresh trace viewer while test is running', async ({ activate, createLatch, traceViewerMode }) => { const latch = createLatch(); const { vscode, testController } = await activate({ @@ -102,7 +96,7 @@ test('should refresh trace viewer while test is running', async ({ activate, cre const testRunPromise = testController.run(); await expect.poll(() => traceViewerInfo(vscode)).toMatchObject({ - type: 'spawn', + type: traceViewerMode, traceFile: expect.stringMatching(/\.json$/), }); @@ -110,12 +104,12 @@ test('should refresh trace viewer while test is running', async ({ activate, cre await testRunPromise; await expect.poll(() => traceViewerInfo(vscode)).toMatchObject({ - type: 'spawn', + type: traceViewerMode, traceFile: expect.stringMatching(/\.zip$/), }); }); -test('should close trace viewer if test configs refreshed', async ({ activate }) => { +test('should close trace viewer if test configs refreshed', async ({ activate, traceViewerMode }) => { const { vscode, testController } = await activate({ 'playwright.config.js': `module.exports = { testDir: 'tests' }`, 'tests/test.spec.ts': ` @@ -129,7 +123,7 @@ test('should close trace viewer if test configs refreshed', async ({ activate }) selectTestItem(testController.findTestItems(/pass/)[0]); await expect.poll(() => traceViewerInfo(vscode)).toMatchObject({ - type: 'spawn', + type: traceViewerMode, traceFile: expect.stringContaining('pass'), }); @@ -138,7 +132,7 @@ test('should close trace viewer if test configs refreshed', async ({ activate }) await expect.poll(() => traceViewerInfo(vscode)).toBeUndefined(); }); -test('should open new trace viewer when another test config is selected', async ({ activate }) => { +test('should open new trace viewer when another test config is selected', async ({ activate, traceViewerMode }) => { const { vscode, testController } = await activate({ 'playwright1.config.js': `module.exports = { testDir: 'tests1' }`, 'playwright2.config.js': `module.exports = { testDir: 'tests2' }`, @@ -162,7 +156,7 @@ test('should open new trace viewer when another test config is selected', async selectTestItem(testItems[0]); await expect.poll(() => traceViewerInfo(vscode)).toMatchObject({ - type: 'spawn', + type: traceViewerMode, serverUrlPrefix: expect.stringContaining('http'), testConfigFile: expect.stringContaining('playwright1.config.js'), }); @@ -177,7 +171,7 @@ test('should open new trace viewer when another test config is selected', async selectTestItem(testItems[0]); await expect.poll(() => traceViewerInfo(vscode)).toMatchObject({ - type: 'spawn', + type: traceViewerMode, serverUrlPrefix: expect.stringContaining('http'), testConfigFile: expect.stringContaining('playwright2.config.js'), }); diff --git a/tests/utils.ts b/tests/utils.ts index e96c35e7d..92e318c20 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -37,8 +37,6 @@ type Latch = { type TestFixtures = { vscode: VSCode, activate: (files: { [key: string]: string }, options?: { rootDir?: string, workspaceFolders?: [string, any][], env?: Record }) => Promise; - showTrace: boolean; - envRemoteName?: string; createLatch: () => Latch; }; @@ -46,6 +44,7 @@ export type WorkerOptions = { overridePlaywrightVersion?: number; showBrowser: boolean; vsCodeVersion: number; + traceViewerMode?: 'spawn' | 'embedded'; }; // Make sure connect tests work with the locally-rolled version. @@ -125,14 +124,13 @@ export const test = baseTest.extend({ overridePlaywrightVersion: [undefined, { option: true, scope: 'worker' }], showBrowser: [false, { option: true, scope: 'worker' }], vsCodeVersion: [1.86, { option: true, scope: 'worker' }], - showTrace: false, - envRemoteName: undefined, + traceViewerMode: [undefined, { option: true, scope: 'worker' }], vscode: async ({ browser, vsCodeVersion }, use) => { await use(new VSCode(vsCodeVersion, path.resolve(__dirname, '..'), browser)); }, - activate: async ({ vscode, showBrowser, showTrace, envRemoteName, overridePlaywrightVersion }, use, testInfo) => { + activate: async ({ vscode, showBrowser, overridePlaywrightVersion, traceViewerMode }, use, testInfo) => { const instances: VSCode[] = []; await use(async (files: { [key: string]: string }, options?: { rootDir?: string, workspaceFolders?: [string, any][], env?: Record }) => { if (options?.workspaceFolders) { @@ -147,10 +145,15 @@ export const test = baseTest.extend({ configuration.update('env', options.env); if (showBrowser) configuration.update('reuseBrowser', true); - if (showTrace) + if (traceViewerMode) { configuration.update('showTrace', true); - if (envRemoteName) - vscode.env.remoteName = envRemoteName; + + // prevents spawn trace viewer process from opening app and browser + vscode.env.remoteName = 'ssh-remote'; + process.env.PWTEST_UNDER_TEST = '1'; + } + if (traceViewerMode === 'embedded') + configuration.update('embeddedTraceViewer', true); const extension = new Extension(vscode, vscode.context); if (overridePlaywrightVersion)