> ## Documentation Index
> Fetch the complete documentation index at: https://narrator.ami.rip/llms.txt
> Use this file to discover all available pages before exploring further.

# @usenarrator/testkit

> Helpers for testing plugins and locales.

```ts theme={null}
import { narrate, narrateWithStats, phrasebookGaps } from "@usenarrator/testkit";
```

The testkit wires up the TypeScript language with the native parser and the English locale, so a test only has to say which plugins it needs.

## narrate

```ts theme={null}
function narrate(code: string, options?: SnippetOptions): string;

type SnippetOptions = { plugins?: (TsPlugin | TsPlugin[])[]; locale?: Locale; path?: string };
```

Narrates a snippet and returns plain text. `path` defaults to `snippet.ts`. Set it to a `.tsx` name when the snippet contains JSX, or to a path such as `app/blog/[slug]/page.tsx` when a plugin reads meaning from it.

If a plugin rule throws, `narrate` throws too, with the plugin and rule in the message, even though a real narrator would carry on with a plain reading. That way a bug in a rule fails its test instead of hiding behind a fallback. Syntax errors don't throw, so snippets may use a top-level `return`.

The testkit doesn't load dependency manifests, so a plugin that checks `e.usesLibrary` only applies when the snippet imports its library. Start test snippets with the import, as real files do.

```ts theme={null}
const fee = new Decimal(amount).times(rate).toDecimalPlaces(2);
```

```text narrate(code, { plugins: [decimal()] }) theme={null}
Let fee be amount times rate rounded to 2 decimal places.
```

## narrateWithStats

```ts theme={null}
function narrateWithStats(code: string, options?: SnippetOptions): { text: string; fallbacks: number };
```

Like `narrate`, and also returns how many nodes fell back to raw code. Assert it is `0` to make sure your snippet is fully covered.

## phrasebookGaps

```ts theme={null}
function phrasebookGaps(reference: object, translation: object): { missing: string[]; extra: string[] };
```

Compares the key paths of two phrasebooks. Use the English phrasebook as the reference. `missing` lists phrases the translation doesn't have yet, and `extra` lists keys that don't exist in the reference, which usually means a typo.

```ts theme={null}
const gaps = phrasebookGaps(decimalEn, { plus: () => "", compare: { atMost: () => "" } });
// gaps.missing includes "minus", "compare.moreThan", "isZero" and more
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.