mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-04-28 03:49:31 +00:00
fix: resolve TypeScript type errors in update-check.test.ts (#3284)
Replace `mock()` + `spyOn().mockImplementation(mockFn)` pattern with
direct `spyOn().mockImplementation(() => ...)` to fix fetch mock type
mismatches. Make execFileSync mocks return Buffer.from("") instead of
void. Add explicit type annotations for callback parameters.
Agent: code-health
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
0f6a48369b
commit
439e5a1446
2 changed files with 46 additions and 44 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@openrouter/spawn",
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.5",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"spawn": "cli.js"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { ExecFileSyncOptions } from "node:child_process";
|
||||
|
||||
import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from "bun:test";
|
||||
import { afterEach, beforeEach, describe, expect, it, spyOn } from "bun:test";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { tryCatch } from "@openrouter/spawn-shared";
|
||||
|
|
@ -94,12 +94,11 @@ describe("update-check", () => {
|
|||
});
|
||||
|
||||
it("should check for updates on every run", async () => {
|
||||
const mockFetch = mock(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
|
||||
// Mock execFileSync to prevent actual update + re-exec
|
||||
const { executor } = await import("../update-check.js");
|
||||
const execFileSyncSpy = spyOn(executor, "execFileSync").mockImplementation(() => {});
|
||||
const execFileSyncSpy = spyOn(executor, "execFileSync").mockImplementation(() => Buffer.from(""));
|
||||
|
||||
const { checkForUpdates } = await import("../update-check.js");
|
||||
await checkForUpdates();
|
||||
|
|
@ -110,12 +109,11 @@ describe("update-check", () => {
|
|||
});
|
||||
|
||||
it("should auto-update when newer version is available", async () => {
|
||||
const mockFetch = mock(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
|
||||
// Mock execFileSync to prevent actual update + re-exec
|
||||
const { executor } = await import("../update-check.js");
|
||||
const execFileSyncSpy = spyOn(executor, "execFileSync").mockImplementation(() => {});
|
||||
const execFileSyncSpy = spyOn(executor, "execFileSync").mockImplementation(() => Buffer.from(""));
|
||||
|
||||
const { checkForUpdates } = await import("../update-check.js");
|
||||
await checkForUpdates();
|
||||
|
|
@ -137,12 +135,13 @@ describe("update-check", () => {
|
|||
});
|
||||
|
||||
it("should not update when up to date", async () => {
|
||||
const mockFetch = mock(() => Promise.resolve(new Response(`${pkg.version}\n`)));
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() =>
|
||||
Promise.resolve(new Response(`${pkg.version}\n`)),
|
||||
);
|
||||
|
||||
// Mock executor to prevent actual commands
|
||||
const { executor } = await import("../update-check.js");
|
||||
const execFileSyncSpy = spyOn(executor, "execFileSync").mockImplementation(() => {});
|
||||
const execFileSyncSpy = spyOn(executor, "execFileSync").mockImplementation(() => Buffer.from(""));
|
||||
|
||||
const { checkForUpdates } = await import("../update-check.js");
|
||||
await checkForUpdates();
|
||||
|
|
@ -156,8 +155,7 @@ describe("update-check", () => {
|
|||
});
|
||||
|
||||
it("should handle network errors gracefully", async () => {
|
||||
const mockFetch = mock(() => Promise.reject(new Error("Network error")));
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() => Promise.reject(new Error("Network error")));
|
||||
|
||||
const { checkForUpdates } = await import("../update-check.js");
|
||||
await checkForUpdates();
|
||||
|
|
@ -169,8 +167,7 @@ describe("update-check", () => {
|
|||
});
|
||||
|
||||
it("should handle update failures gracefully", async () => {
|
||||
const mockFetch = mock(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
|
||||
// Mock execFileSync to throw an error (curl fetch fails)
|
||||
const { executor } = await import("../update-check.js");
|
||||
|
|
@ -193,14 +190,13 @@ describe("update-check", () => {
|
|||
});
|
||||
|
||||
it("should handle bad response format", async () => {
|
||||
const mockFetch = mock(() =>
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() =>
|
||||
Promise.resolve(
|
||||
new Response("Not Found", {
|
||||
status: 404,
|
||||
}),
|
||||
),
|
||||
);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
|
||||
const { checkForUpdates } = await import("../update-check.js");
|
||||
await checkForUpdates();
|
||||
|
|
@ -212,8 +208,7 @@ describe("update-check", () => {
|
|||
});
|
||||
|
||||
it("should redirect install script stdout to stderr when jsonOutput=true", async () => {
|
||||
const mockFetch = mock(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
|
||||
const { executor } = await import("../update-check.js");
|
||||
const execFileSyncCalls: {
|
||||
|
|
@ -228,6 +223,7 @@ describe("update-check", () => {
|
|||
args,
|
||||
options,
|
||||
});
|
||||
return Buffer.from("");
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -249,8 +245,7 @@ describe("update-check", () => {
|
|||
});
|
||||
|
||||
it("should use inherit stdio for install script when jsonOutput=false", async () => {
|
||||
const mockFetch = mock(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
|
||||
const { executor } = await import("../update-check.js");
|
||||
const execFileSyncCalls: {
|
||||
|
|
@ -265,6 +260,7 @@ describe("update-check", () => {
|
|||
args,
|
||||
options,
|
||||
});
|
||||
return Buffer.from("");
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -289,20 +285,24 @@ describe("update-check", () => {
|
|||
"sprite",
|
||||
];
|
||||
|
||||
const mockFetch = mock(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
|
||||
const { executor } = await import("../update-check.js");
|
||||
const execFileSyncCalls: {
|
||||
file: string;
|
||||
args: string[];
|
||||
options?: ExecFileSyncOptions;
|
||||
}[] = [];
|
||||
const execFileSyncSpy = spyOn(executor, "execFileSync").mockImplementation((file: string, args: string[]) => {
|
||||
execFileSyncCalls.push({
|
||||
file,
|
||||
args,
|
||||
});
|
||||
});
|
||||
const execFileSyncSpy = spyOn(executor, "execFileSync").mockImplementation(
|
||||
(file: string, args: string[], options?: ExecFileSyncOptions) => {
|
||||
execFileSyncCalls.push({
|
||||
file,
|
||||
args,
|
||||
options,
|
||||
});
|
||||
return Buffer.from("");
|
||||
},
|
||||
);
|
||||
|
||||
const { checkForUpdates } = await import("../update-check.js");
|
||||
await checkForUpdates();
|
||||
|
|
@ -312,7 +312,7 @@ describe("update-check", () => {
|
|||
// 1. curl to fetch install script
|
||||
expect(execFileSyncCalls[0].file).toBe("curl");
|
||||
expect(execFileSyncCalls[0].args).toContain("-fsSL");
|
||||
expect(execFileSyncCalls[0].args.some((a) => a.includes("install.sh"))).toBe(true);
|
||||
expect(execFileSyncCalls[0].args.some((a: string) => a.includes("install.sh"))).toBe(true);
|
||||
// 2. bash to execute fetched script
|
||||
expect(execFileSyncCalls[1].file).toBe("bash");
|
||||
expect(execFileSyncCalls[1].args[0]).toBe("-c");
|
||||
|
|
@ -328,13 +328,13 @@ describe("update-check", () => {
|
|||
]);
|
||||
|
||||
// Should show rerunning message
|
||||
const output = consoleErrorSpy.mock.calls.map((call) => call[0]).join("\n");
|
||||
const output = consoleErrorSpy.mock.calls.map((call: unknown[]) => call[0]).join("\n");
|
||||
expect(output).toContain("Rerunning");
|
||||
|
||||
// Should set SPAWN_NO_UPDATE_CHECK=1 to prevent infinite loop
|
||||
const reexecCall = execFileSyncSpy.mock.calls[3];
|
||||
expect(reexecCall[2]).toHaveProperty("env");
|
||||
expect(reexecCall[2].env.SPAWN_NO_UPDATE_CHECK).toBe("1");
|
||||
const reexecCall = execFileSyncCalls[3];
|
||||
expect(reexecCall.options).toHaveProperty("env");
|
||||
expect(reexecCall.options?.env?.SPAWN_NO_UPDATE_CHECK).toBe("1");
|
||||
|
||||
expect(processExitSpy).toHaveBeenCalledWith(0);
|
||||
|
||||
|
|
@ -352,12 +352,11 @@ describe("update-check", () => {
|
|||
"sprite",
|
||||
];
|
||||
|
||||
const mockFetch = mock(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
|
||||
const { executor } = await import("../update-check.js");
|
||||
let callCount = 0;
|
||||
const execFileSyncSpy = spyOn(executor, "execFileSync").mockImplementation((file: string) => {
|
||||
const execFileSyncSpy = spyOn(executor, "execFileSync").mockImplementation((): Buffer => {
|
||||
callCount++;
|
||||
// First 3 calls succeed (curl, bash, which), 4th call (re-exec) fails
|
||||
if (callCount >= 4) {
|
||||
|
|
@ -367,6 +366,7 @@ describe("update-check", () => {
|
|||
});
|
||||
throw err;
|
||||
}
|
||||
return Buffer.from("");
|
||||
});
|
||||
|
||||
const { checkForUpdates } = await import("../update-check.js");
|
||||
|
|
@ -397,8 +397,9 @@ describe("update-check", () => {
|
|||
// Write an old timestamp (2 hours ago)
|
||||
writeUpdateChecked(Date.now() - 2 * 60 * 60 * 1000);
|
||||
|
||||
const mockFetch = mock(() => Promise.resolve(new Response(`${pkg.version}\n`)));
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() =>
|
||||
Promise.resolve(new Response(`${pkg.version}\n`)),
|
||||
);
|
||||
|
||||
const { checkForUpdates } = await import("../update-check.js");
|
||||
await checkForUpdates();
|
||||
|
|
@ -408,8 +409,9 @@ describe("update-check", () => {
|
|||
});
|
||||
|
||||
it("should write cache file after successful version fetch", async () => {
|
||||
const mockFetch = mock(() => Promise.resolve(new Response(`${pkg.version}\n`)));
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() =>
|
||||
Promise.resolve(new Response(`${pkg.version}\n`)),
|
||||
);
|
||||
|
||||
const { checkForUpdates } = await import("../update-check.js");
|
||||
await checkForUpdates();
|
||||
|
|
@ -429,8 +431,7 @@ describe("update-check", () => {
|
|||
"/usr/local/bin/spawn",
|
||||
];
|
||||
|
||||
const mockFetch = mock(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(mockFetch);
|
||||
const fetchSpy = spyOn(global, "fetch").mockImplementation(() => Promise.resolve(new Response("1.0.99\n")));
|
||||
|
||||
const { executor } = await import("../update-check.js");
|
||||
const execFileSyncCalls: {
|
||||
|
|
@ -442,6 +443,7 @@ describe("update-check", () => {
|
|||
file,
|
||||
args,
|
||||
});
|
||||
return Buffer.from("");
|
||||
});
|
||||
|
||||
const { checkForUpdates } = await import("../update-check.js");
|
||||
|
|
@ -456,7 +458,7 @@ describe("update-check", () => {
|
|||
expect(execFileSyncCalls[3].args).toEqual([]);
|
||||
|
||||
// Should show restarting message
|
||||
const output = consoleErrorSpy.mock.calls.map((call) => call[0]).join("\n");
|
||||
const output = consoleErrorSpy.mock.calls.map((call: unknown[]) => call[0]).join("\n");
|
||||
expect(output).toContain("Restarting spawn");
|
||||
|
||||
expect(processExitSpy).toHaveBeenCalledWith(0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue