Testing
Pick a layer, then open the working page for that kind of test.
Test the public behavior your app uses. Keep the runtime and thread state real when they are part of that behavior. Mock the model, or an external API, only when that is not what the test is about.
This page is the map. Each layer has a working page with the branches you actually write.
| Layer | Package | Model | Working page |
|---|---|---|---|
| Tool | @pai/test-utils | none | Tool tests |
| Runtime | @pai/test-utils | mocked | Runtime tests |
| Eval | @pai/test-utils | real or mocked | Evals |
| React | @pai/react-test-utils | none | React tests |
Which layer?
- Tool — one
execute: schemas, context, suspend,fail, cancel. - Runtime — PAI wired the agent: the model called a tool, a pending action appeared, a second send ran.
- Eval — the model chose the right tool or said the right thing. Stub tools so you score the agent, not your CRM.
- React — a card, a chat page, a client tool. Script thread state; there is no runtime behind it.
import { runTool } from "@pai/test-utils";
const result = await runTool(searchDocs, {
input: { query: "tenancy" },
context: { workspaceId: "ws_1", docs: fakeDocs },
});
expect(result.expectOutput().hits[0]?.title).toBe("Identity");That is a tool test. The other layers look different on purpose — see the working pages.