
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
@agentforge/testing
Advanced tools
Testing utilities for TypeScript AI agents, including mock LLMs, mock tools, state builders, fixtures, and workflow assertions.
Testing utilities and helpers for the AgentForge framework
Complete testing toolkit | Full TypeScript support | Comprehensive documentation
npm install --save-dev @agentforge/testing
# or
pnpm add -D @agentforge/testing
# or
yarn add -D @agentforge/testing
import { describe, it, expect } from 'vitest';
import {
createMockLLM,
createMockTool,
createStateBuilder,
createAgentTestRunner,
assertMessageContains,
} from '@agentforge/testing';
describe('My Agent', () => {
it('should respond to greetings', async () => {
// Create mock LLM
const llm = createMockLLM({
responses: ['Hello! How can I help you?']
});
// Create test state
const state = createStateBuilder()
.addHumanMessage('Hi')
.build();
// Run agent
const runner = createAgentTestRunner(agent);
const result = await runner.run(state);
// Assert
expect(result.passed).toBe(true);
assertMessageContains(result.messages, 'Hello');
});
});
Create mock language models for testing:
import { createMockLLM, createEchoLLM, createErrorLLM } from '@agentforge/testing';
// Basic mock with predefined responses
const llm = createMockLLM({
responses: ['Response 1', 'Response 2']
});
// Echo LLM (echoes input)
const echoLLM = createEchoLLM();
// Error LLM (always throws)
const errorLLM = createErrorLLM('Custom error message');
// Custom response generator
const customLLM = createMockLLM({
responseGenerator: (messages) => {
const lastMsg = messages[messages.length - 1];
return `You said: ${lastMsg.content}`;
}
});
Create mock tools for testing:
import { createMockTool, createEchoTool, createCalculatorTool } from '@agentforge/testing';
import { z } from 'zod';
// Basic mock tool
const tool = createMockTool({
name: 'my_tool',
schema: z.object({ input: z.string() }),
implementation: async ({ input }) => `Processed: ${input}`
});
// Echo tool
const echoTool = createEchoTool();
// Calculator tool
const calcTool = createCalculatorTool();
Build test states easily:
import { createStateBuilder } from '@agentforge/testing';
const state = createStateBuilder()
.addHumanMessage('Hello')
.addAIMessage('Hi there!')
.set('customField', 'value')
.build();
Helpful assertion functions:
import {
assertMessageContains,
assertLastMessageContains,
assertToolCalled,
assertCompletesWithin,
} from '@agentforge/testing';
// Assert message contains text
assertMessageContains(messages, 'hello');
// Assert last message contains text
assertLastMessageContains(messages, 'goodbye');
// Assert tool was called
assertToolCalled(toolCalls, 'calculator', { operation: 'add' });
// Assert completes within time
await assertCompletesWithin(async () => {
await agent.invoke(input);
}, 1000);
Pre-built test data:
import {
simpleGreeting,
multiTurnConversation,
sampleTools,
calculatorTool,
} from '@agentforge/testing';
// Use sample conversations
const messages = simpleGreeting;
// Use sample tools
const tools = sampleTools;
Run integration tests on agents:
import { createAgentTestRunner } from '@agentforge/testing';
const runner = createAgentTestRunner(agent, {
timeout: 5000,
captureSteps: true,
validateState: true,
});
const result = await runner.run({ messages: [new HumanMessage('Test')] });
expect(result.passed).toBe(true);
expect(result.executionTime).toBeLessThan(5000);
Simulate multi-turn conversations:
import { createConversationSimulator } from '@agentforge/testing';
const simulator = createConversationSimulator(agent, {
maxTurns: 5,
verbose: true,
stopCondition: (messages) => {
const lastMsg = messages[messages.length - 1];
return lastMsg.content.includes('goodbye');
}
});
const result = await simulator.simulate([
'Hello',
'What can you do?',
'Help me with a task'
]);
expect(result.completed).toBe(true);
expect(result.turns).toBe(3);
Create and compare state snapshots:
import {
createSnapshot,
assertMatchesSnapshot,
compareStates,
createStateDiff,
} from '@agentforge/testing';
// Create snapshot
const snapshot = createSnapshot(state, {
normalizeTimestamps: true,
normalizeIds: true,
excludeFields: ['_internal']
});
// Assert matches snapshot
assertMatchesSnapshot(state);
// Compare states
const isEqual = compareStates(state1, state2);
// Create diff
const diff = createStateDiff(stateBefore, stateAfter);
console.log(diff.changed); // { field: { from: 'old', to: 'new' } }
import { describe, it, expect } from 'vitest';
import {
createMockLLM,
createMockTool,
createStateBuilder,
createAgentTestRunner,
createConversationSimulator,
assertMessageContains,
assertToolCalled,
assertMatchesSnapshot,
} from '@agentforge/testing';
import { createReActAgent } from '@agentforge/patterns';
describe('ReAct Agent Integration Tests', () => {
const llm = createMockLLM({
responses: [
'I need to use the calculator tool.',
'The result is 4.'
]
});
const calculatorTool = createMockTool({
name: 'calculator',
implementation: async ({ operation, a, b }) => {
if (operation === 'add') return `${a + b}`;
return '0';
}
});
const agent = createReActAgent({
llm,
tools: [calculatorTool],
});
it('should use tools to solve problems', async () => {
const runner = createAgentTestRunner(agent, {
timeout: 5000,
captureSteps: true
});
const state = createStateBuilder()
.addHumanMessage('What is 2 + 2?')
.build();
const result = await runner.run(state);
expect(result.passed).toBe(true);
assertMessageContains(result.messages, 'calculator');
assertToolCalled(result.finalState.toolCalls, 'calculator');
});
it('should handle multi-turn conversations', async () => {
const simulator = createConversationSimulator(agent, {
maxTurns: 3,
verbose: false
});
const result = await simulator.simulate([
'Hello',
'Calculate 5 + 3',
'Thank you'
]);
expect(result.completed).toBe(true);
expect(result.turns).toBe(3);
assertMatchesSnapshot(result.messages);
});
});
createMockLLM(config?) - Create a mock LLMcreateEchoLLM() - Create an echo LLMcreateErrorLLM(message?) - Create an error LLMcreateMockTool(config?) - Create a mock toolcreateEchoTool(name?) - Create an echo toolcreateCalculatorTool() - Create a calculator toolcreateStateBuilder() - Create a state buildercreateConversationState(messages) - Create conversation statecreateReActState(config?) - Create ReAct agent statecreatePlanningState(config?) - Create planning agent stateassertMessageContains(messages, content) - Assert message contains textassertLastMessageContains(messages, content) - Assert last message contains textassertToolCalled(toolCalls, name, args?) - Assert tool was calledassertCompletesWithin(fn, maxMs) - Assert completes within timeassertStateHasFields(state, fields) - Assert state has fieldsassertMatchesSnapshot(state, config?) - Assert matches snapshotcreateAgentTestRunner(agent, config?) - Create agent test runnercreateConversationSimulator(agent, config?) - Create conversation simulatorsimpleGreeting - Simple greeting conversationmultiTurnConversation - Multi-turn conversationsampleTools - Array of sample toolscalculatorTool - Calculator toolsearchTool - Search toolMIT © 2026 Tom Van Schoor
FAQs
Testing utilities for TypeScript AI agents, including mock LLMs, mock tools, state builders, fixtures, and workflow assertions.
We found that @agentforge/testing demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.