Skip to content

Testing Guide

The SDK provides testing utilities at two levels: lightweight mocks for unit tests, and the Mock LLM backend for integration tests.

ImportPurpose
@witqq/agent-sdk/testingMock factories for services, runtimes, clients, sessions, messages
@witqq/agent-sdk/mock-llmFull Mock LLM backend with BaseAgent lifecycle

All factories are in @witqq/agent-sdk/testing. They return objects that implement SDK interfaces without requiring a real backend.

Creates a mock IAgentService. Use for testing code that depends on agent services.

import { createMockAgentService } from "@witqq/agent-sdk/testing";
import type { MockAgentServiceOptions } from "@witqq/agent-sdk/testing";
const service = createMockAgentService({
name: "test-service",
models: [
{ id: "test-model", name: "Test Model", provider: "test" },
],
validationResult: { valid: true, errors: [] },
onRun: async (prompt, options) => ({
output: `Echo: ${typeof prompt === "string" ? prompt : "complex"}`,
structuredOutput: undefined,
toolCalls: [],
messages: [],
}),
});
const models = await service.listModels();
const validation = await service.validate();
const agent = service.createAgent({ systemPrompt: "Test" });

Options:

FieldTypeDefaultDescription
namestring"mock"Service name
modelsModelInfo[][]Available models
validationResultValidationResult{ valid: true }validate() return
onRun(prompt, options) => Promise<AgentResult>echoCustom run handler
onStream(prompt, options) => AsyncIterable<AgentEvent>echo streamCustom stream handler
mockLLMBackendMockLLMBackendOptionsDelegate to full Mock LLM

Creates a mock IChatRuntime. Use for testing chat runtime consumers.

import { createMockRuntime, createMockSession } from "@witqq/agent-sdk/testing";
const session = createMockSession({ title: "Test chat" });
const runtime = createMockRuntime({
defaultBackend: "mock",
defaultModel: "test-model",
sessions: [session],
models: [{ id: "test-model", name: "Test" }],
onSend: async function* (sessionId, message) {
yield { type: "message:start", messageId: "msg-1", role: "assistant" };
yield { type: "message:delta", messageId: "msg-1", text: "Response" };
yield { type: "done" };
},
});

Options:

FieldTypeDefaultDescription
defaultBackendstring"mock"Default backend name
defaultModelstringDefault model ID
sessionsChatSession[][]Pre-populated sessions
modelsModelInfo[][]Available models
onSend(sessionId, message, options?) => AsyncIterable<ChatEvent>Custom send handler

Creates a mock IChatClient. Use for React component tests.

import { createMockChatClient, createMockSession } from "@witqq/agent-sdk/testing";
const client = createMockChatClient({
sessions: [createMockSession({ title: "Chat 1" })],
models: [{ id: "gpt-4.1", name: "GPT-4.1" }],
providers: [{ id: "openai", backend: "vercel-ai", model: "gpt-4.1", label: "OpenAI GPT-4.1", createdAt: Date.now() }],
onSend: async function* (sessionId, message) {
yield { type: "message:start", messageId: "msg-1", role: "assistant" };
yield { type: "done" };
},
});

Options:

FieldTypeDefaultDescription
sessionsChatSession[][]Pre-populated sessions
modelsModelInfo[][]Available models
providersProviderConfig[][]Provider configurations
onSend(sessionId, message, options?) => AsyncIterable<ChatEvent>Custom send handler

Factory for ChatSession test instances. All fields have sensible defaults.

import { createMockSession } from "@witqq/agent-sdk/testing";
const session = createMockSession({
id: "session-123",
title: "Test session",
config: { model: "gpt-4.1", backend: "copilot" },
messages: [],
status: "active",
});

Factory for ChatMessage test instances.

import { createMockMessage } from "@witqq/agent-sdk/testing";
const userMsg = createMockMessage({
role: "user",
text: "Hello",
status: "complete",
});
const assistantMsg = createMockMessage({
role: "assistant",
parts: [
{ type: "text", text: "Hi there", status: "complete" },
{ type: "reasoning", text: "User greeted me", status: "complete" },
],
status: "complete",
});

Options:

FieldTypeDefaultDescription
idstringgeneratedMessage ID
role"user" | "assistant" | "system""user"Message role
textstringShorthand: creates a single TextPart
partsMessagePart[]Full parts array (overrides text)
status"pending" | "streaming" | "complete" | "error""complete"Message status
metadataRecord<string, unknown>Custom metadata

