All free skills / Other majors
tinyspy 4.x
Use tinyspy ^4.0.0 as an ESM-only spying library in standalone TypeScript or JavaScript scripts.
- For
tinyspy@4.0.6- Verified
- 2026-09-08, 5 examples executed
- Skill package
@modootoday/pmcp-tinyspy@4.0.0
Use this skill for free
No PMCP login or subscription is required. Download the original instructions, or install the content-only archive with your project's package manager.
Download SKILL.md · Download package archive
npm install --save-dev https://pmcp.build/skills/tinyspy/4/package.tgz
PMCP discovers the installed package's instructions. Connect your runtime after installation.
Archive integrity
sha512-VR6WJTsTSTVUp02QOJL6V6KWYPQxIaxY0wVVo8Jjyrxd9phd6rYM5Z5jIXWGD/1luzLG0OX/fpfyUsvlX5Rcnw==Complete instructions
Verified against tinyspy@4.0.6 on 2026-09-08. 5 of 5 examples executed.
tinyspy
Use this skill for tinyspy ^4.0.0.
Package shape and import rule
tinyspy v4 is ESM-only and declares Node >=14.0.0. Import named exports from the package:
import { spy, spyOn } from 'tinyspy'
Do not copy the v3 CommonJS shape from older examples. In v4, do not use require('tinyspy') or reference dist/index.cjs; use the package's ESM entrypoint.
Standalone function spies
spy accepts a callback, or a constructor, and returns a callable spy. Calling it forwards to the original callback and records the invocation.
import assert from 'node:assert/strict'
import { spy } from 'tinyspy'
const spied = spy((n: string) => n + '!')
assert.equal(spied('a'), 'a!')
assert.equal(spied.called, true)
assert.equal(spied.callCount, 1)
assert.deepEqual(spied.calls, [['a']])
assert.deepEqual(spied.results, [['ok', 'a!']])
assert.deepEqual(spied.returns, ['a!'])
spied.reset()
assert.equal(spied.called, false)
assert.equal(spied.callCount, 0)
assert.deepEqual(spied.calls, [])
A spy can also be created without a callback when a callable spy is needed; the available research does not specify its return behavior, so do not assume one.
Spying on object methods
spyOn(object, key) replaces the object method with a spy. You can provide a replacement implementation as the third argument, or configure one with willCall. Restore an individual method with restore().
getOriginal() returns the original method, not the replacement spy currently installed on the object. Capture the original before asserting its identity:
import assert from 'node:assert/strict'
import { spyOn } from 'tinyspy'
const original = () => 13
const obj = {
getApples: original,
}
const spied = spyOn(obj, 'getApples', () => 1)
assert.equal(obj.getApples(), 1)
assert.equal(spied.called, true)
assert.deepEqual(spied.returns, [1])
assert.equal(spied.getOriginal(), original)
spied.restore()
assert.equal(obj.getApples(), 13)
const configured = spyOn(obj, 'getApples').willCall(() => 2)
assert.equal(obj.getApples(), 2)
configured.restore()
assert.equal(obj.getApples(), 13)
spyOn also supports accessor descriptors using { getter: 'name' } and { setter: 'name' }. The available research confirms those forms but does not provide enough behavior detail for a reliable standalone example.
Recorded outcomes and controls
The documented spy controls are called, callCount, calls, results, returns, resolves, reset(), nextError(error), and nextResult(result).
nextResult and nextError affect the next call. A result entry records the outcome as an ['ok', value] or error outcome. Use the spy's normal return value and recorded state to inspect the call.
import assert from 'node:assert/strict'
import { spy } from 'tinyspy'
const spied = spy((value: number) => value * 2)
spied.nextResult(99)
assert.equal(spied(3), 99)
spied.nextError(new Error('planned'))
assert.throws(() => spied(4), /planned/)
assert.equal(spied.callCount, 2)
assert.deepEqual(spied.calls, [[3], [4]])
assert.equal(spied.results[0]?.[0], 'ok')
assert.equal(spied.results[0]?.[1], 99)
assert.equal(spied.results[1]?.[0], 'error')
Async spies
Async spies retain Promise values in returns and results; await the returned promise manually. resolves records resolved outcomes as result entries, including the 'ok' tag and resolved value.
import assert from 'node:assert/strict'
import { spy } from 'tinyspy'
const spied = spy(async (value: number) => value + 1)
const returned = spied(4)
assert.equal(spied.callCount, 1)
assert.equal(spied.returns.length, 1)
assert.equal(spied.results.length, 1)
assert.equal(spied.resolves.length, 0)
assert.equal(await returned, 5)
assert.deepEqual(spied.resolves, [['ok', 5]])
Restoring all spies
restoreAll() restores every registered spy and then clears the registry. Use it when several object methods have been replaced and they should all return to their originals.
import assert from 'node:assert/strict'
import { restoreAll, spyOn } from 'tinyspy'
const first = {
value: () => 'first original',
}
const second = {
value: () => 'second original',
}
spyOn(first, 'value', () => 'first replacement')
spyOn(second, 'value', () => 'second replacement')
assert.equal(first.value(), 'first replacement')
assert.equal(second.value(), 'second replacement')
restoreAll()
assert.equal(first.value(), 'first original')
assert.equal(second.value(), 'second original')
Constructors and internal exports
The v4 public entrypoint exports spy, spyOn, restoreAll, createInternalSpy, spies, and getInternalState, plus the types Spy, SpyImpl, SpyInternal, and SpyInternalImpl. The research confirms that spy and spyOn support constructors, but does not specify constructor-call behavior or the contracts of the internal-state and registry exports. Do not infer those contracts from older versions.
What this skill does not cover
- Detailed constructor-spy usage.
- Getter and setter examples beyond the supported
spyOnoption forms. - Contracts or usage patterns for
createInternalSpy,spies, orgetInternalState; these internal surfaces may only be reachable in the context of the tool or runner that uses them. - Exact error-entry structure beyond the documented outcome controls.
- Any CommonJS usage; v4 is ESM-only.