Skip to content

Commit 8b59156

Browse files
committed
Address Copilot review comments
1 parent 3ad174d commit 8b59156

5 files changed

Lines changed: 31 additions & 12 deletions

File tree

core/electron/src/test/frontend/utils/backend.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { ElectronHost } from "../../../ElectronBackend";
77

88
async function init() {
9-
const cacheDir = process.env.ELECTRON_CACHE_DIR;
9+
const cacheDir = process.env.VITEST_ELECTRON_CACHE_DIR ?? process.env.ELECTRON_CACHE_DIR;
1010
await ElectronHost.startup(cacheDir ? {
1111
iModelHost: {
1212
cacheDir,

tools/vitest-certa-bridge/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ The not-yet-supported areas are specifically `@vitest/browser` command APIs that
5858

5959
The provider also starts with `supportsParallelism = false`. That keeps one Electron session active at a time while the callback bridge, preload composition, cache isolation, and teardown behavior are proven. Parallel sessions can be enabled later after adding dedicated coverage for concurrent BrowserWindows/processes and any shared backend callback state.
6060

61-
Test-file isolation is still controlled by Vitest browser-mode config. The provider loads its preload into Vitest's tester iframe, so isolated test iframes are a supported direction, but each consuming package should validate its own setup/teardown assumptions when enabling or changing isolation.
61+
Test-file isolation is still controlled by Vitest browser-mode config. Vitest executes tests inside a same-origin tester iframe, so the provider loads its preload into subframes while keeping `nodeIntegration` disabled and `contextIsolation` enabled. Each consuming package should validate its own setup/teardown assumptions when enabling or changing isolation.
6262

6363
## Backend callbacks
6464

tools/vitest-certa-bridge/src/electron/provider-session.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@ async function main() {
137137
webPreferences: {
138138
preload,
139139
nodeIntegration: false,
140-
// Vitest browser mode executes test modules inside a tester iframe. Load the preload
141-
// in subframes too so renderer tests can reach the callback bridge from that iframe.
140+
// Vitest browser mode executes tests inside a same-origin tester iframe. Electron only
141+
// loads preload scripts into that iframe when this option is enabled; nodeIntegration
142+
// itself remains disabled above, so tests still rely on contextBridge-exposed APIs.
142143
nodeIntegrationInSubFrames: true,
143144
contextIsolation: true,
144145
sandbox: false,

tools/vitest-certa-bridge/src/electron/provider.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import { type ChildProcess, spawn } from "child_process";
77
import * as fs from "fs";
88
import * as os from "os";
99
import * as path from "path";
10+
import { createRequire } from "module";
1011
import { playwright as PlaywrightBrowserProvider } from "@vitest/browser/providers";
1112
import type { BrowserProviderInitializationOptions, TestProject } from "vitest/node";
1213
import type { ElectronBrowserProviderOptions } from "./types.js";
1314

1415
const playwrightBrowserProviderBase: any = PlaywrightBrowserProvider;
16+
const moduleRequire = createRequire(path.join(process.cwd(), "package.json"));
1517

1618
interface ElectronSession {
1719
process: ChildProcess;
@@ -20,9 +22,8 @@ interface ElectronSession {
2022

2123
/** Resolve the Electron provider main-process entry point from this package's compiled CJS output. */
2224
function getProviderSessionEntryPath(): string {
23-
// __dirname is either lib/cjs/electron or lib/esm/electron. Electron main runs under CJS,
24-
// so always target the CJS provider-session entry.
25-
const pkgRoot = path.resolve(__dirname, "../../..");
25+
const providerEntry = moduleRequire.resolve("@itwin/vitest-certa-bridge/electron-provider");
26+
const pkgRoot = path.resolve(path.dirname(providerEntry), "../../..");
2627
return path.join(pkgRoot, "lib", "cjs", "electron", "provider-session.js");
2728
}
2829

@@ -120,7 +121,7 @@ export default class ElectronBrowserProvider extends playwrightBrowserProviderBa
120121
}
121122

122123
const cacheDir = fs.mkdtempSync(path.join(os.tmpdir(), `vitest-electron-${sessionId}-`));
123-
const electronBin = require("electron/index.js");
124+
const electronBin = moduleRequire("electron/index.js") as string;
124125
const sessionEntry = getProviderSessionEntryPath();
125126
const electronArgs = [...(this._options.electronArgs ?? []), sessionEntry];
126127

@@ -134,6 +135,8 @@ export default class ElectronBrowserProvider extends playwrightBrowserProviderBa
134135
// eslint-disable-next-line @typescript-eslint/naming-convention
135136
VITEST_ELECTRON_CACHE_DIR: cacheDir,
136137
// eslint-disable-next-line @typescript-eslint/naming-convention
138+
ELECTRON_CACHE_DIR: cacheDir,
139+
// eslint-disable-next-line @typescript-eslint/naming-convention
137140
VITEST_ELECTRON_HEADLESS: String(this._project.config.browser.headless !== false),
138141
};
139142

@@ -198,8 +201,8 @@ export default class ElectronBrowserProvider extends playwrightBrowserProviderBa
198201
electronProcess.on("exit", (code, signal) => {
199202
this._sessions.delete(sessionId);
200203
cleanupCacheDir(cacheDir);
201-
if (!settled && code !== 0 && code !== null)
202-
settleReject(new Error(`Electron provider session ${sessionId} exited before tests completed: code=${code}, signal=${signal ?? "none"}`));
204+
if (!settled)
205+
settleReject(new Error(`Electron provider session ${sessionId} exited before becoming ready: code=${code ?? "none"}, signal=${signal ?? "none"}`));
203206
});
204207
});
205208
}

tools/vitest-certa-bridge/src/test/electron-provider-smoke.test.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,29 @@ import { describe, expect, it, vi } from "vitest";
77

88
type SendToBackend = (name: string, args: unknown[]) => Promise<unknown>;
99

10+
function getBridgeGlobal(name: string): unknown {
11+
for (const candidateWindow of [window, window.parent, window.top]) {
12+
try {
13+
const candidate = (candidateWindow as unknown as Record<string, unknown> | null)?.[name];
14+
if (candidate !== undefined)
15+
return candidate;
16+
} catch {
17+
// Ignore inaccessible frames. Vitest's tester iframe is same-origin in this provider,
18+
// but keep the helper defensive in case that changes.
19+
}
20+
}
21+
22+
return undefined;
23+
}
24+
1025
function getSendToBackend(): SendToBackend {
11-
const candidate = (window as unknown as Record<string, unknown>)._CertaSendToBackend;
26+
const candidate = getBridgeGlobal("_CertaSendToBackend");
1227
expect(candidate).toBeTypeOf("function");
1328
return candidate as SendToBackend;
1429
}
1530

1631
function getUserPreloadState() {
17-
return (window as unknown as Record<string, unknown>).__electronProviderUserPreload;
32+
return getBridgeGlobal("__electronProviderUserPreload");
1833
}
1934

2035
describe("Electron Vitest browser provider", () => {

0 commit comments

Comments
 (0)