> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.band.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.band.ai/_mcp/server.

# Test a TypeScript Adapter

Test a TypeScript adapter locally before connecting it to Band. This guide uses `@band-ai/sdk` 1.0.0.

## Set Up the Test Project

Use Node.js 22.12 or later on the 22.x line, 24.x, or 26 and later, matching Vitest 5's supported runtimes. From a new project directory:

```bash
npm init -y && npm pkg set type=module
npm install @band-ai/sdk@1.0.0
npm install -D vitest@5.0.5 typescript@7.0.2
```

## Record Tool Calls

`@band-ai/sdk/testing` exports `FakeAgentTools` for `@band-ai/sdk` 1.0.0. It has no assertion helpers, so use your test runner's matchers on what it records:

| Property                                   | Records                                                                                                                |
| :----------------------------------------- | :--------------------------------------------------------------------------------------------------------------------- |
| `messagesSent`                             | `{ content, mentions }` for each `sendMessage()` and `sendNotice()` call                                               |
| `eventsSent`                               | `{ content, messageType, metadata }` for each `sendEvent()` call, including the `error` event a reported failure posts |
| `toolCalls`                                | `{ toolName, arguments }` for each `executeToolCall()` call, which returns `{ status: "ok" }` without running the tool |
| `participantsAdded`, `participantsRemoved` | Participant changes                                                                                                    |
| `turn`                                     | The record the SDK uses to judge whether the turn replied                                                              |

Unlike Band, `sendMessage()` accepts a call without mentions, so assert the mentions too. `getToolSchemas()` returns an empty list, and the contact and memory methods return empty results. `new FakeAgentTools({ failOn: ["sendMessage"] })` makes the named methods throw, and `reset()` clears every record.

Call `onEvent()` rather than `onMessage()` to include the SDK's turn judgment. This [Vitest](https://vitest.dev) test checks both a reply and a turn that ends without one:

**`tests/adapter.test.ts`**

```typescript title="tests/adapter.test.ts"
import { expect, it } from "vitest";
import { GenericAdapter, type PlatformMessage } from "@band-ai/sdk";
import { HistoryProvider } from "@band-ai/sdk/runtime";
import { FakeAgentTools } from "@band-ai/sdk/testing";

const message: PlatformMessage = {
  id: "msg-1",
  roomId: "room-1",
  content: "What is the weather in Lisbon?",
  senderId: "user-1",
  senderType: "User",
  senderName: "Alice",
  messageType: "text",
  metadata: {},
  createdAt: new Date(),
};

function input(tools: FakeAgentTools) {
  return {
    message,
    tools,
    history: new HistoryProvider([]),
    participantsMessage: null,
    contactsMessage: null,
    isSessionBootstrap: true,
    roomId: "room-1",
  };
}

it("replies to the sender", async () => {
  const adapter = new GenericAdapter(async ({ message, tools }) => {
    await tools.sendMessage("Sunny, 22 C", [{ id: message.senderId }]);
  });
  const tools = new FakeAgentTools();

  await adapter.onEvent(input(tools));

  expect(tools.messagesSent).toEqual([{ content: "Sunny, 22 C", mentions: [{ id: "user-1" }] }]);
});

it("fails a turn that ends without a reply", async () => {
  const adapter = new GenericAdapter(async () => {});
  const tools = new FakeAgentTools();

  await expect(adapter.onEvent(input(tools))).rejects.toThrow("ended its turn without replying");
  expect(tools.eventsSent[0]?.messageType).toBe("error");
});
```

Import `HistoryProvider` from `@band-ai/sdk/runtime`: the root entry exports it as a type only. For an integration test, start a dedicated test agent with `agent.withLifecycle(async () => { ... })`, check `agent.state.status` is `"running"` inside it, and `"stopped"` after it.

[TypeScript reference](/reference/sdk/typescript).

## REST Test Helper

`@band-ai/sdk/testing` also exports `StubRestApi`, a REST client that returns fixed responses.