diff --git a/server/src/__tests__/agent-device-login-routes.test.ts b/server/src/__tests__/agent-device-login-routes.test.ts index c9e1841964f..98128d9438c 100644 --- a/server/src/__tests__/agent-device-login-routes.test.ts +++ b/server/src/__tests__/agent-device-login-routes.test.ts @@ -3,7 +3,7 @@ import request from "supertest"; import { lstat, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { withAccountHomeSecretMutationLock } from "@paperclipai/adapter-codex-local/server"; import { AdapterAuthSessionConflictError } from "../services/device-login-service.js"; import type { @@ -386,8 +386,11 @@ describe("adapter device-login routes", () => { // `afterEach` whether or not the route removed them itself. const accountHomeTestDirs: string[] = []; - beforeEach(() => { + beforeAll(() => { vi.resetModules(); + }); + + beforeEach(() => { vi.clearAllMocks(); mockDeviceLoginPromotion.mockResolvedValue({ outcome: "promoted", @@ -1330,9 +1333,6 @@ describe("adapter device-login routes", () => { accountHomeDir, accountHomeCreated: true, }); - // `vi.resetModules()` in `beforeEach` gives the route module a fresh copy - // of `../errors.js`. Import the conflict helper from that same fresh copy, - // so the route's `err instanceof HttpError` check sees a matching class. const { conflict: freshConflict } = await vi.importActual("../errors.js"); mockSecretService.create.mockRejectedValueOnce( diff --git a/server/src/__tests__/agent-skills-routes.test.ts b/server/src/__tests__/agent-skills-routes.test.ts index 6e4f29ddf10..f49dcd8ea56 100644 --- a/server/src/__tests__/agent-skills-routes.test.ts +++ b/server/src/__tests__/agent-skills-routes.test.ts @@ -1,7 +1,7 @@ import express from "express"; import { readFile } from "node:fs/promises"; import request from "supertest"; -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const runnerTarget = vi.hoisted(() => ({ driver: "local", platform: "linux", architecture: "x64" })); vi.mock("../services/agent-runner-selection.js", async (importOriginal) => { @@ -272,14 +272,21 @@ function skillSnapshot(adapterType = "claude_local", mode = "ephemeral") { } describe("agent skill routes", () => { - beforeEach(async () => { - runnerTarget.platform = "linux"; - runnerTarget.architecture = "x64"; + beforeAll(async () => { vi.resetModules(); vi.doUnmock("../routes/agents.js"); vi.doUnmock("../routes/authz.js"); vi.doUnmock("../middleware/index.js"); registerModuleMocks(); + [{ agentRoutes }, { errorHandler }] = await Promise.all([ + vi.importActual("../routes/agents.js"), + vi.importActual("../middleware/index.js"), + ]); + }); + + beforeEach(() => { + runnerTarget.platform = "linux"; + runnerTarget.architecture = "x64"; vi.clearAllMocks(); for (const mock of Object.values(mockAgentService)) mock.mockReset(); for (const mock of Object.values(mockAccessService)) mock.mockReset(); @@ -384,13 +391,6 @@ describe("agent skill routes", () => { mockAccessService.listPrincipalGrants.mockResolvedValue([]); mockAccessService.ensureMembership.mockResolvedValue(undefined); mockAccessService.setPrincipalPermission.mockResolvedValue(undefined); - - // Prepare the module graph inside the setup budget after every reset. Each - // test still constructs its own app after configuring its request-specific mocks. - [{ agentRoutes }, { errorHandler }] = await Promise.all([ - vi.importActual("../routes/agents.js"), - vi.importActual("../middleware/index.js"), - ]); }); it("skips runtime materialization when listing Claude skills", async () => { diff --git a/server/src/__tests__/issue-attachment-routes.test.ts b/server/src/__tests__/issue-attachment-routes.test.ts index 1415722b2fb..383169997da 100644 --- a/server/src/__tests__/issue-attachment-routes.test.ts +++ b/server/src/__tests__/issue-attachment-routes.test.ts @@ -2,7 +2,7 @@ import { Readable } from "node:stream"; import type { IncomingMessage } from "node:http"; import express from "express"; import request from "supertest"; -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import type { StorageService } from "../storage/types.js"; const mockIssueService = vi.hoisted(() => ({ @@ -224,7 +224,7 @@ describe("MAX_ATTACHMENT_BYTES", () => { }); describe("issue attachment routes", () => { - beforeEach(() => { + beforeAll(() => { vi.resetModules(); vi.doUnmock("@paperclipai/shared/telemetry"); vi.doUnmock("../telemetry.js"); @@ -235,6 +235,9 @@ describe("issue attachment routes", () => { vi.doUnmock("../routes/authz.js"); vi.doUnmock("../middleware/index.js"); registerRouteMocks(); + }); + + beforeEach(() => { vi.clearAllMocks(); mockAccessService.decide.mockResolvedValue({ allowed: true, diff --git a/server/src/routes/setup-token-route.test.ts b/server/src/routes/setup-token-route.test.ts index aaa448f9027..97357ef7966 100644 --- a/server/src/routes/setup-token-route.test.ts +++ b/server/src/routes/setup-token-route.test.ts @@ -19,7 +19,7 @@ import express from "express"; import { Writable } from "node:stream"; import request from "supertest"; -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { SETUP_TOKEN_SESSION_NOT_FOUND, @@ -465,9 +465,12 @@ async function settle(): Promise { } } -beforeEach(() => { +beforeAll(() => { vi.resetModules(); registerModuleMocks(); +}); + +beforeEach(() => { vi.clearAllMocks(); useOwner(); // The default registry declares the Claude setup-token capability for