mockAgent()
mockAgent() creates a runtime-neutral Agent mock with writable signals for testing @threadplane/chat components. Use it when you're testing chat UI behavior and don't need LangGraph-specific fields.
Import:
import {
completeDelivery,
mockAgent,
staticDelivery,
streamingDelivery,
} from '@threadplane/chat';
import type { MockAgent } from '@threadplane/chat';Signature
function mockAgent(opts?: MockAgentOptions): MockAgentOptions
| Option | Type | Default | Description |
|---|---|---|---|
messages | Message[] | [] | Initial runtime-neutral messages |
status | AgentStatus | 'idle' | Initial agent status |
isLoading | boolean | false | Whether the agent is currently running |
error | unknown | null | Initial error value |
toolCalls | ToolCall[] | [] | Initial tool-call list |
state | Record<string, unknown> | {} | Initial agent state |
withInterrupt | boolean | false | Include a writable interrupt signal |
withSubagents | boolean | false | Include a writable subagents signal |
history | AgentCheckpoint[] | undefined | Include history and return an AgentWithHistory-compatible mock |
events$ | Observable<AgentEvent> | EMPTY | Event stream the mock exposes via events$ (defaults to RxJS EMPTY) |
Basic Test Usage
import { TestBed } from '@angular/core/testing';
import { ChatComponent, mockAgent, staticDelivery } from '@threadplane/chat';
it('renders messages from an agent', async () => {
const agent = mockAgent({
messages: [
{ id: 'm1', role: 'user', content: 'Hello', delivery: staticDelivery('m1') },
{ id: 'm2', role: 'assistant', content: 'Hi there', delivery: staticDelivery('m2') },
],
});
await TestBed.configureTestingModule({
imports: [ChatComponent],
}).compileComponents();
const fixture = TestBed.createComponent(ChatComponent);
fixture.componentRef.setInput('agent', agent);
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toContain('Hello');
expect(fixture.nativeElement.textContent).toContain('Hi there');
});Controlling State
The returned mock exposes writable signals, so tests can update state directly:
const agent = mockAgent();
const generation = 'attempt-1';
agent.status.set('running');
agent.isLoading.set(true);
agent.messages.set([{
id: 'm1',
role: 'assistant',
content: 'Ret',
delivery: streamingDelivery(generation),
}]);
agent.status.set('error');
agent.isLoading.set(false);
agent.error.set(new Error('Connection failed'));
agent.messages.set([{
id: 'm1',
role: 'assistant',
content: 'Retry?',
delivery: completeDelivery(generation, 'error'),
}]);Spying on Actions
The mock records calls to core actions:
const agent = mockAgent();
await agent.submit({ message: 'Hello' });
await agent.stop();
await agent.regenerate(1);
expect(agent.submitCalls[0]?.input).toEqual({ message: 'Hello' });
expect(agent.stopCount).toBe(1);
expect(agent.submitCalls[1]?.input).toEqual({
regenerate: { assistantMessageIndex: 1 },
});Lifecycle and History
mockAgent() exposes a readonly lifecycle.streamStartedAt signal plus an _internal.streamStartedAt writable escape hatch. Use the escape hatch to drive stream-start timing in a test without running a full submit/stream cycle:
const agent = mockAgent();
// Flip the underlying writable; lifecycle.streamStartedAt() reflects it.
agent._internal.streamStartedAt.set(Date.now());
expect(agent.lifecycle.streamStartedAt()).not.toBeNull();The withInterrupt, withSubagents, and history options unlock optional signals — interrupt, subagents, and history are undefined unless you opt in, so tests must null-check (or use ?.) before driving them:
const agent = mockAgent({
withInterrupt: true,
withSubagents: true,
history: [], // pass an AgentCheckpoint[] to enable agent.history
});
// Each optional signal is writable when its option was set.
agent.interrupt?.set({ id: 'int-1', value: 'Approve this action?', resumable: true });
agent.history?.set([{ id: 'ckpt-1', values: {} }]);
expect(agent.subagents?.()).toBeDefined();LangGraph-Specific Tests
Use mockLangGraphAgent() from @threadplane/langgraph only when the test needs LangGraph-specific signals such as raw LangGraph messages, checkpoint state, branches, queued runs, or transport metadata.