diff --git a/src/evaluate.test.ts b/src/evaluate.test.ts index e640e99..6db0e63 100644 --- a/src/evaluate.test.ts +++ b/src/evaluate.test.ts @@ -1,4 +1,4 @@ -import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test"; import { createDefaultScheduler } from "@intx/inference"; import type { EvaluateDeps } from "./client"; @@ -168,6 +168,32 @@ describe("evaluate without a transport", () => { }); }); +describe("evaluate with the default transport", () => { + test("calls the global fetch unbound, as browsers require", async () => { + const fetchSpy = spyOn(globalThis, "fetch").mockImplementation( + Object.assign( + function browserLikeFetch(this: unknown): Promise { + if (this !== undefined && this !== globalThis) { + throw new TypeError("Illegal invocation"); + } + return Promise.reject(new TypeError("offline")); + }, + { preconnect: globalThis.fetch.preconnect }, + ), + ); + try { + const result = await evaluate({ + state: {}, + questions, + config: { apiKey: "key" }, + }); + expect(result).toMatchObject({ reason: "network", detail: "offline" }); + } finally { + fetchSpy.mockRestore(); + } + }); +}); + // Records the bearer key and timeout of the one POST `evaluate` makes; the // POST fails at once, so each call ends in a network fallback. function recordingDeps(): { diff --git a/src/evaluate.ts b/src/evaluate.ts index 5fcff32..a0c096f 100644 --- a/src/evaluate.ts +++ b/src/evaluate.ts @@ -251,7 +251,8 @@ export async function evaluate( options?: EvaluateOptions, ): Promise { const deps: EvaluateDeps = options?.deps ?? { - fetch: globalThis.fetch, + // Browsers reject fetch called as a method of another object. + fetch: (input, init) => fetch(input, init), scheduler: createDefaultScheduler(), }; const start = deps.scheduler.now();