authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-10-06 14:12:08-03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-06 17:12:08+00:00
logfd1c3386c4d60f3477ab3f13c87537848de099f5
tree26c4c56851961a2ab441df8eba83b057933866c8
parentdff412c3411f34b3150983f00686a98b600526e3
signature Signed by PGP key B5690EEEBB952194

fix(release): unblock nightly browser tests and cli builds (#16515)

Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com>

3 files changed, 15 insertions(+), 7 deletions(-)

.github/workflows/release.yml+3
......@@ -330,6 +330,9 @@ jobs:
330330 # No Electron setup here: `t3` (apps/server) has no Electron dependency
331331 # and none of its tests touch the runtime. Only the non-server `test`
332332 # job, which covers @t3tools/desktop, needs the download.
333 - name: Install Chromium for server browser integration tests
334 run: node apps/server/node_modules/playwright-core/cli.js install --with-deps --only-shell chromium
335
333336 - name: Test
334337 run: vp run --filter t3 test --shard ${{ matrix.shard }}/${{ strategy.job-total }}
335338
apps/server/src/preview/ServerBrowserContexts.test.ts+3-4
......@@ -1,7 +1,7 @@
11import * as NodeEvents from "node:events";
22
33import { INCOGNITO_BROWSER_PROFILE_ID } from "@t3tools/contracts";
4import type { Browser, BrowserContext, BrowserType } from "playwright-core";
4import { chromium, type Browser, type BrowserContext, type BrowserType } from "playwright-core";
55import { beforeEach, describe, expect, it, vi } from "vite-plus/test";
66
77import { ServerBrowserContexts } from "./ServerBrowserContexts.ts";
......@@ -12,9 +12,8 @@ const launches = vi.hoisted(() => ({
1212 mkdir: vi.fn().mockResolvedValue(undefined),
1313 rm: vi.fn().mockResolvedValue(undefined),
1414}));
15vi.mock("playwright-core", () => ({
16 chromium: { launch: launches.launch, launchPersistentContext: launches.persistent },
17}));
15vi.spyOn(chromium, "launch").mockImplementation(launches.launch);
16vi.spyOn(chromium, "launchPersistentContext").mockImplementation(launches.persistent);
1817vi.mock("node:fs/promises", () => ({ mkdir: launches.mkdir, rm: launches.rm }));
1918
2019const makeContext = () => {
apps/server/src/preview/ServerBrowserContexts.ts+9-3
......@@ -2,11 +2,17 @@
22import { INCOGNITO_BROWSER_PROFILE_ID } from "@t3tools/contracts";
33import { constVoid } from "effect/Function";
44import * as NodeFSP from "node:fs/promises";
5import * as NodeModule from "node:module";
56import * as NodePath from "node:path";
67import type { Browser, BrowserContext } from "playwright-core";
78
89import { sandboxDisabled } from "./PreviewBrowserHost.ts";
910
11// Playwright needs its files on disk. createRequire also resolves it from a Node SEA executable.
12const requirePlaywright = NodeModule.createRequire(import.meta.url);
13const loadPlaywright = () =>
14 requirePlaywright("playwright-core") as typeof import("playwright-core");
15
1016interface Options {
1117 readonly profilesDir: string;
1218 /** The shared headless browser's executable, installing it on first use. */
......@@ -54,7 +60,7 @@ export class ServerBrowserContexts {
5460 private sharedBrowser() {
5561 if (!this.browser) {
5662 const launched = this.launchOptions().then(async (options) => {
57 const { chromium } = await import("playwright-core");
63 const { chromium } = loadPlaywright();
5864 const browser = await this.launch(options, () => chromium.launch(options));
5965 browser.on("disconnected", () => {
6066 if (this.browser === launched) this.browser = undefined;
......@@ -104,7 +110,7 @@ export class ServerBrowserContexts {
104110 }
105111 const directory = this.profileDirectory(profileId);
106112 const options = await this.launchOptions();
107 const { chromium } = await import("playwright-core");
113 const { chromium } = loadPlaywright();
108114 await NodeFSP.mkdir(directory, { recursive: true });
109115 return this.launch(options, () =>
110116 chromium.launchPersistentContext(directory, { ...options, ...contextOptions }),
......@@ -133,7 +139,7 @@ export class ServerBrowserContexts {
133139 * serves. The page keeps the desktop's storage, size, and window.
134140 */
135141 async connectDesktopPage(endpoint: string) {
136 const { chromium } = await import("playwright-core");
142 const { chromium } = loadPlaywright();
137143 const browser = await chromium.connectOverCDP(endpoint, { timeout: 15_000 });
138144 const page = browser.contexts().flatMap((context) => context.pages())[0];
139145 if (!page) {