Testing
8 min readUpdated: October 2026

Testing AI Agents in TypeScript: Unit Tests, Mocks & Integration Testing

Technical Review: Smoke Monkey Core Architecture Team
Tested on Node.js 18+ & BunTypeScript 5.x
Quick Answer & Executive Definition

Testing AI Agents in TypeScript: Unit Tests, Mocks & Integration Testing: Designed as a zero-dependency, open-source TypeScript architecture under the MIT License with native Model Context Protocol (MCP) support and deterministic phase state machines.

Key Architectural Takeaways

Mocking the LLM Provider

The key to fast, deterministic agent tests is replacing the live LLM with a scripted mock that returns predefined tool calls and responses:

agent.test.tstypescript
import { describe, it, expect, vi } from 'vitest';
import { createAgent } from 'smoke-monkey-harness';
// Mock the LLM provider to return a scripted tool call sequence
vi.mock('smoke-monkey-harness/providers', () => ({
createProvider: () => ({
complete: vi.fn()
// First call: agent decides to read a file
.mockResolvedValueOnce({
toolCalls: [{ name: 'read_file', args: { path: 'src/utils.ts' } }],
})
// Second call: agent writes the fix
.mockResolvedValueOnce({
toolCalls: [{ name: 'replace_file_content', args: {
path: 'src/utils.ts',
oldText: 'var x = 1',
newText: 'const x = 1',
}}],
})
// Third call: agent completes
.mockResolvedValueOnce({ content: 'Done. Replaced var with const.' }),
}),
}));
describe('refactoring agent', () => {
it('replaces var with const in target file', async () => {
const agent = createAgent({ provider: 'anthropic', model: 'claude-3-7-sonnet', workspacePath: '/tmp/test' });
const result = await agent.run('Replace all var declarations with const');
expect(result.toolCallCount).toBe(2);
expect(result.summary).toContain('const');
});
});

Integration Testing with Real Models

For integration tests that validate end-to-end agent behaviour against real LLMs:

  1. Use a cheap, fast model like claude-3-haiku or gpt-4o-mini to keep costs low.
  2. Scope tasks tightly — give the agent a small, well-defined task with a verifiable outcome.
  3. Assert on outcomes, not on the exact sequence of tool calls (which may vary between runs).
  4. Set maxIterations low (e.g., 5) to prevent runaway integration tests.

Run integration tests in CI only on PRs to main, not on every feature branch commit.

Never use production API keys in CI integration tests

Use test-specific API keys with low rate limits and spending caps. Tag all integration test requests with a custom header for cost attribution.

Google Search Questions & Answers

Frequently Asked Questions

Q:How do I test that a permission gate correctly blocks a dangerous tool call?

Set the tool permission to "deny" and assert that the agent emits a permission.denied event for that tool call, and that the tool was never executed (verify via the mock).

Q:Can I use Jest instead of Vitest?

Yes. Smoke Monkey Harness is test-framework agnostic. Replace vi.mock with jest.mock and vi.fn with jest.fn — the mocking pattern is identical.

Related Alternatives & Comparisons

Build with Smoke Monkey Harness

Zero dependencies. 24 built-in tools. Human-in-the-loop safety. 100% open source under the MIT License.

npm install smoke-monkey-harness