ci: stabilize vitest runs

This commit is contained in:
Peter Steinberger
2026-01-18 06:58:46 +00:00
parent f86b24c511
commit d3b15c6afa
17 changed files with 28 additions and 25 deletions

View File

@@ -52,7 +52,7 @@ describe("Agent-specific sandbox config", () => {
it(
"should use global sandbox config when no agent-specific config exists",
{ timeout: 15_000 },
{ timeout: 60_000 },
async () => {
const { resolveSandboxContext } = await import("./sandbox.js");

View File

@@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest";
describe("sandbox config merges", () => {
it("resolves sandbox scope deterministically", { timeout: 15_000 }, async () => {
it("resolves sandbox scope deterministically", { timeout: 60_000 }, async () => {
const { resolveSandboxScope } = await import("./sandbox.js");
expect(resolveSandboxScope({})).toBe("agent");

View File

@@ -97,7 +97,7 @@ afterEach(() => {
});
describe("trigger handling", () => {
it("stages inbound media into the sandbox workspace", { timeout: 15_000 }, async () => {
it("stages inbound media into the sandbox workspace", { timeout: 60_000 }, async () => {
await withTempHome(async (home) => {
const inboundDir = join(home, ".clawdbot", "media", "inbound");
await fs.mkdir(inboundDir, { recursive: true });

View File

@@ -26,7 +26,7 @@ vi.mock("../runtime.js", () => ({
}));
describe("cron cli", () => {
it("trims model and thinking on cron add", { timeout: 30_000 }, async () => {
it("trims model and thinking on cron add", { timeout: 60_000 }, async () => {
callGatewayFromCli.mockClear();
const { registerCronCli } = await import("./cron-cli.js");

View File

@@ -14,7 +14,7 @@ vi.mock("../commands/models.js", async () => {
});
describe("models cli", () => {
it("registers github-copilot login command", { timeout: 15_000 }, async () => {
it("registers github-copilot login command", { timeout: 60_000 }, async () => {
const { Command } = await import("commander");
const { registerModelsCli } = await import("./models-cli.js");

View File

@@ -322,7 +322,7 @@ vi.mock("./doctor-state-migrations.js", () => ({
}));
describe("doctor command", () => {
it("migrates routing.allowFrom to channels.whatsapp.allowFrom", { timeout: 30_000 }, async () => {
it("migrates routing.allowFrom to channels.whatsapp.allowFrom", { timeout: 60_000 }, async () => {
readConfigFileSnapshot.mockResolvedValue({
path: "/tmp/clawdbot.json",
exists: true,
@@ -366,7 +366,7 @@ describe("doctor command", () => {
expect(written.routing).toBeUndefined();
});
it("migrates legacy gateway services", { timeout: 30_000 }, async () => {
it("migrates legacy gateway services", { timeout: 60_000 }, async () => {
readConfigFileSnapshot.mockResolvedValue({
path: "/tmp/clawdbot.json",
exists: true,

View File

@@ -33,7 +33,7 @@ beforeEach(() => {
});
describe("discord native commands", () => {
it("streams tool results for native slash commands", { timeout: 30_000 }, async () => {
it("streams tool results for native slash commands", { timeout: 60_000 }, async () => {
const { ChannelType } = await import("@buape/carbon");
const { createDiscordNativeCommand } = await import("./monitor.js");

View File

@@ -333,7 +333,7 @@ describe("gateway server agent", () => {
await server.close();
});
test("agent dedupe survives reconnect", { timeout: 15000 }, async () => {
test("agent dedupe survives reconnect", { timeout: 60_000 }, async () => {
const port = await getFreePort();
const server = await startGatewayServer(port);

View File

@@ -26,7 +26,7 @@ async function waitForWsClose(ws: WebSocket, timeoutMs: number): Promise<boolean
}
describe("gateway server auth/connect", () => {
test("closes silent handshakes after timeout", { timeout: 30_000 }, async () => {
test("closes silent handshakes after timeout", { timeout: 60_000 }, async () => {
vi.useRealTimers();
const { server, ws } = await startServerWithClient();
const closed = await waitForWsClose(ws, HANDSHAKE_TIMEOUT_MS + 2_000);
@@ -129,7 +129,7 @@ describe("gateway server auth/connect", () => {
test(
"invalid connect params surface in response and close reason",
{ timeout: 15000 },
{ timeout: 60_000 },
async () => {
const { server, ws } = await startServerWithClient();
const closeInfoPromise = new Promise<{ code: number; reason: string }>((resolve) => {

View File

@@ -26,7 +26,7 @@ async function waitFor(condition: () => boolean, timeoutMs = 1500) {
}
describe("gateway server chat", () => {
test("chat.history caps payload bytes", { timeout: 15_000 }, async () => {
test("chat.history caps payload bytes", { timeout: 60_000 }, async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
@@ -105,7 +105,7 @@ describe("gateway server chat", () => {
await server.close();
});
test("chat.abort cancels an in-flight chat.send", { timeout: 15000 }, async () => {
test("chat.abort cancels an in-flight chat.send", { timeout: 60_000 }, async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({
@@ -263,7 +263,7 @@ describe("gateway server chat", () => {
await server.close();
});
test("chat.send treats /stop as an out-of-band abort", { timeout: 15000 }, async () => {
test("chat.send treats /stop as an out-of-band abort", { timeout: 60_000 }, async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-"));
testState.sessionStorePath = path.join(dir, "sessions.json");
await writeSessionStore({

View File

@@ -16,7 +16,7 @@ import {
installGatewayTestHooks();
describe("gateway server health/presence", () => {
test("connect + health + presence + status succeed", { timeout: 20_000 }, async () => {
test("connect + health + presence + status succeed", { timeout: 60_000 }, async () => {
const { server, ws } = await startServerWithClient();
await connectOk(ws);

View File

@@ -46,7 +46,7 @@ describe("gateway server misc", () => {
}
});
test("send dedupes by idempotencyKey", { timeout: 20_000 }, async () => {
test("send dedupes by idempotencyKey", { timeout: 60_000 }, async () => {
const { server, ws } = await startServerWithClient();
await connectOk(ws);

View File

@@ -64,7 +64,7 @@ describe("gateway server models + voicewake", () => {
test(
"voicewake.get returns defaults and voicewake.set broadcasts",
{ timeout: 30_000 },
{ timeout: 60_000 },
async () => {
const homeDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-home-"));
const restoreHome = setTempHome(homeDir);

View File

@@ -95,7 +95,7 @@ describe("sessions_send gateway loopback", () => {
});
describe("sessions_send label lookup", () => {
it("finds session by label and sends message", { timeout: 15_000 }, async () => {
it("finds session by label and sends message", { timeout: 60_000 }, async () => {
const port = await getFreePort();
const prevPort = process.env.CLAWDBOT_GATEWAY_PORT;
process.env.CLAWDBOT_GATEWAY_PORT = String(port);
@@ -170,7 +170,7 @@ describe("sessions_send label lookup", () => {
}
});
it("returns error when label not found", { timeout: 15_000 }, async () => {
it("returns error when label not found", { timeout: 60_000 }, async () => {
const port = await getFreePort();
const prevPort = process.env.CLAWDBOT_GATEWAY_PORT;
process.env.CLAWDBOT_GATEWAY_PORT = String(port);
@@ -199,7 +199,7 @@ describe("sessions_send label lookup", () => {
}
});
it("returns error when neither sessionKey nor label provided", { timeout: 15_000 }, async () => {
it("returns error when neither sessionKey nor label provided", { timeout: 60_000 }, async () => {
const port = await getFreePort();
const prevPort = process.env.CLAWDBOT_GATEWAY_PORT;
process.env.CLAWDBOT_GATEWAY_PORT = String(port);

View File

@@ -228,7 +228,7 @@ describe("web auto-reply", () => {
await run;
}, 15_000);
it("stops after hitting max reconnect attempts", { timeout: 20000 }, async () => {
it("stops after hitting max reconnect attempts", { timeout: 60_000 }, async () => {
const closeResolvers: Array<() => void> = [];
const sleep = vi.fn(async () => {});
const listenerFactory = vi.fn(async () => {

View File

@@ -21,7 +21,7 @@ describe("web logout", () => {
vi.restoreAllMocks();
});
it("deletes cached credentials when present", { timeout: 15_000 }, async () => {
it("deletes cached credentials when present", { timeout: 60_000 }, async () => {
await withTempHome(async (home) => {
vi.resetModules();
const { logoutWeb, WA_WEB_AUTH_DIR } = await import("./session.js");
@@ -37,7 +37,7 @@ describe("web logout", () => {
});
});
it("no-ops when nothing to delete", { timeout: 15_000 }, async () => {
it("no-ops when nothing to delete", { timeout: 60_000 }, async () => {
await withTempHome(async () => {
vi.resetModules();
const { logoutWeb } = await import("./session.js");

View File

@@ -3,6 +3,7 @@ import { fileURLToPath } from "node:url";
import { defineConfig } from "vitest/config";
const repoRoot = path.dirname(fileURLToPath(import.meta.url));
const isCI = process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
export default defineConfig({
resolve: {
@@ -11,8 +12,10 @@ export default defineConfig({
},
},
test: {
testTimeout: 30_000,
hookTimeout: 60_000,
testTimeout: 60_000,
hookTimeout: 120_000,
pool: "forks",
maxWorkers: isCI ? 3 : 4,
include: [
"src/**/*.test.ts",
"extensions/**/*.test.ts",