import { it as effectIt } from "@effect/vitest";import { DESKTOP_PREVIEW_RECORDING_CAPTURE_TRIGGER } from "@t3tools/contracts";import type { DesktopPreviewRecordingFrame } from "@t3tools/contracts";import { HostProcessPlatform } from "@t3tools/shared/hostProcess";import * as Cause from "effect/Cause";import * as Deferred from "effect/Deferred";import * as Effect from "effect/Effect";import * as Exit from "effect/Exit";import * as FileSystem from "effect/FileSystem";import * as Fiber from "effect/Fiber";import * as Layer from "effect/Layer";import * as Logger from "effect/Logger";import * as Option from "effect/Option";import * as Path from "effect/Path";import * as Schema from "effect/Schema";import type * as Scope from "effect/Scope";import { TestClock } from "effect/testing";import { beforeEach, describe, expect, it, vi } from "vite-plus/test"; import * as DesktopEnvironment from "../app/DesktopEnvironment.ts";import * as ElectronWindow from "../electron/ElectronWindow.ts";import * as BrowserSession from "./BrowserSession.ts";import * as PreviewManager from "./Manager.ts"; describe("fitPictureInPictureContentSize", () => { it("preserves the PiP content area across aspect-ratio changes", () => { expect(PreviewManager.fitPictureInPictureContentSize([480, 320], 16 / 9)).toEqual([523, 294]); expect(PreviewManager.fitPictureInPictureContentSize([480, 320], 9 / 16)).toEqual([294, 523]); }); it("does not collapse toward the minimum size when orientation changes repeatedly", () => { const portrait = PreviewManager.fitPictureInPictureContentSize([523, 294], 9 / 16); const landscape = PreviewManager.fitPictureInPictureContentSize(portrait, 16 / 9); expect(portrait).toEqual([294, 523]); expect(landscape).toEqual([523, 294]); });}); describe("recordingFileExtension", () => { it("derives the artifact extension from the recorder's actual mime type", () => { expect(PreviewManager.recordingFileExtension("video/mp4;codecs=avc1.640028")).toBe("mp4"); expect(PreviewManager.recordingFileExtension("video/webm;codecs=vp9")).toBe("webm"); expect(PreviewManager.recordingFileExtension("video/x-matroska")).toBe("matroska"); });}); describe("isPreviewRefreshShortcut", () => { const input = (overrides: Partial<Electron.Input> = {}) => ({ type: "keyDown", key: "r", meta: true, control: false, shift: false, alt: false, ...overrides, }) as Electron.Input; it("recognizes the platform refresh chord without matching modified variants", () => { expect(PreviewManager.isPreviewRefreshShortcut(input())).toBe(true); expect(PreviewManager.isPreviewRefreshShortcut(input({ meta: false, control: true }))).toBe( true, ); expect(PreviewManager.isPreviewRefreshShortcut(input({ shift: true }))).toBe(false); expect(PreviewManager.isPreviewRefreshShortcut(input({ type: "keyUp" }))).toBe(false); });}); describe("isPreviewEditingShortcut", () => { const input = (platform: NodeJS.Platform, key: string, overrides: Partial<Electron.Input> = {}) => ({ type: "keyDown", key, meta: platform === "darwin", control: platform !== "darwin", shift: false, alt: false, ...overrides, }) as Electron.Input; it.each(["darwin", "linux", "win32"] as const)( "allows native editing chords on %s without allowing host shortcuts", (platform) => { for (const key of ["a", "c", "v", "x", "z", "V"]) { expect(PreviewManager.isPreviewEditingShortcut(input(platform, key), platform)).toBe(true); } const redo = platform === "win32" ? input(platform, "y") : input(platform, "z", { shift: true }); expect(PreviewManager.isPreviewEditingShortcut(redo, platform)).toBe(true); expect( PreviewManager.isPreviewEditingShortcut( input(platform, "v", { shift: true, alt: platform === "darwin" }), platform, ), ).toBe(true); for (const key of ["k", ",", "w", "j", "q", "+", "=", "-", "0", "r", "F12"]) { expect(PreviewManager.isPreviewEditingShortcut(input(platform, key), platform)).toBe(false); } for (const modifiers of [ { meta: false, control: false }, { meta: true, control: true }, { meta: platform !== "darwin", control: platform === "darwin" }, { alt: true }, { shift: true, alt: platform !== "darwin" }, ]) { expect( PreviewManager.isPreviewEditingShortcut(input(platform, "v", modifiers), platform), ).toBe(false); } expect( PreviewManager.isPreviewEditingShortcut(input(platform, "a", { shift: true }), platform), ).toBe(false); }, ); it("recognizes macOS Paste and Match Style when Option changes the key to a symbol", () => { const pasteAndMatchStyle = input("darwin", "◊", { code: "KeyV", alt: true, shift: true }); expect(PreviewManager.isPreviewEditingShortcut(pasteAndMatchStyle, "darwin")).toBe(true); for (const modifiers of [ { code: "KeyC" }, { alt: false }, { shift: false }, { control: true }, ]) { expect( PreviewManager.isPreviewEditingShortcut({ ...pasteAndMatchStyle, ...modifiers }, "darwin"), ).toBe(false); } });}); describe("previewWindowOpenAction", () => { const details = (overrides: { readonly url?: string; readonly disposition?: Electron.HandlerDetails["disposition"]; }) => ({ url: "https://accounts.google.com/o/oauth2/auth", disposition: "new-window" as Electron.HandlerDetails["disposition"], ...overrides, }); it("opens a real window for scripted popups so the opener survives", () => { // OAuth SDKs read a null `window.open()` as a blocked popup, and they need // the opener alive to receive the credential back. expect(PreviewManager.previewWindowOpenAction(details({}))).toBe("popup"); expect( PreviewManager.previewWindowOpenAction(details({ url: "http://localhost:5173/auth" })), ).toBe("popup"); }); it("keeps target=_blank links in the preview tab", () => { expect(PreviewManager.previewWindowOpenAction(details({ disposition: "foreground-tab" }))).toBe( "navigate", ); expect(PreviewManager.previewWindowOpenAction(details({ disposition: "background-tab" }))).toBe( "navigate", ); }); it("does not hand a window to schemes that cannot be hardened", () => { // A popup skips the `will-attach-webview` hardening, so it only gets a window // when its preferences can be overridden. Chromium copies the guest's // preferences for `about:blank` and forbids overriding them. for (const url of [ "about:blank", "javascript:alert(1)", "file:///etc/passwd", "vscode://vscode-remote/ssh-remote+box/tmp", "not a url", ]) { expect(PreviewManager.previewWindowOpenAction(details({ url }))).toBe("navigate"); } });}); const { browserWindowConstructor, clipboardItemConstructor, createFromPath, fromId, getFocusedWebContents, mkdir, showItemInFolder, webviewSend, writeFile, writeClipboard,} = vi.hoisted(() => ({ browserWindowConstructor: vi.fn(), clipboardItemConstructor: vi.fn(), createFromPath: vi.fn((): { readonly isEmpty: () => boolean; readonly toPNG: () => Buffer } => ({ isEmpty: () => false, toPNG: () => Buffer.from("png"), })), fromId: vi.fn<(_id?: number) => Electron.WebContents | null>((_id?: number) => null), getFocusedWebContents: vi.fn(() => null), mkdir: vi.fn((_path: string) => undefined), showItemInFolder: vi.fn(), webviewSend: vi.fn(), writeFile: vi.fn((_path: string, _data: Uint8Array) => undefined), writeClipboard: vi.fn(async () => undefined),})); vi.mock("electron", () => ({ BrowserWindow: browserWindowConstructor, ClipboardItem: class { constructor(data: Record<string, unknown>) { clipboardItemConstructor(data); } }, clipboard: { write: writeClipboard, }, nativeImage: { createFromPath, }, shell: { showItemInFolder, }, session: { fromPartition: vi.fn(), }, webContents: { fromId, getFocusedWebContents, },})); const browserSessionLayer = Layer.succeed( BrowserSession.BrowserSession, BrowserSession.BrowserSession.of({ getPartition: () => Effect.succeed("persist:t3code-preview-test"), isPartition: (partition) => partition.startsWith("persist:t3code-preview-"), getSession: () => Effect.die("unexpected getSession"), clearCookies: () => Effect.void, clearCache: () => Effect.void, }),); const environmentLayer = Layer.succeed( DesktopEnvironment.DesktopEnvironment, DesktopEnvironment.DesktopEnvironment.of({ browserArtifactsDir: "/tmp/t3/dev/browser-artifacts", dirname: "/tmp/t3/desktop", path: { join: (...parts: ReadonlyArray<string>) => parts.join("/"), }, } as DesktopEnvironment.DesktopEnvironment["Service"]),); const fileSystemLayer = FileSystem.layerNoop({ makeDirectory: (path) => Effect.sync(() => { mkdir(path); }), writeFile: (path, data) => Effect.sync(() => { writeFile(path, data); }),}); const layer = PreviewManager.layer.pipe( Layer.provideMerge(browserSessionLayer), Layer.provideMerge(environmentLayer), Layer.provideMerge(fileSystemLayer), Layer.provideMerge(Path.layer), Layer.provideMerge(Layer.succeed(HostProcessPlatform, "darwin")),);const encodePreviewManagerError = Schema.encodeSync(PreviewManager.PreviewManagerError); const withManager = <A>( use: ( manager: PreviewManager.PreviewManager["Service"], ) => Effect.Effect<A, PreviewManager.PreviewManagerError, Scope.Scope>,) => Effect.gen(function* () { const manager = yield* PreviewManager.PreviewManager; return yield* use(manager); }).pipe(Effect.provide(layer), Effect.scoped); interface TestCapturedPreviewImage { readonly toJPEG: () => Buffer; readonly getSize: () => { readonly width: number; readonly height: number };} type TestDisplayMediaHandler = ( request: { readonly frame: { readonly frameTreeNodeId: number } | null }, callback: (streams: { video?: unknown }) => void,) => void; interface TestHostWebContents { readonly id: number; readonly mainFrame: { readonly frameTreeNodeId: number }; readonly executeJavaScript: ReturnType<typeof vi.fn>; readonly isDestroyed: () => boolean; readonly session: { readonly setDisplayMediaRequestHandler: ReturnType<typeof vi.fn>; }; readonly displayMediaHandler: () => TestDisplayMediaHandler | undefined;} type TestPreviewWebContents = Electron.WebContents & { readonly setBackgroundThrottling: ReturnType<typeof vi.fn<(enabled: boolean) => void>>;}; const makeTestHostWebContents = (): TestHostWebContents => { let handler: TestDisplayMediaHandler | undefined; return { id: 7, mainFrame: { frameTreeNodeId: 7 }, executeJavaScript: vi.fn(async () => true), isDestroyed: () => false, session: { setDisplayMediaRequestHandler: vi.fn((next: TestDisplayMediaHandler) => { handler = next; }), }, displayMediaHandler: () => handler, };}; const makeTestPreviewWebContents = ( capturePage: () => Promise<TestCapturedPreviewImage>, id = 42, hostWebContents: TestHostWebContents = makeTestHostWebContents(),) => { const setBackgroundThrottling = vi.fn<(enabled: boolean) => void>(); return { id, mainFrame: { routingId: id }, hostWebContents, executeJavaScript: vi.fn(async () => ({ width: 1280, height: 720 })), isDestroyed: () => false, getType: () => "webview", getURL: () => "https://example.com", getTitle: () => "Example", isLoading: () => false, getZoomFactor: () => 1, setZoomFactor: vi.fn(), setAudioMuted: vi.fn(), setBackgroundThrottling, isCurrentlyAudible: () => false, on: vi.fn(), off: vi.fn(), ipc: { on: vi.fn(), off: vi.fn() }, send: webviewSend, navigationHistory: { canGoBack: () => false, canGoForward: () => false }, setIgnoreMenuShortcuts: vi.fn(), setWindowOpenHandler: vi.fn(), debugger: { isAttached: () => false, attach: vi.fn(), sendCommand: vi.fn(async () => undefined), on: vi.fn(), off: vi.fn(), }, capturePage, } as unknown as TestPreviewWebContents;}; /** Two ready tabs (41, 42) sharing one window, so they contend for the single display-media slot. */const setupRecordingRaceTabs = (manager: PreviewManager.PreviewManager["Service"]) => Effect.gen(function* () { const capturePage = vi.fn(async () => ({ toJPEG: () => Buffer.from("unused-recording-frame"), getSize: () => ({ width: 1280, height: 720 }), })); const host = makeTestHostWebContents(); const destroyedIds = new Set<number>(); const makeWebContents = (id: number) => Object.assign(makeTestPreviewWebContents(capturePage, id, host), { executeJavaScript: vi.fn(async () => ({ width: 1280, height: 720 })), isDestroyed: () => destroyedIds.has(id), }); const webContentsById = new Map([ [41, makeWebContents(41)], [42, makeWebContents(42)], ]); fromId.mockImplementation((id) => id === undefined ? null : (webContentsById.get(id) ?? null), ); yield* manager.createTab("tab_race_a"); yield* manager.createTab("tab_race_b"); yield* manager.registerWebview("tab_race_a", 41); yield* manager.registerWebview("tab_race_b", 42); const grants: Array<{ video?: unknown }> = []; return { host, grants, destroy: (id: number) => destroyedIds.add(id), takeGrant: (frame = host.mainFrame) => host.displayMediaHandler()?.({ frame }, (value) => { grants.push(value); }), }; }); const TEST_FAVICON = "data:image/png;base64,cG5n"; const makeSourcePng = (width = 1, height = 1): Buffer => { const buffer = Buffer.alloc(24); Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]).copy(buffer); buffer.writeUInt32BE(width, 16); buffer.writeUInt32BE(height, 20); return buffer;}; const makeFaviconWebContents = (options?: { readonly fetch?: (url: string, init?: RequestInit) => Promise<Response>; readonly id?: number; readonly rasterize?: (code: string) => Promise<unknown>; readonly url?: string;}) => { const sourcePng = makeSourcePng(); const listeners = new Map<string, (...args: never[]) => void>(); let currentUrl = options?.url ?? "http://localhost:3200/"; let destroyed = false; let loading = false; const fetch = vi.fn( options?.fetch ?? (async () => new Response(new Uint8Array(sourcePng), { headers: { "content-type": "image/png" }, })), ); const executeJavaScriptInIsolatedWorld = vi.fn( async (_worldId: number, scripts: ReadonlyArray<{ readonly code: string }>) => options?.rasterize ? options.rasterize(scripts[0]?.code ?? "") : TEST_FAVICON, ); const reload = vi.fn(); const loadURL = vi.fn(async (url: string) => { currentUrl = url; }); const off = vi.fn(); const debuggerOff = vi.fn(); const webContents = { id: options?.id ?? 42, isDestroyed: () => destroyed, getType: () => "webview", getURL: () => currentUrl, getTitle: () => "Preview", isLoading: () => loading, isDevToolsOpened: () => false, getZoomFactor: () => 1, setZoomFactor: vi.fn(), setAudioMuted: vi.fn(), isCurrentlyAudible: () => false, reload, reloadIgnoringCache: vi.fn(), loadURL, on: vi.fn((event: string, listener: (...args: never[]) => void) => { listeners.set(event, listener); }), off, ipc: { on: vi.fn(), off: vi.fn() }, send: webviewSend, session: { fetch }, navigationHistory: { canGoBack: () => false, canGoForward: () => false }, setIgnoreMenuShortcuts: vi.fn(), setWindowOpenHandler: vi.fn(), executeJavaScriptInIsolatedWorld, debugger: { isAttached: () => false, attach: vi.fn(), sendCommand: vi.fn(async () => undefined), on: vi.fn(), off: debuggerOff, }, }; return { executeJavaScriptInIsolatedWorld, fetch, debuggerOff, listeners, loadURL, off, reload, setDestroyed: (value: boolean) => { destroyed = value; }, setLoading: (value: boolean) => { loading = value; }, setUrl: (url: string) => { currentUrl = url; }, webContents: webContents as never, };}; const settle = function* (until: () => boolean) { for (let attempt = 0; attempt < 30 && !until(); attempt++) { yield* Effect.promise(() => Promise.resolve()); }}; const makeTestPictureInPictureWindow = (loadURL: () => Promise<void> = async () => undefined) => { const listeners = new Map<string, () => void>(); const webContentsListeners = new Map<string, () => void>();Lines 1–500 of 4333. Load more
import { it as effectIt } from "@effect/vitest"; import { DESKTOP_PREVIEW_RECORDING_CAPTURE_TRIGGER } from "@t3tools/contracts"; import type { DesktopPreviewRecordingFrame } from "@t3tools/contracts"; import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; import * as Cause from "effect/Cause"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; import * as Exit from "effect/Exit"; import * as FileSystem from "effect/FileSystem"; import * as Fiber from "effect/Fiber"; import * as Layer from "effect/Layer"; import * as Logger from "effect/Logger"; import * as Option from "effect/Option"; import * as Path from "effect/Path"; import * as Schema from "effect/Schema"; import type * as Scope from "effect/Scope"; import { TestClock } from "effect/testing"; import { beforeEach, describe, expect, it, vi } from "vite-plus/test"; import * as DesktopEnvironment from "../app/DesktopEnvironment.ts"; import * as ElectronWindow from "../electron/ElectronWindow.ts"; import * as BrowserSession from "./BrowserSession.ts"; import * as PreviewManager from "./Manager.ts"; describe("fitPictureInPictureContentSize", () => { it("preserves the PiP content area across aspect-ratio changes", () => { expect(PreviewManager.fitPictureInPictureContentSize([480, 320], 16 / 9)).toEqual([523, 294]); expect(PreviewManager.fitPictureInPictureContentSize([480, 320], 9 / 16)).toEqual([294, 523]); }); it("does not collapse toward the minimum size when orientation changes repeatedly", () => { const portrait = PreviewManager.fitPictureInPictureContentSize([523, 294], 9 / 16); const landscape = PreviewManager.fitPictureInPictureContentSize(portrait, 16 / 9); expect(portrait).toEqual([294, 523]); expect(landscape).toEqual([523, 294]); }); }); describe("recordingFileExtension", () => { it("derives the artifact extension from the recorder's actual mime type", () => { expect(PreviewManager.recordingFileExtension("video/mp4;codecs=avc1.640028")).toBe("mp4"); expect(PreviewManager.recordingFileExtension("video/webm;codecs=vp9")).toBe("webm"); expect(PreviewManager.recordingFileExtension("video/x-matroska")).toBe("matroska"); }); }); describe("isPreviewRefreshShortcut", () => { const input = (overrides: Partial<Electron.Input> = {}) => ({ type: "keyDown", key: "r", meta: true, control: false, shift: false, alt: false, ...overrides, }) as Electron.Input; it("recognizes the platform refresh chord without matching modified variants", () => { expect(PreviewManager.isPreviewRefreshShortcut(input())).toBe(true); expect(PreviewManager.isPreviewRefreshShortcut(input({ meta: false, control: true }))).toBe( true, ); expect(PreviewManager.isPreviewRefreshShortcut(input({ shift: true }))).toBe(false); expect(PreviewManager.isPreviewRefreshShortcut(input({ type: "keyUp" }))).toBe(false); }); }); describe("isPreviewEditingShortcut", () => { const input = (platform: NodeJS.Platform, key: string, overrides: Partial<Electron.Input> = {}) => ({ type: "keyDown", key, meta: platform === "darwin", control: platform !== "darwin", shift: false, alt: false, ...overrides, }) as Electron.Input; it.each(["darwin", "linux", "win32"] as const)( "allows native editing chords on %s without allowing host shortcuts", (platform) => { for (const key of ["a", "c", "v", "x", "z", "V"]) { expect(PreviewManager.isPreviewEditingShortcut(input(platform, key), platform)).toBe(true); } const redo = platform === "win32" ? input(platform, "y") : input(platform, "z", { shift: true }); expect(PreviewManager.isPreviewEditingShortcut(redo, platform)).toBe(true); expect( PreviewManager.isPreviewEditingShortcut( input(platform, "v", { shift: true, alt: platform === "darwin" }), platform, ), ).toBe(true); for (const key of ["k", ",", "w", "j", "q", "+", "=", "-", "0", "r", "F12"]) { expect(PreviewManager.isPreviewEditingShortcut(input(platform, key), platform)).toBe(false); } for (const modifiers of [ { meta: false, control: false }, { meta: true, control: true }, { meta: platform !== "darwin", control: platform === "darwin" }, { alt: true }, { shift: true, alt: platform !== "darwin" }, ]) { expect( PreviewManager.isPreviewEditingShortcut(input(platform, "v", modifiers), platform), ).toBe(false); } expect( PreviewManager.isPreviewEditingShortcut(input(platform, "a", { shift: true }), platform), ).toBe(false); }, ); it("recognizes macOS Paste and Match Style when Option changes the key to a symbol", () => { const pasteAndMatchStyle = input("darwin", "◊", { code: "KeyV", alt: true, shift: true }); expect(PreviewManager.isPreviewEditingShortcut(pasteAndMatchStyle, "darwin")).toBe(true); for (const modifiers of [ { code: "KeyC" }, { alt: false }, { shift: false }, { control: true }, ]) { expect( PreviewManager.isPreviewEditingShortcut({ ...pasteAndMatchStyle, ...modifiers }, "darwin"), ).toBe(false); } }); }); describe("previewWindowOpenAction", () => { const details = (overrides: { readonly url?: string; readonly disposition?: Electron.HandlerDetails["disposition"]; }) => ({ url: "https://accounts.google.com/o/oauth2/auth", disposition: "new-window" as Electron.HandlerDetails["disposition"], ...overrides, }); it("opens a real window for scripted popups so the opener survives", () => { // OAuth SDKs read a null `window.open()` as a blocked popup, and they need // the opener alive to receive the credential back. expect(PreviewManager.previewWindowOpenAction(details({}))).toBe("popup"); expect( PreviewManager.previewWindowOpenAction(details({ url: "http://localhost:5173/auth" })), ).toBe("popup"); }); it("keeps target=_blank links in the preview tab", () => { expect(PreviewManager.previewWindowOpenAction(details({ disposition: "foreground-tab" }))).toBe( "navigate", ); expect(PreviewManager.previewWindowOpenAction(details({ disposition: "background-tab" }))).toBe( "navigate", ); }); it("does not hand a window to schemes that cannot be hardened", () => { // A popup skips the `will-attach-webview` hardening, so it only gets a window // when its preferences can be overridden. Chromium copies the guest's // preferences for `about:blank` and forbids overriding them. for (const url of [ "about:blank", "javascript:alert(1)", "file:///etc/passwd", "vscode://vscode-remote/ssh-remote+box/tmp", "not a url", ]) { expect(PreviewManager.previewWindowOpenAction(details({ url }))).toBe("navigate"); } }); }); const { browserWindowConstructor, clipboardItemConstructor, createFromPath, fromId, getFocusedWebContents, mkdir, showItemInFolder, webviewSend, writeFile, writeClipboard, } = vi.hoisted(() => ({ browserWindowConstructor: vi.fn(), clipboardItemConstructor: vi.fn(), createFromPath: vi.fn((): { readonly isEmpty: () => boolean; readonly toPNG: () => Buffer } => ({ isEmpty: () => false, toPNG: () => Buffer.from("png"), })), fromId: vi.fn<(_id?: number) => Electron.WebContents | null>((_id?: number) => null), getFocusedWebContents: vi.fn(() => null), mkdir: vi.fn((_path: string) => undefined), showItemInFolder: vi.fn(), webviewSend: vi.fn(), writeFile: vi.fn((_path: string, _data: Uint8Array) => undefined), writeClipboard: vi.fn(async () => undefined), })); vi.mock("electron", () => ({ BrowserWindow: browserWindowConstructor, ClipboardItem: class { constructor(data: Record<string, unknown>) { clipboardItemConstructor(data); } }, clipboard: { write: writeClipboard, }, nativeImage: { createFromPath, }, shell: { showItemInFolder, }, session: { fromPartition: vi.fn(), }, webContents: { fromId, getFocusedWebContents, }, })); const browserSessionLayer = Layer.succeed( BrowserSession.BrowserSession, BrowserSession.BrowserSession.of({ getPartition: () => Effect.succeed("persist:t3code-preview-test"), isPartition: (partition) => partition.startsWith("persist:t3code-preview-"), getSession: () => Effect.die("unexpected getSession"), clearCookies: () => Effect.void, clearCache: () => Effect.void, }), ); const environmentLayer = Layer.succeed( DesktopEnvironment.DesktopEnvironment, DesktopEnvironment.DesktopEnvironment.of({ browserArtifactsDir: "/tmp/t3/dev/browser-artifacts", dirname: "/tmp/t3/desktop", path: { join: (...parts: ReadonlyArray<string>) => parts.join("/"), }, } as DesktopEnvironment.DesktopEnvironment["Service"]), ); const fileSystemLayer = FileSystem.layerNoop({ makeDirectory: (path) => Effect.sync(() => { mkdir(path); }), writeFile: (path, data) => Effect.sync(() => { writeFile(path, data); }), }); const layer = PreviewManager.layer.pipe( Layer.provideMerge(browserSessionLayer), Layer.provideMerge(environmentLayer), Layer.provideMerge(fileSystemLayer), Layer.provideMerge(Path.layer), Layer.provideMerge(Layer.succeed(HostProcessPlatform, "darwin")), ); const encodePreviewManagerError = Schema.encodeSync(PreviewManager.PreviewManagerError); const withManager = <A>( use: ( manager: PreviewManager.PreviewManager["Service"], ) => Effect.Effect<A, PreviewManager.PreviewManagerError, Scope.Scope>, ) => Effect.gen(function* () { const manager = yield* PreviewManager.PreviewManager; return yield* use(manager); }).pipe(Effect.provide(layer), Effect.scoped); interface TestCapturedPreviewImage { readonly toJPEG: () => Buffer; readonly getSize: () => { readonly width: number; readonly height: number }; } type TestDisplayMediaHandler = ( request: { readonly frame: { readonly frameTreeNodeId: number } | null }, callback: (streams: { video?: unknown }) => void, ) => void; interface TestHostWebContents { readonly id: number; readonly mainFrame: { readonly frameTreeNodeId: number }; readonly executeJavaScript: ReturnType<typeof vi.fn>; readonly isDestroyed: () => boolean; readonly session: { readonly setDisplayMediaRequestHandler: ReturnType<typeof vi.fn>; }; readonly displayMediaHandler: () => TestDisplayMediaHandler | undefined; } type TestPreviewWebContents = Electron.WebContents & { readonly setBackgroundThrottling: ReturnType<typeof vi.fn<(enabled: boolean) => void>>; }; const makeTestHostWebContents = (): TestHostWebContents => { let handler: TestDisplayMediaHandler | undefined; return { id: 7, mainFrame: { frameTreeNodeId: 7 }, executeJavaScript: vi.fn(async () => true), isDestroyed: () => false, session: { setDisplayMediaRequestHandler: vi.fn((next: TestDisplayMediaHandler) => { handler = next; }), }, displayMediaHandler: () => handler, }; }; const makeTestPreviewWebContents = ( capturePage: () => Promise<TestCapturedPreviewImage>, id = 42, hostWebContents: TestHostWebContents = makeTestHostWebContents(), ) => { const setBackgroundThrottling = vi.fn<(enabled: boolean) => void>(); return { id, mainFrame: { routingId: id }, hostWebContents, executeJavaScript: vi.fn(async () => ({ width: 1280, height: 720 })), isDestroyed: () => false, getType: () => "webview", getURL: () => "https://example.com", getTitle: () => "Example", isLoading: () => false, getZoomFactor: () => 1, setZoomFactor: vi.fn(), setAudioMuted: vi.fn(), setBackgroundThrottling, isCurrentlyAudible: () => false, on: vi.fn(), off: vi.fn(), ipc: { on: vi.fn(), off: vi.fn() }, send: webviewSend, navigationHistory: { canGoBack: () => false, canGoForward: () => false }, setIgnoreMenuShortcuts: vi.fn(), setWindowOpenHandler: vi.fn(), debugger: { isAttached: () => false, attach: vi.fn(), sendCommand: vi.fn(async () => undefined), on: vi.fn(), off: vi.fn(), }, capturePage, } as unknown as TestPreviewWebContents; }; /** Two ready tabs (41, 42) sharing one window, so they contend for the single display-media slot. */ const setupRecordingRaceTabs = (manager: PreviewManager.PreviewManager["Service"]) => Effect.gen(function* () { const capturePage = vi.fn(async () => ({ toJPEG: () => Buffer.from("unused-recording-frame"), getSize: () => ({ width: 1280, height: 720 }), })); const host = makeTestHostWebContents(); const destroyedIds = new Set<number>(); const makeWebContents = (id: number) => Object.assign(makeTestPreviewWebContents(capturePage, id, host), { executeJavaScript: vi.fn(async () => ({ width: 1280, height: 720 })), isDestroyed: () => destroyedIds.has(id), }); const webContentsById = new Map([ [41, makeWebContents(41)], [42, makeWebContents(42)], ]); fromId.mockImplementation((id) => id === undefined ? null : (webContentsById.get(id) ?? null), ); yield* manager.createTab("tab_race_a"); yield* manager.createTab("tab_race_b"); yield* manager.registerWebview("tab_race_a", 41); yield* manager.registerWebview("tab_race_b", 42); const grants: Array<{ video?: unknown }> = []; return { host, grants, destroy: (id: number) => destroyedIds.add(id), takeGrant: (frame = host.mainFrame) => host.displayMediaHandler()?.({ frame }, (value) => { grants.push(value); }), }; }); const TEST_FAVICON = "data:image/png;base64,cG5n"; const makeSourcePng = (width = 1, height = 1): Buffer => { const buffer = Buffer.alloc(24); Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]).copy(buffer); buffer.writeUInt32BE(width, 16); buffer.writeUInt32BE(height, 20); return buffer; }; const makeFaviconWebContents = (options?: { readonly fetch?: (url: string, init?: RequestInit) => Promise<Response>; readonly id?: number; readonly rasterize?: (code: string) => Promise<unknown>; readonly url?: string; }) => { const sourcePng = makeSourcePng(); const listeners = new Map<string, (...args: never[]) => void>(); let currentUrl = options?.url ?? "http://localhost:3200/"; let destroyed = false; let loading = false; const fetch = vi.fn( options?.fetch ?? (async () => new Response(new Uint8Array(sourcePng), { headers: { "content-type": "image/png" }, })), ); const executeJavaScriptInIsolatedWorld = vi.fn( async (_worldId: number, scripts: ReadonlyArray<{ readonly code: string }>) => options?.rasterize ? options.rasterize(scripts[0]?.code ?? "") : TEST_FAVICON, ); const reload = vi.fn(); const loadURL = vi.fn(async (url: string) => { currentUrl = url; }); const off = vi.fn(); const debuggerOff = vi.fn(); const webContents = { id: options?.id ?? 42, isDestroyed: () => destroyed, getType: () => "webview", getURL: () => currentUrl, getTitle: () => "Preview", isLoading: () => loading, isDevToolsOpened: () => false, getZoomFactor: () => 1, setZoomFactor: vi.fn(), setAudioMuted: vi.fn(), isCurrentlyAudible: () => false, reload, reloadIgnoringCache: vi.fn(), loadURL, on: vi.fn((event: string, listener: (...args: never[]) => void) => { listeners.set(event, listener); }), off, ipc: { on: vi.fn(), off: vi.fn() }, send: webviewSend, session: { fetch }, navigationHistory: { canGoBack: () => false, canGoForward: () => false }, setIgnoreMenuShortcuts: vi.fn(), setWindowOpenHandler: vi.fn(), executeJavaScriptInIsolatedWorld, debugger: { isAttached: () => false, attach: vi.fn(), sendCommand: vi.fn(async () => undefined), on: vi.fn(), off: debuggerOff, }, }; return { executeJavaScriptInIsolatedWorld, fetch, debuggerOff, listeners, loadURL, off, reload, setDestroyed: (value: boolean) => { destroyed = value; }, setLoading: (value: boolean) => { loading = value; }, setUrl: (url: string) => { currentUrl = url; }, webContents: webContents as never, }; }; const settle = function* (until: () => boolean) { for (let attempt = 0; attempt < 30 && !until(); attempt++) { yield* Effect.promise(() => Promise.resolve()); } }; const makeTestPictureInPictureWindow = (loadURL: () => Promise<void> = async () => undefined) => { const listeners = new Map<string, () => void>(); const webContentsListeners = new Map<string, () => void>();