Writing tests for pota
SkillWeb & browsingWrite or extend pota's own tests, browser tests under tests/api/ and typecheck-only tests under tests/typescript/. Use when adding coverage for a component, reactive primitive, prop, store, or use/* module, when writing a regression test for a bug, or when improving existing test files. Covers file placement, the test-harness contract, timing rules, and how to run the suite.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Writing tests for pota skill
What this skill tells your AI
The instructions your AI receives, as published by potahtml/pota in .claude/skills/writing-tests/SKILL.md and read by ahel’s review.
Tests run in a real Chromium browser via the custom Puppeteer runner
(architecture and the full #test helper contract:
tools/test-runner/readme.md). Conventions, timing rules, and the
coverage inventory live in tests/readme.md. This skill is the
procedure for adding coverage.
Procedure
- Read the source first. Find the unit's real signature and
behavior in
src/— never test from memory of a similar API. - Place the file mirroring
src/:tests/api/components/for built-in components,reactivity/for primitives,dom/for renderer/props/events,store/,use/(one file perpota/use/*module),forms/for native form behavior,jsx/for transform and tracking semantics. Type-level assertions go intests/typescript/*.tsxinstead (typecheck-only,npm run test:ts-tests). - Write the tests (anatomy below), one file at a time. Cover the behaviors the source actually shows, including edge cases.
- Run filtered, then full:
npm run test:api -- <path-substring>, thennpm run test:api. - Update the inventory — the matching table row in
tests/readme.md. - If a test you wrote fails, don't delete, weaken, or rewrite it
to pass. Surface the failing assertion, the observed behavior, and
a hypothesis — it may be a real library bug (see Workflow in
documentation/AGENTS.md). To demonstrate an alternative expectation, add a new test alongside the existing one.
Anatomy
/** @jsxImportSource pota */
// Tests for the Show component: static truthy/falsy, signal
// toggling, fallback.
import { test, body, microtask } from '#test'
import { render, signal } from 'pota'
import { Show } from 'pota/components'
await test('Show - renders children when `when` is true', expect => {
const dispose = render(
<Show when={true}>
<p>hello</p>
</Show>,
)
expect(body()).toBe('<p>hello</p>')
dispose()
})
await test('Show - signal: toggles from true to false', expect => {
const visible = signal(true)
const dispose = render(
<Show
when={visible.read}
fallback={<p>fallback</p>}
>
<p>hello</p>
</Show>,
)
expect(body()).toBe('<p>hello</p>')
visible.write(false)
expect(body()).toBe('<p>fallback</p>')
dispose()
})
- Files start with the
@jsxImportSource potapragma and a 1–3 line comment saying what the file covers. - Tests are top-level
await test(title, fn)calls, run sequentially in file order; the harness reports automatically — norun()call, no registration step, no build step before running. fnreceivesexpect(toBe,toEqual,not.*). Prefer exact output assertions (expect(body()).toBe('…')) when browser serialization is stable.- Call the
disposereturned byrenderat the end of the test. The harness asserts a clean document around every test, so a leaked node fails the next test — this doubles as a disposal-leak check. - No
try/catcharound assertions, no helper mini-frameworks — inline the setup.
Timing
Signal writes update the DOM synchronously — assert right after
the write, no await needed (see the toggle test above). When an
await is needed, prefer microtask() over macrotask() over
sleep(ms) — the ladder and the cases each covers are in
tests/readme.md (Timing Considerations). The two common cases:
promise/async content needs await microtask() after the promise
settles; a use:* plugin registered with the default
onMicrotask=true needs await microtask() after render().
Running
npm run test:api -- <substring> filters by path; --bail stops on
the first failure; npm run watch:test re-runs on change;
npm run coverage adds a c8 report under generated/coverage/. The
full pre-release gate is npm test (types + browser + babel-preset).
Signals
- GitHub stars
- 66
- Forks
- 2
- Last commit
- Jul 2026
Advanced
- Catalog kind
- skill
- Gateway key
writing-tests-potahtml- Source
- github.com/potahtml/pota