diff --git a/docs/testing.md b/docs/testing.md index 946db07bf1..4ec866a6d8 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -144,8 +144,11 @@ without serial scheduling. Pure domain/service, composition, conformance, evaluation, CLI boundary, and MCP boundary projects share module graphs. Their tests avoid process-global state and keep resource cleanup test-scoped. Each MCP session still owns its resources, and CLI cases retain fresh command -instances or subprocesses. CLI and MCP module mocks belong in `tests/process-global/` -so they keep per-file isolation. Product catalog verification stays with the +instances or subprocesses. Fixtures using `vi.mock` or `vi.doMock` need an +isolated project. CLI/MCP fixtures normally live in `tests/process-global/`. +When a path must stay, assign it explicitly in `scripts/lib/test-projects.mjs`, +exclude it from its shared owner, and preserve its source/built group. +Product catalog verification stays with the isolated filesystem boundary tests because it loads both source and compiled module graphs. Adapter, other boundary, acceptance, and process-global projects retain per-file isolation. See `vitest.config.ts` for current settings. @@ -156,6 +159,10 @@ with the consumer preloaded as well as alone. For simulated protocol traces, use an acknowledged event barrier before asserting complete observations; a zero-duration capture does not guarantee queued events have arrived. +Focused contract tests should import the named contract family they exercise; +reserve the full tool catalog for catalog-wide assertions. Resolve contracts by +operation name rather than array position. + Check advertised schemas after SDK conversion for every supported schema profile. Meta-schema validity does not establish client acceptance or useful rendered declarations. Keep canonical rejection checks separate from the diff --git a/tests/boundary/cli/fridaCli.test.ts b/tests/boundary/cli/fridaCli.test.ts index efdfac275e..fff4af9277 100644 --- a/tests/boundary/cli/fridaCli.test.ts +++ b/tests/boundary/cli/fridaCli.test.ts @@ -6,7 +6,7 @@ import { expect, it } from "vitest"; import type { DeviceManager } from "frida"; import { createCli } from "../../../src/cli.js"; -import { toolContract } from "../../../src/contracts/toolContracts.js"; +import { FRIDA_TOOL_CONTRACTS } from "../../../src/contracts/fridaToolContracts.js"; import type { FridaInstrumentationPort } from "../../../src/application/frida/FridaInstrumentationPort.js"; import { AnalysisCapabilityUnavailableError } from "../../../src/domain/analysisErrorCore.js"; import { FridaInstrumentationManager } from "../../../src/frida/FridaInstrumentationManager.js"; @@ -47,9 +47,9 @@ it.each([ ); expect(exitCode).toBe(0); expect(closed).toBe(true); - const output = toolContract("list_frida_devices").outputSchema.parse( - JSON.parse(stdout), - ); + const output = FRIDA_TOOL_CONTRACTS.find( + (contract) => contract.name === "list_frida_devices", + )!.outputSchema.parse(JSON.parse(stdout)); expect(output).toEqual({ devices: observation.devices.map(({ deviceId, name, type }) => ({ device_id: deviceId, @@ -106,9 +106,9 @@ it.each([false, true])( }); else expect( - toolContract("list_frida_processes").outputSchema.parse( - JSON.parse(stdout), - ), + FRIDA_TOOL_CONTRACTS.find( + (contract) => contract.name === "list_frida_processes", + )!.outputSchema.parse(JSON.parse(stdout)), ).toEqual(expected); }, ); @@ -214,7 +214,9 @@ it("maps one-shot Frida CLI target, script, duration, and remote options", async expect(exitCode).toBe(0); const result: unknown = JSON.parse(stdout); expect(() => - toolContract("instrument_with_frida").outputSchema.parse(result), + FRIDA_TOOL_CONTRACTS.find( + (contract) => contract.name === "instrument_with_frida", + )!.outputSchema.parse(result), ).not.toThrow(); expect(JSON.stringify(result)).not.toContain("synthetic-secret-token"); expect(calls).toEqual([