For integration tests that need the full agent lifecycle (tool calls, permissions, streaming), use the Mock LLM backend. See Mock LLM Guide for complete documentation.

import { createMockLLMService } from "@witqq/agent-sdk/mock-llm";
const service = createMockLLMService({
mode: { type: "static", response: "Test response" },
});

Mock LLM response modes:

ModeDescription
{ type: "echo" }Returns the user prompt
{ type: "static", response: string }Fixed response
{ type: "scripted", responses: string[], loop?: boolean }Sequence of responses
{ type: "error", error: string, code?, recoverable? }Simulates errors
import { describe, it, expect } from "vitest";
import { z } from "zod";
import type { ToolDefinition, ToolContext } from "@witqq/agent-sdk";
const calculator: ToolDefinition<{ a: number; b: number; op: string }> = {
name: "calc",
description: "Calculate",
parameters: z.object({ a: z.number(), b: z.number(), op: z.string() }),
execute: async ({ a, b, op }) => {
if (op === "add") return a + b;
if (op === "mul") return a * b;
throw new Error(`Unknown op: ${op}`);
},
};
describe("calculator tool", () => {
it("adds numbers", async () => {
const result = await calculator.execute({ a: 2, b: 3, op: "add" });
expect(result).toBe(5);
});
it("rejects unknown ops", async () => {
await expect(calculator.execute({ a: 1, b: 1, op: "div" })).rejects.toThrow("Unknown op");
});
});
import { render, screen } from "@testing-library/react";
import { createMockChatClient, createMockSession, createMockMessage } from "@witqq/agent-sdk/testing";
const session = createMockSession({
title: "Test",
messages: [
createMockMessage({ role: "user", text: "Hello" }),
createMockMessage({ role: "assistant", text: "Hi" }),
],
});
const client = createMockChatClient({
sessions: [session],
});
// Pass client to your component under test
render(<ChatView client={client} sessionId={session.id} />);
import { createMockAgentService } from "@witqq/agent-sdk/testing";
import type { AgentEvent } from "@witqq/agent-sdk";
const service = createMockAgentService({
onStream: async function* (): AsyncIterable<AgentEvent> {
yield { type: "session_info", sessionId: "s1", backend: "mock" };
yield { type: "text_delta", text: "Hello " };
yield { type: "text_delta", text: "world" };
yield { type: "usage_update", promptTokens: 10, completionTokens: 5 };
yield { type: "done", finalOutput: "Hello world" };
},
});
const agent = service.createAgent({ systemPrompt: "Test" });
const events: AgentEvent[] = [];
for await (const event of agent.stream("Hi", { model: "test" })) {
events.push(event);
}
expect(events.filter((e) => e.type === "text_delta")).toHaveLength(2);
import { createMockLLMService } from "@witqq/agent-sdk/mock-llm";
import { z } from "zod";
it("executes tool calls", async () => {
const service = createMockLLMService({
mode: { type: "static", response: "Done" },
toolCalls: [{ name: "greet", args: { name: "Alice" } }],
});
const agent = service.createAgent({
systemPrompt: "Greeter",
tools: [{
name: "greet",
description: "Greet someone",
parameters: z.object({ name: z.string() }),
execute: async ({ name }) => `Hello, ${name}!`,
}],
});
const result = await agent.run("Greet Alice", { model: "mock-model" });
expect(result.toolCalls).toHaveLength(1);
expect(result.toolCalls[0].result).toBe("Hello, Alice!");
});
NeedUseImport
Test tool execute() in isolationDirect function call@witqq/agent-sdk
Test code that takes IAgentServicecreateMockAgentService@witqq/agent-sdk/testing
Test chat runtime consumerscreateMockRuntime@witqq/agent-sdk/testing
Test React chat componentscreateMockChatClient@witqq/agent-sdk/testing
Generate test ChatSession datacreateMockSession@witqq/agent-sdk/testing
Generate test ChatMessage datacreateMockMessage@witqq/agent-sdk/testing
Full agent lifecycle (tools, permissions, streaming)Mock LLM Backend@witqq/agent-sdk/mock-llm

API Reference: Testing Utilities · Mock LLM Backend