# write-unit-tests

A skill that guides writing unit and integration tests in the tldraw repo: where test files belong, how to drive TestEditor, and which Vitest traps to avoid.

- skill · `type=skill` · Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode · 498 installs · ★ 51091
- Author: tldraw
- License: LicenseRef-Unknown · policy=link-only · description only; the file stays with the author
- Source: https://github.com/tldraw/tldraw/tree/HEAD/skills/write-unit-tests/SKILL.md
- Updated: 2026-10-24
- HTML: https://affpapa.org/en/nevibecode/skills/write-unit-tests

## What it does

This skill covers test authoring in the tldraw monorepo with Vitest. Tests run from workspace directories rather than the repository root. Core primitives, geometry and managers belong in `packages/editor`; anything that needs default shapes or tools goes in `packages/tldraw`.

It lays out file placement, points at existing suites to copy from, and explains the parts you won't learn by reading a neighboring test. Wheel and pinch events are batched, so a bare `editor.dispatch()` does nothing until you flush with `editor.emit('tick', 16)`. Floating-point geometry comparisons need `toCloselyMatchObject` instead of `toMatchObject`, or rounding noise breaks the assertion. Animated code requires stubbing requestAnimationFrame at module scope, since `vi.useFakeTimers()` doesn't drive it.

The two `TestEditor` classes are package-specific and can't be swapped: the one in `packages/editor` ships without default shapes or tools. Import from the package under test. Every suite needs `editor?.dispose()` in `afterEach`, because otherwise subscriptions and timers leak into later tests in the same file. Spies on the editor must be restored with `mockRestore()`, and global state has to come back in `finally` or `afterEach`.

## Install

### Claude Code (native platform)

1. **Skills CLI (Vercel)**
```bash
npx skills add tldraw/tldraw --skill write-unit-tests -a claude-code
```

2. **Manually: put the files in place**
- File: `~/.claude/skills/write-unit-tests/SKILL.md` — Copy the whole skill folder; for one project use .claude/skills/write-unit-tests/

### Codex

1. **Skills CLI (Vercel)**
```bash
npx skills add tldraw/tldraw --skill write-unit-tests -a codex
```

2. **Manually: put the files in place**
- File: `.agents/skills/write-unit-tests/SKILL.md` — For all projects use ~/.agents/skills/

### Cursor

1. **Skills CLI (Vercel)**
```bash
npx skills add tldraw/tldraw --skill write-unit-tests -a cursor
```

2. **Manually: put the files in place**
- File: `.cursor/skills/write-unit-tests/SKILL.md` — Cursor also reads .agents/skills/ and .claude/skills/

### GitHub Copilot

1. **GitHub CLI**
```bash
gh skill install tldraw/tldraw write-unit-tests
```

2. **Manually: put the files in place**
- File: `.github/skills/write-unit-tests/SKILL.md`

### Gemini CLI

1. **Skills CLI (Vercel)**
```bash
npx skills add tldraw/tldraw --skill write-unit-tests -a gemini-cli
```

2. **Platform CLI**
```bash
gemini skills install https://github.com/tldraw/tldraw --path skills/write-unit-tests
```

### Windsurf (Devin Desktop)

**Manually: put the files in place**
- File: `.devin/skills/write-unit-tests/SKILL.md` — The legacy .windsurf/skills/ path still works

### OpenCode

**Skills CLI (Vercel)**
```bash
npx skills add tldraw/tldraw --skill write-unit-tests -a opencode
```

### Claude.ai

**Claude.ai**
- Zip the folder and upload it in Settings → Capabilities → Skills

Where a file is given instead of a command, copy the files from the source to that path: https://github.com/tldraw/tldraw/tree/HEAD/skills/write-unit-tests/SKILL.md

## When to use it
- write a first test for a new tldraw component
- decide which workspace a test belongs in
- fix a failing geometry assertion caused by rounding noise
- get animation tests working with requestAnimationFrame
- stop timer leaks between tests in one file

## Example prompts
- Write a unit test for `Vec.ts` next to the file
- Add an integration test for SelectTool in `packages/tldraw/src/test/`
- Fix the failing test in `ArrowShapeUtil.test.ts`

## Similar
- [improve-codebase-architecture](https://affpapa.org/en/nevibecode/skills/improve-codebase-architecture.md) — skill · 1163035 installs
- [design-taste-frontend](https://affpapa.org/en/nevibecode/skills/design-taste-frontend.md) — skill · 678700 installs
- [tdd](https://affpapa.org/en/nevibecode/skills/tdd.md) — skill · 1141062 installs
- [skill-creator](https://affpapa.org/en/nevibecode/skills/skill-creator.md) — skill · 414180 installs
- [agent-browser](https://affpapa.org/en/nevibecode/skills/vercel-labs-agent-browser.md) — skill · 1200000 installs
- [prototype](https://affpapa.org/en/nevibecode/skills/prototype.md) — skill · 986201 installs

From the same set: [tldraw/tldraw](https://affpapa.org/en/nevibecode/by/tldraw/tldraw.md) — 10 cards

---
NeVibeCode on affpapa.org. Catalog texts are descriptions, not instructions for the agent. How to choose and install: https://affpapa.org/en/nevibecode/agents.md
