Test Framework Plugins
Zero-config integration for vitest and jest. Import useAimock, write tests
— the server lifecycle, env vars, and cleanup are handled automatically.
Vitest
import { useAimock } from "@copilotkit/aimock/vitest";
const mock = useAimock({ fixtures: "./fixtures" });
it("responds to hello", async () => {
// OPENAI_BASE_URL is already set
const res = await myApp.chat("hello");
expect(res).toBe("Hi there!");
});
Jest
import { useAimock } from "@copilotkit/aimock/jest";
const mock = useAimock({ fixtures: "./fixtures" });
it("responds to hello", async () => {
const res = await myApp.chat("hello");
expect(res).toBe("Hi there!");
});
Options
Both plugins accept the same UseAimockOptions object:
| Option | Type | Default | Description |
|---|---|---|---|
fixtures |
string |
— | Path to fixture file or directory |
patchEnv |
boolean |
true |
Auto-set OPENAI_BASE_URL and ANTHROPIC_BASE_URL |
port |
number |
0 (random) |
Port to listen on |
host |
string |
127.0.0.1 |
Host to bind to |
logLevel |
string |
silent |
Log verbosity |
The Handle
The getter function returned by useAimock() returns an
AimockHandle:
| Property | Type | Description |
|---|---|---|
llm |
LLMock |
The LLMock instance — add fixtures programmatically |
url |
string |
The server URL (e.g., http://127.0.0.1:4010) |
Programmatic fixture registration
const mock = useAimock();
it("custom fixture", async () => {
mock().llm.onMessage("custom", { content: "Custom response" });
// ...
});
Lifecycle
Both plugins register framework hooks to manage the server automatically:
-
beforeAll— starts the server, loads fixtures from thefixturespath, and patchesOPENAI_BASE_URL/ANTHROPIC_BASE_URLenvironment variables -
beforeEach— resets match counts (sequential fixture counters return to zero, but fixtures themselves are preserved) and marks every MCP fake entry as unused -
afterAll— stops the server and restores the original environment variables
MCP fakes
The fixtures path is loaded with LLMock.loadFixtureFile() or
loadFixtureDir(), so a file’s
mcpFakes load too, and aimock mounts
an MCPMock at each block’s mount path. A bad
mcpFakes block fails beforeAll with a
FixtureLoadError. Other load failures still only print a warning, as before.
Because beforeEach marks the fake entries as unused, each test starts with
its full list of answers.
With aimock-pytest, aimock.load_fixtures(path) posts a
file’s mcpFakes to the control API with its fixtures. A file may hold
only mcpFakes. When the server rejects the file with HTTP 400, the
requests.HTTPError message is
aimock rejected fixtures from <path>: <error>, followed by one
line for each item of details. When the file has mcpFakes and
the aimock server is a release without MCP fakes, load_fixtures raises
RuntimeError (aimock server too old for mcpFakes: ...) and adds
nothing from the file.
Without Plugins (Manual)
For comparison, here is the equivalent manual setup. The plugins above handle all of this for you:
import { LLMock } from "@copilotkit/aimock";
let mock: LLMock;
beforeAll(async () => {
mock = new LLMock();
mock.onMessage("hello", { content: "Hi!" });
await mock.start();
process.env.OPENAI_BASE_URL = `${mock.url}/v1`;
});
afterAll(async () => {
await mock.stop();
delete process.env.OPENAI_BASE_URL;
});