Skip to content

Commit 8555f35

Browse files
committed
Ensures e2e runner gets built in all cases
Switches to commands for reliability/speed
1 parent 109f968 commit 8555f35

File tree

7 files changed

+69
-50
lines changed

7 files changed

+69
-50
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26770,8 +26770,8 @@
2677026770
"rebuild": "pnpm run reset && pnpm run build",
2677126771
"reset": "pnpm run clean && pnpm install --force",
2677226772
"test": "vscode-test",
26773-
"test:e2e": "pnpm run build:e2e-runner && playwright test -c tests/e2e/playwright.config.ts",
26774-
"test:e2e:insiders": "pnpm run build:e2e-runner && set VSCODE_VERSION=insiders && playwright test -c tests/e2e/playwright.config.ts",
26773+
"test:e2e": "playwright test -c tests/e2e/playwright.config.ts",
26774+
"test:e2e:insiders": "set VSCODE_VERSION=insiders && playwright test -c tests/e2e/playwright.config.ts",
2677526775
"build:e2e-runner": "esbuild tests/e2e/runner/src/index.ts --bundle --outfile=tests/e2e/runner/dist/index.js --platform=node --external:vscode --format=cjs",
2677626776
"watch": "webpack --watch --mode development",
2677726777
"watch:extension": "webpack --watch --mode development --config-name extension",

tests/e2e/baseTest.ts

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-disable no-empty-pattern */
2+
import { execSync } from 'node:child_process';
23
import fs from 'node:fs';
34
import os from 'node:os';
45
import path from 'node:path';
@@ -16,6 +17,15 @@ export type { VSCode } from './fixtures/vscodeEvaluator';
1617

1718
export const MaxTimeout = 10000;
1819

