| name | sinon |
| description | Use when the user asks about Sinon stubbing, spying, mocking, or test double APIs for unit tests. Triggers on questions like "how do I stub this", "Sinon fake timers", "spy vs stub", "sandbox usage", "assert.calledWith", "stub.resolves", "sinon.match", or test double patterns. |
| allowed-tools | ["Read","Bash","WebFetch","WebSearch"] |
Sinon.JS Documentation Lookup
This skill helps look up Sinon.JS APIs, patterns, and best practices for creating test doubles in
unit tests.
Sources
Sinon.JS Documentation (v18)
The official docs organized by feature at https://sinonjs.org/releases/v18/:
| Section | URL | Use For |
|---|
| Overview | https://sinonjs.org/releases/v18/ | General concepts, what's new |
| Spies | https://sinonjs.org/releases/v18/spies/ | Observing function calls without changing them |
| Stubs | https://sinonjs.org/releases/v18/stubs/ | Replacing functions with controlled behavior |
| Mocks | https://sinonjs.org/releases/v18/mocks/ | Pre-programmed expectations (use sparingly) |
| Fakes | https://sinonjs.org/releases/v18/fakes/ | Immutable spies with optional behavior |
| Sandbox | https://sinonjs.org/releases/v18/sandbox/ | Automatic cleanup of stubs/spies/mocks |
| Fake Timers | https://sinonjs.org/releases/v18/fake-timers/ | Controlling setTimeout, setInterval, Date |
| Fake XHR | https://sinonjs.org/releases/v18/fake-xhr-and-server/ | Faking HTTP requests |
| Assertions | https://sinonjs.org/releases/v18/assertions/ | Sinon-specific assertion helpers |
| Matchers | https://sinonjs.org/releases/v18/matchers/ | Argument matching for assertions |
Process
1. Understand the Question Context
Determine whether the user needs:
- API reference: Exact method signatures, options, return values
- Pattern guidance: How to set up stubs, organize sandboxes, verify calls
- Troubleshooting: Why a stub isn't working, common pitfalls
- Best practices: Project-specific conventions for test doubles
2. Check Project Conventions First
Before fetching external docs, review the project's stubbing conventions from CLAUDE.md:
- Always use a sandbox: create via
sinon.createSandbox(), restore in afterEach. The project
uses sandboxes in virtually all test files — never use bare sinon.stub() or sinon.spy()
- Design for stubbing: avoid calling same-module functions you need to stub — Sinon can only stub
module exports, not internal calls within the same file
- Extract dependencies to separate modules or pass them as parameters
- Common stubs go in the top-level
describe block's beforeEach
- The project uses Node.js
assert (not Chai) alongside Sinon
3. Fetch Documentation
Sinon docs are organized by feature — fetch the specific section page:
WebFetch: https://sinonjs.org/releases/v18/stubs/
Prompt: "Find the API documentation for [specific method like stub.resolves, stub.callsFake, etc.]"
For general best practices or newer features, supplement with web search:
WebSearch: "sinon.js stub resolves rejects async example"
WebSearch: "sinon sandbox restore best practices"
4. Look at Existing Test Examples
When the user needs pattern guidance, look at how the project uses Sinon:
grep -r "sinon.stub" --include="*.test.ts" -l src/ | head -5
grep -r "createSandbox\|sinon.sandbox" --include="*.test.ts" -l src/ | head -5
grep -r "stub\.resolves\|stub\.returns\|stub\.callsFake" --include="*.test.ts" -l src/ | head -5
Read 1-2 relevant test files to show project-specific patterns alongside official docs.
5. Search for Specific APIs
When the user asks about a specific API (e.g., stub.resolves(), sandbox.create()):
- Fetch the relevant Sinon section page (stubs, sandbox, etc.)
- Search for the specific method or property
- Extract the API signature with description and examples
- Cross-reference with project usage if applicable
Output Format
API Reference
## Sinon: [method/feature]
### API
[Method signature and description from docs]
### Example
[Code example from docs or adapted to project patterns]
### Project Usage
[How this is typically used in the project, with file references if found]
Pattern Guidance
## Pattern: [description]
### From the Docs
[Official recommended approach]
### In This Project
[How the project implements this pattern, with examples from existing tests]
### Key Points
- [Important considerations]
- [Common pitfalls to avoid]
Common Lookup Patterns
Sandbox (project default)
Always create stubs and spies through a sandbox for automatic cleanup:
- Create:
const sandbox = sinon.createSandbox()
- Stubs:
sandbox.stub(obj, 'method'), sandbox.stub() (anonymous)
- Spies:
sandbox.spy(obj, 'method'), sandbox.spy() (anonymous)
- Cleanup:
sandbox.restore() in afterEach (restores all fakes created through the sandbox)
Stubs
- Behavior:
stub.returns(val), stub.resolves(val), stub.rejects(err),
stub.callsFake(fn), stub.throws(err)
- Conditional:
stub.withArgs(arg).returns(val), stub.onFirstCall().returns(val)
- Reset:
stub.reset(), stub.resetBehavior(), stub.resetHistory()
Spies
- Inspect:
spy.calledOnce, spy.calledWith(arg), spy.returnValues, spy.args
- Count:
spy.callCount, spy.firstCall, spy.secondCall, spy.lastCall
Assertions
sinon.assert.calledOnce(spy)
sinon.assert.calledWith(spy, arg1, arg2)
sinon.assert.calledOnceWithExactly(spy, arg1)
sinon.assert.notCalled(spy)
sinon.assert.callOrder(spy1, spy2)
Fake Timers
- Create:
sandbox.useFakeTimers(), sandbox.useFakeTimers({ now: timestamp })
- Control:
clock.tick(ms), clock.tickAsync(ms), clock.next(), clock.runAll()
- Cleanup: handled by
sandbox.restore()
Matchers
- Type:
sinon.match.string, sinon.match.number, sinon.match.func, sinon.match.object
- Partial:
sinon.match({ key: value }), sinon.match.has('key', value)
- Custom:
sinon.match(predicate), sinon.match.any
Tips
- Always use sandbox — the project convention is
sinon.createSandbox() with
sandbox.restore() in afterEach. Never suggest bare sinon.stub() or sinon.spy() — always
use sandbox.stub() and sandbox.spy() instead
- Sinon docs are organized by feature — fetch the specific section page rather than the overview for
API details
- When the user asks "how do I stub X", first check whether the function is an export from another
module (stubbable) vs. an internal call within the same file (needs restructuring) — this is a key
project convention
- The project uses Node.js
assert (not Chai) — adapt any Chai-based examples from docs to use
assert.strictEqual, assert.deepStrictEqual, assert.ok, etc.
stub.resolves() / stub.rejects() are the async-friendly counterparts to stub.returns() /
stub.throws() — use these for Promise-based code
- When stubbing VS Code APIs (like
vscode.window.showErrorMessage), the stub target must be the
vscode module's export, not a local reference