diff --git a/packages/safe-bash-playground/src/engine/kernel.test.ts b/packages/safe-bash-playground/src/engine/kernel.test.ts index 1f4599782..8e4d64818 100644 --- a/packages/safe-bash-playground/src/engine/kernel.test.ts +++ b/packages/safe-bash-playground/src/engine/kernel.test.ts @@ -13,6 +13,7 @@ describe("real safe-bash browser kernel", () => { const activeWorkers = new Set<{ terminate(): void }>(); beforeAll(async () => { + vi.stubGlobal("navigator", { language: "en-US" }); vi.stubGlobal( "Worker", class extends EventTarget { @@ -28,6 +29,7 @@ describe("real safe-bash browser kernel", () => { const worker = new NodeWorker( ` const { parentPort } = require('node:worker_threads'); + Object.defineProperty(globalThis, 'navigator', { configurable: true, value: { language: 'en-US' } }); globalThis.addEventListener = (event, handler) => parentPort.on(event, data => handler({ data })); globalThis.postMessage = (value, transfer) => parentPort.postMessage(value, transfer); ${code} diff --git a/packages/safe-bash-playground/src/execution-filesystem.test.ts b/packages/safe-bash-playground/src/execution-filesystem.test.ts index 2015b8e72..c988e3dbd 100644 --- a/packages/safe-bash-playground/src/execution-filesystem.test.ts +++ b/packages/safe-bash-playground/src/execution-filesystem.test.ts @@ -1,8 +1,11 @@ -import { describe, expect, it, vi } from "vitest"; +import { afterAll, describe, expect, it, vi } from "vitest"; import { createMemoryFileSystem, FsError } from "./engine/index.js"; import type { FileSystem } from "./engine/index.js"; import { decodeError, encodeError, hostFileSystem, remoteFileSystem } from "./execution-filesystem.js"; +vi.hoisted(() => vi.stubGlobal("navigator", { language: "en-US" })); +afterAll(() => vi.unstubAllGlobals()); + vi.mock("./engine/index.js", async () => { const { buildBrowserEngine } = await import("./engine/build-plugin.mjs"); const built = await buildBrowserEngine(); diff --git a/packages/safe-bash-playground/src/execution.test.ts b/packages/safe-bash-playground/src/execution.test.ts index ee52c40f2..0ecf2a3e7 100644 --- a/packages/safe-bash-playground/src/execution.test.ts +++ b/packages/safe-bash-playground/src/execution.test.ts @@ -7,6 +7,8 @@ import type { ExecutionMessage } from "./execution-protocol.js"; import { browserWorkerFixture } from "../test/browser-worker.js"; import { setTimeout as delay } from "node:timers/promises"; +vi.hoisted(() => vi.stubGlobal("navigator", { language: "en-US" })); + vi.mock("virtual:safe-bash-worker-sources", async () => { const { buildBrowserEngine } = await import("./engine/build-plugin.mjs"); return { sources: (await buildBrowserEngine({ workersOnly: true })).workerSources }; diff --git a/packages/safe-bash-playground/src/session.test.ts b/packages/safe-bash-playground/src/session.test.ts index 4fd62e3d1..0e0ff593f 100644 --- a/packages/safe-bash-playground/src/session.test.ts +++ b/packages/safe-bash-playground/src/session.test.ts @@ -3,6 +3,8 @@ import { createSession, SESSION_LIMITS } from "./session.js"; import { sampleFiles } from "./samples.js"; import { browserWorkerFixture } from "../test/browser-worker.js"; +vi.hoisted(() => vi.stubGlobal("navigator", { language: "en-US" })); + vi.mock("virtual:safe-bash-worker-sources", async () => { const { buildBrowserEngine } = await import("./engine/build-plugin.mjs"); return { sources: (await buildBrowserEngine({ workersOnly: true })).workerSources }; diff --git a/packages/safe-bash-playground/test/browser-worker.ts b/packages/safe-bash-playground/test/browser-worker.ts index 0bf50ce00..cd415285e 100644 --- a/packages/safe-bash-playground/test/browser-worker.ts +++ b/packages/safe-bash-playground/test/browser-worker.ts @@ -18,6 +18,7 @@ export function browserWorkerFixture(executionSource: string) { this.worker = source.then((code) => { const worker = new NodeWorker(` const { parentPort } = require("node:worker_threads"); + Object.defineProperty(globalThis, "navigator", { configurable: true, value: { language: "en-US" } }); globalThis.addEventListener = (event, handler) => parentPort.on(event, data => handler({ data })); globalThis.postMessage = value => parentPort.postMessage(value); (() => { ${code} })(); diff --git a/packages/toolcraft/src/stream.test.ts b/packages/toolcraft/src/stream.test.ts index 2a5f5b0c6..691c458ac 100644 --- a/packages/toolcraft/src/stream.test.ts +++ b/packages/toolcraft/src/stream.test.ts @@ -7,6 +7,12 @@ import { type ToolcraftStream } from "./index.js"; +async function collect(stream: AsyncIterable): Promise { + const values: Value[] = []; + for await (const value of stream) values.push(value); + return values; +} + describe("defineStreamCommand SDK lifecycle", () => { it("starts lazily and advances only when the consumer pulls", async () => { const produced: number[] = []; @@ -78,7 +84,7 @@ describe("defineStreamCommand SDK lifecycle", () => { const stream = sdk.watch({}, { onStatus: (event) => statuses.push(event) }); - await expect(Array.fromAsync(stream)).resolves.toEqual([{ state: "fresh-token" }]); + await expect(collect(stream)).resolves.toEqual([{ state: "fresh-token" }]); expect(statuses).toEqual([ { type: "reconnecting", message: "Refreshing credentials" } ]); @@ -95,7 +101,7 @@ describe("defineStreamCommand SDK lifecycle", () => { }); const sdk = createSDK(defineGroup({ name: "devices", children: [watch] })); - await expect(Array.fromAsync(sdk.watch({}))).rejects.toThrow("state"); + await expect(collect(sdk.watch({}))).rejects.toThrow("state"); }); it("propagates terminal errors and releases resources once", async () => { @@ -115,7 +121,7 @@ describe("defineStreamCommand SDK lifecycle", () => { }); const sdk = createSDK(defineGroup({ name: "devices", children: [watch] })); - await expect(Array.fromAsync(sdk.watch({}))).rejects.toThrow("connection lost"); + await expect(collect(sdk.watch({}))).rejects.toThrow("connection lost"); expect(cleanup).toHaveBeenCalledOnce(); }); });