Test a mod changedplugins/mods/test
Nearest release: v2.1.295, published 4 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Upstream edited this page at 8 Oct 2026 22:59 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 8 Oct 2026 23:07 UTC.
Upstream edited
Recorded here
Lines+7added
Lines−2removed
From line
102
where the diff opens
First seen
1 Oct 2026
this site's first read of the page
Recorded edits4to this page, all time
The whole hunk
from line 102, old and new numbered
/
from line 102
102102* `returned neither { value } nor { deny }`: a stub for a mods API call returned a bare value, which fails the test
103103* `no implementation for` followed by a name: your mod made that call and no stub answers it
104104
105The kit also exports in-memory mocks that answer a whole namespace for you. `mock.clock(on)` answers [`$.clock`](/docs/en/plugins/mods/api#run-work-in-the-background), `mock.store(on, { count: 7 })` answers `$.store` from a store that starts with those entries, and `mock.env(on, { CI: 'true' })` answers `$.env.get` from those variables. `mock.clock` returns a mock clock that your test advances, so a test of a timer doesn't wait. `mock.store` returns nothing, so to check what your mod saved, write the two `store` stubs yourself as the [drawing test](#test-a-drawing) does.
105The kit also exports ready-made mocks for the clock, the store, environment variables, and rows appended to the conversation:
106106
107* **`mock.clock(on)`**: answers [`$.clock`](/docs/en/plugins/mods/api#run-work-in-the-background) and returns a mock clock that your test advances, so a test of a timer doesn't wait.
108* **`mock.store(on, { count: 7 })`**: answers `$.store` from a store that starts with those entries. It returns nothing, so to check what your mod saved, write the two `store` stubs yourself as the [drawing test](#test-a-drawing) does.
109* **`mock.env(on, { CI: 'true' })`**: answers `$.env.get` from those variables.
110* **`mock.session(on)`**: returns a mock session whose `appended()` method lists the rows your mod added with [`$.session.append`](/docs/en/plugins/mods/reference#session), oldest first; it requires Claude Code v2.1.293 or later.
111
107112### Follow the test kit's rules
108113
109114The test kit has a few rules of its own, and breaking one produces the errors new test authors hit first:
from line 161
156161
157162### Look up what a stub returns
158163
159Every mods API call your mod makes in a test needs a stub that answers in Claude Code's place, except the few the kit answers itself: [`$.ui.invalidate`](/docs/en/plugins/mods/interface#redraw-when-something-changes) and [`$.state`](/docs/en/plugins/mods/interface#keep-state) calls. For `$.clock` calls, use `mock.clock(on)`, or your mod's `$.clock.now()` fails with `no implementation for clock.now`.
164Every mods API call your mod makes in a test needs a stub that answers in Claude Code's place, except the few the kit answers itself: [`$.ui.invalidate`](/docs/en/plugins/mods/interface#redraw-when-something-changes), [`$.state`](/docs/en/plugins/mods/interface#keep-state), and `$.session.append` calls. For `$.clock` calls, use `mock.clock(on)`, or your mod's `$.clock.now()` fails with `no implementation for clock.now`.
160165
161166This table lists the ones mods use most. The first column is the call your mod makes or the event it passes on with `next(e)`. The second is the function to pass to `on` under that name, so the `$.store.get` row becomes `on('store.get', ($, e) => ({ value: saved.get(e.key) }))`. A `'...'` in a stub marks text for you to fill in:
162167
No line in this hunk matches that.