Skip to content

Commit

Permalink
test(trace-viewer): test harness for embedded trace viewer (#514)
Browse files Browse the repository at this point in the history
  • Loading branch information
ruifigueira authored Aug 9, 2024
1 parent 98c19d6 commit d21186f
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 31 deletions.
2 changes: 2 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const config: PlaywrightTestConfig<WorkerOptions> = {
name: 'default',
use: {
showBrowser: false,
traceViewerMode: 'spawn',
}
},
{
Expand All @@ -46,6 +47,7 @@ const config: PlaywrightTestConfig<WorkerOptions> = {
use: {
overridePlaywrightVersion: 1.43,
showBrowser: false,
traceViewerMode: 'spawn',
}
},
{
Expand Down
32 changes: 29 additions & 3 deletions tests/mock/vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -960,9 +960,16 @@ export class VSCode {
this.window.createWebviewPanel = (viewType: string) => {
const { webview, pagePromise } = this._createWebviewAndPage();
const didDispose = new EventEmitter<void>();
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();
Expand Down Expand Up @@ -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 => {
Expand Down Expand Up @@ -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<any>();
webview.onDidReceiveMessage = eventEmitter.event;
const didReceiveMessage = new EventEmitter<any>();
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) => {
Expand All @@ -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(() => {});
Expand Down
34 changes: 14 additions & 20 deletions tests/spawn-trace-viewer.spec.ts → tests/trace-viewer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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': `
Expand All @@ -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': `
Expand All @@ -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'),
});
});
Expand All @@ -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({
Expand All @@ -102,20 +96,20 @@ 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$/),
});

latch.open();
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': `
Expand All @@ -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'),
});

Expand All @@ -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' }`,
Expand All @@ -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'),
});
Expand All @@ -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'),
});
Expand Down
19 changes: 11 additions & 8 deletions tests/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,14 @@ type Latch = {
type TestFixtures = {
vscode: VSCode,
activate: (files: { [key: string]: string }, options?: { rootDir?: string, workspaceFolders?: [string, any][], env?: Record<string, any> }) => Promise<ActivateResult>;
showTrace: boolean;
envRemoteName?: string;
createLatch: () => Latch;
};

export type WorkerOptions = {
overridePlaywrightVersion?: number;
showBrowser: boolean;
vsCodeVersion: number;
traceViewerMode?: 'spawn' | 'embedded';
};

// Make sure connect tests work with the locally-rolled version.
Expand Down Expand Up @@ -125,14 +124,13 @@ export const test = baseTest.extend<TestFixtures, WorkerOptions>({
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<string, any> }) => {
if (options?.workspaceFolders) {
Expand All @@ -147,10 +145,15 @@ export const test = baseTest.extend<TestFixtures, WorkerOptions>({
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)
Expand Down

0 comments on commit d21186f

Please sign in to comment.