The official TypeScript SDK is @anthropic-ai/sdk on npm, installed with npm install @anthropic-ai/sdk. Its README lists Jest 28 and newer (in the node environment) among the supported runtimes, alongside Node.js 20 LTS+, Deno, Bun, and the major edge runtimes — so the SDK itself runs happily inside a Jest process. The question is when you actually want it to. As with Python testing, the healthy shape is a large, fast suite of unit tests that never touch the network, plus a thin layer of real integration tests run on a schedule. This article is about the first layer.
Design for replaceability: inject the client
The single most valuable pattern costs nothing: never construct the Claude client deep inside business logic. Build it once at your application's entry point and pass it into the functions or classes that need it (dependency injection). The real construction looks like the README's minimal example:
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({
apiKey: process.env['ANTHROPIC_API_KEY'],
});
await client.messages.create({ max_tokens: 1024, messages: [...], model: ... });
Once the client arrives as a parameter, tests don't need the real class at all. They pass an object with the same shape — something exposing messages.create — whose methods are Jest mock functions. Your unit tests then verify your logic: that the right model name, system prompt, and max_tokens were sent, and that your code handles whatever came back.
Mock functions and spies
Jest's jest.fn() creates a stand-in function that records every call it receives and returns whatever you tell it to. For async SDK methods, configure it to resolve with a hand-built response object shaped like a real API message — a content array containing a text block, a stop_reason, a usage object. Keep one small factory helper in your test utilities that builds these fake responses, so a future change to the response shape means updating one file, not fifty tests.
Assertions then come in two flavors. Behavioral: the function under test returned the parsed result you expected given the fake response. Interactional: Jest's call-inspection matchers (toHaveBeenCalledWith and friends) confirm the request your code composed. The second flavor is what catches the classic regression where a refactor silently drops the system prompt or changes the model string — a bug no type checker will find, because the request is still perfectly valid.
If you can't inject the client — say, legacy code constructs it inline — Jest's module mocking (jest.mock pointed at '@anthropic-ai/sdk') can replace the entire module with a fake constructor. It works, but it couples tests to import structure and is harder to type correctly; treat it as the fallback, not the default.
Async testing without flakes
Every SDK call is a Promise, so every test that exercises one should be an async test that awaits its subject — Jest fails a test whose returned promise rejects, which is exactly what you want. Two habits prevent the common flakes: never mix done-callbacks with promises, and when testing rejection paths, use Jest's rejection matchers rather than try/catch blocks that silently pass when nothing throws. For code with timeouts and retries, Jest's fake timers let you fast-forward through backoff delays instead of actually sleeping.
Vitest: same ideas, same shapes
Vitest, the test runner common in Vite-based projects, deliberately mirrors Jest's API — mock functions, module mocks, and matchers all have close equivalents (vi.fn(), vi.mock()). Everything above transfers: inject the client, fake the response objects, assert on both the output and the composed request. Teams migrating between the two runners generally only touch import lines in test utilities.
The integration layer
Keep a handful of tests that construct the real client and make one small, cheap call — gated behind an environment check so they skip when ANTHROPIC_API_KEY is absent. Per Anthropic's authentication docs, the SDKs pick that variable up from the environment, which makes CI wiring a matter of secret injection; see injecting Claude credentials into CI/CD. For everything deeper on the TypeScript client itself, the source of truth is the official repository.
Where to go next
Pair this with SDK mocking strategies and the Python counterpart, pytest patterns. New to the SDK entirely? Start at the TypeScript quickstart.