20+
/** Ensures the E2E runner is built before tests run */
21+
function ensureRunnerBuilt(): void {
22+
const runnerDist = path.join(__dirname, 'runner', 'dist', 'index.js');
23+
if (!fs.existsSync(runnerDist)) {
24+
const rootDir = path.resolve(__dirname, '../..');
25+
execSync('pnpm run build:e2e-runner', { cwd: rootDir, stdio: 'inherit' });
26+
}
27+
}
28+
1929
/** Default VS Code settings applied to all E2E tests */
2030
const defaultUserSettings: Record<string, unknown> = {
2131
// Disable telemetry
@@ -52,23 +62,17 @@ export interface LaunchOptions {
5262
}
5363

5464
export interface VSCodeInstance {
55-
page: Page;
56-
electronApp: ElectronApplication;
65+
electron: {
66+
app: ElectronApplication;
67+
/** Path to the VS Code executable for this test instance */
68+
executablePath: string;
69+
/** Launch arguments used for this VS Code instance (for reuse in sequence editor, etc.) */
70+
args: string[];
71+
/** Path to the workspace opened in VS Code */
72+
workspacePath: string;
73+
};
5774
gitlens: GitLensPage;
58-
/**
59-
* Evaluate a function in the VS Code Extension Host context.
60-
* The function receives the `vscode` module as its first argument.
61-
*
62-
* @example
63-
* ```ts
64-
* await vscode.evaluate(vscode => {
65-
* vscode.commands.executeCommand('gitlens.showCommitGraph');
66-
* });
67-
*
68-
* const version = await vscode.evaluate(vscode => vscode.version);
69-
* ```
70-
*/
71-
evaluate: VSCodeEvaluator['evaluate'];
75+
page: Page;
7276
}
7377

7478
/** Base fixtures for all E2E tests */
@@ -94,6 +98,9 @@ export const test = base.extend<BaseFixtures, WorkerFixtures>({
9498
// vscode launches VS Code with GitLens extension (shared per worker)
9599
vscode: [
96100
async ({ vscodeOptions }, use) => {
101+
// Ensure the E2E runner is built (handles VS Code extension skipping globalSetup)
102+
ensureRunnerBuilt();
103+
97104
const tempDir = await createTmpDir();
98105
const vscodePath = await downloadAndUnzipVSCode(vscodeOptions.vscodeVersion ?? 'stable');
99106
const extensionPath = path.join(__dirname, '..', '..');
@@ -112,7 +119,7 @@ export const test = base.extend<BaseFixtures, WorkerFixtures>({
112119
// Run setup callback if provided, otherwise open extension folder
113120
const workspacePath = vscodeOptions.setup ? await vscodeOptions.setup() : extensionPath;
114121

115-
const electronApp = await _electron.launch({
122+
const options: { executablePath: string; args: string[] } = {
116123
executablePath: vscodePath,
117124
args: [
118125
'--no-sandbox',
@@ -127,7 +134,9 @@ export const test = base.extend<BaseFixtures, WorkerFixtures>({
127134
`--user-data-dir=${userDataDir}`,
128135
workspacePath,
129136
],
130-
});
137+
} satisfies Parameters<typeof _electron.launch>[0];
138+
139+
const electronApp = await _electron.launch(options);
131140

132141
// Connect to the VS Code test server using Playwright's internal API
133142
const evaluator = await VSCodeEvaluator.connect(electronApp);
@@ -140,10 +149,9 @@ export const test = base.extend<BaseFixtures, WorkerFixtures>({
140149
await gitlens.waitForActivation();
141150

142151
await use({
143-
page: page,
144-
electronApp: electronApp,
152+
electron: { app: electronApp, ...options, workspacePath: workspacePath },
145153
gitlens: gitlens,
146-
evaluate: evaluate,
154+
page: page,
147155
} satisfies VSCodeInstance);
148156

149157
// Cleanup

tests/e2e/fixtures/vscodeEvaluator.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import type { ChildProcess } from 'child_process';
1111
import type { EventEmitter } from 'events';
1212
import readline from 'readline';
1313
import type { ElectronApplication } from '@playwright/test';
14-
import { _electron } from '@playwright/test';
1514

1615
// Re-export vscode types for use in evaluate callbacks
1716
export type VSCode = typeof import('vscode');
@@ -52,9 +51,9 @@ export class VSCodeEvaluator {
5251
*/
5352
static async connect(electronApp: ElectronApplication, timeout = 30000): Promise<VSCodeEvaluator> {
5453
// Access Playwright's internal implementation to get the process
55-
// The _electron._connection.toImpl() method converts public API objects to internal implementations
54+
// The electronApp._connection.toImpl() method converts public API objects to internal implementations
5655

57-
const connection = (_electron as any)._connection;
56+
const connection = (electronApp as any)._connection;
5857
const electronAppImpl = connection.toImpl(electronApp) as ElectronAppImpl;
5958
const process = electronAppImpl._process;
6059

tests/e2e/pageObjects/components/panel.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,21 @@ export class Panel {
2424
}
2525

2626
async close(): Promise<void> {
27-
if (!(await this.isVisible())) return;
27+
await this.vscode.executeCommand('workbench.action.closePanel', 'View: Hide Panel');
2828

29-
// await this.vscode.executeCommand('View: Hide Panel', 1);
30-
await this.toggle.click();
31-
await this.container.waitFor({ state: 'hidden', timeout: MaxTimeout });
29+
// if (!(await this.isVisible())) return;
30+
31+
// await this.toggle.click();
32+
// await this.container.waitFor({ state: 'hidden', timeout: MaxTimeout });
3233
}
3334

3435
async open(): Promise<void> {
35-
if (await this.isVisible()) return;
36+
await this.vscode.executeCommand('workbench.action.focusPanel', 'View: Focus into Panel');
37+
38+
// if (await this.isVisible()) return;
3639

37-
// await this.vscode.executeCommand('View: Focus into Panel', 1);
38-
await this.toggle.click();
39-
await this.container.waitFor({ state: 'visible', timeout: MaxTimeout });
40+
// await this.toggle.click();
41+
// await this.container.waitFor({ state: 'visible', timeout: MaxTimeout });
4042
}
4143

4244
/**

tests/e2e/pageObjects/components/secondarySidebar.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,21 @@ export class SecondarySidebar {
2424
}
2525

2626
async close(): Promise<void> {
27-
if (!(await this.isVisible())) return;
27+
await this.vscode.executeCommand('workbench.action.closeAuxiliaryBar', 'View: Close Secondary Side Bar');
2828

29-
// await this.vscode.executeCommand('View: Close Secondary Side Bar', 1);
30-
await this.toggle.click();
31-
await this.container.waitFor({ state: 'hidden', timeout: MaxTimeout });
29+
// if (!(await this.isVisible())) return;
30+
31+
// await this.toggle.click();
32+
// await this.container.waitFor({ state: 'hidden', timeout: MaxTimeout });
3233
}
3334

3435
async open(): Promise<void> {
35-
if (await this.isVisible()) return;
36+
await this.vscode.executeCommand('workbench.action.focusAuxiliaryBar', 'View: Focus into Secondary Side Bar');
37+
38+
// if (await this.isVisible()) return;
3639

37-
// await this.vscode.executeCommand('View: Focus into Secondary Side Bar', 1);
38-
await this.toggle.click();
39-
await this.container.waitFor({ state: 'visible', timeout: MaxTimeout });
40+
// await this.toggle.click();
41+
// await this.container.waitFor({ state: 'visible', timeout: MaxTimeout });
4042
}
4143

4244
/**

tests/e2e/pageObjects/components/sidebar.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,21 @@ export class Sidebar {
2424
}
2525

2626
async close(): Promise<void> {
27-
if (!(await this.isVisible())) return;
27+
await this.vscode.executeCommand('workbench.action.closeSidebar', 'View: Close Primary Side Bar');
2828

29-
// await this.vscode.executeCommand('View: Close Primary Side Bar', 1);
30-
await this.toggle.click();
31-
await this.container.waitFor({ state: 'hidden', timeout: MaxTimeout });
29+
// if (!(await this.isVisible())) return;
30+
31+
// await this.toggle.click();
32+
// await this.container.waitFor({ state: 'hidden', timeout: MaxTimeout });
3233
}
3334

3435
async open(): Promise<void> {
35-
if (await this.isVisible()) return;
36+
await this.vscode.executeCommand('workbench.action.focusSideBar', 'View: Focus into Primary Side Bar');
37+
38+
// if (await this.isVisible()) return;
3639

37-
// await this.vscode.executeCommand('View: Focus into Primary Side Bar', 1);
38-
await this.toggle.click();
39-
await this.container.waitFor({ state: 'visible', timeout: MaxTimeout });
40+
// await this.toggle.click();
41+
// await this.container.waitFor({ state: 'visible', timeout: MaxTimeout });
4042
}
4143

4244
/**

tests/e2e/setup.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
import { execSync } from 'node:child_process';
2+
import path from 'node:path';
13
import { downloadAndUnzipVSCode } from '@vscode/test-electron';
24

35
// eslint-disable-next-line import-x/no-default-export
46
export default async (): Promise<void> => {
7+
// Build the E2E runner (required for VS Code extension host)
8+
const rootDir = path.resolve(__dirname, '../..');
9+
execSync('pnpm run build:e2e-runner', { cwd: rootDir, stdio: 'inherit' });
10+
511
await downloadAndUnzipVSCode('stable');
612
};

0 commit comments

Comments
 (0)