@forwardimpact/libmock 0.1.15 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -75,7 +75,7 @@ for narrower imports.
75
75
 
76
76
  Canonical fakes for the `runtime` collaborator surfaces. Every test that needs
77
77
  a fake imports it from here so production and test wire the same shape.
78
- `createTestRuntime` assembles them into a frozen bag mirroring libutil's
78
+ `createTestRuntime` assembles them into a frozen bag that mirrors libutil's
79
79
  `createDefaultRuntime`.
80
80
 
81
81
  | Surface | Production shape | Factory | Example |
@@ -92,16 +92,17 @@ a fake imports it from here so production and test wire the same shape.
92
92
  | grpc health def | stripped `{ Check: { path, … } }` shape | `createMockGrpcHealthDefinition` | `const def = createMockGrpcHealthDefinition();` |
93
93
  | repl env | readline/process/os/formatter/storage bundle | `createReplEnvironment` | `const { readline, process } = createReplEnvironment();` |
94
94
 
95
- `test/runtime-completeness.test.js` asserts every field on libutil's `Runtime`
96
- typedef has a matching fake here, so the fakes can't drift behind the bag.
95
+ `test/runtime-completeness.test.js` asserts that every field on libutil's
96
+ `Runtime` typedef has a matching fake here. So the fakes cannot drift behind
97
+ the bag.
97
98
 
98
99
  ## When to extend libmock
99
100
 
100
- Before adding a helper locally in a test file, check `src/index.js`. If the
101
- helper doesn't exist and would be reused across two or more files, add it to
102
- libmock in the same PR instead of inlining. See
101
+ Check `src/index.js` before you add a helper locally in a test file. If the
102
+ helper does not exist, and two or more files would use it, add it to libmock
103
+ in the same PR. Do not inline it. See
103
104
  [CONTRIBUTING.md](../../CONTRIBUTING.md) READ-DO and DO-CONFIRM checklists for
104
- the enforced policy and `.coaligned/invariants/libmock.rules.mjs` for the
105
+ the enforced policy. See `.jidoka/invariants/libmock.rules.mjs` for the
105
106
  pre-commit guard that flags inline reimplementations.
106
107
 
107
108
  ## `spy` vs `node:test`'s `mock.fn`
@@ -118,5 +119,5 @@ fn.mock.resetCalls();
118
119
  fn.mock.mockImplementation((x) => x + 1);
119
120
  ```
120
121
 
121
- Prefer `spy` over `node:test`'s `mock.fn` — `spy` works under both `bun test`
122
+ Prefer `spy` over `node:test`'s `mock.fn`. `spy` works under both `bun test`
122
123
  (the default runner) and `node --test`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forwardimpact/libmock",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Shared mocks and test fixtures so every library and service tests the same way.",
5
5
  "keywords": [
6
6
  "test",
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Dependency-free, runner-independent `expect()` shim. Replaces `expect` from
3
- * `bun:test` so the test suite can run under `node --test` (which ships no
4
- * `expect`) as well as `bun test`. Mirrors how `spy()` replaced `mock.fn`.
3
+ * `bun:test` so the test suite can run under `node --test` and under
4
+ * `bun test`. `node --test` ships no `expect`. Mirrors how `spy()` replaced
5
+ * `mock.fn`.
5
6
  *
6
7
  * Covers exactly the matcher surface the converged test files use: `toBe`,
7
8
  * `toEqual`, `toMatchObject`, `toBeNull`, `toBeUndefined`, `toBeDefined`,
@@ -16,9 +17,9 @@ import { AssertionError } from "node:assert";
16
17
  import { isDeepStrictEqual } from "node:util";
17
18
 
18
19
  /**
19
- * Render a value for assertion messages without throwing on circular refs.
20
+ * Render a value for assertion messages. It does not throw on circular refs.
20
21
  * @param {unknown} value - Value to stringify.
21
- * @returns {string} Human-readable rendering.
22
+ * @returns {string} Human-readable text.
22
23
  */
23
24
  function show(value) {
24
25
  if (typeof value === "string") {
@@ -41,12 +42,13 @@ function show(value) {
41
42
  }
42
43
 
43
44
  /**
44
- * Throw or, when negated, swallow — the single choke point that makes `.not`
45
- * invert every matcher. `pass` is the un-negated truth of the assertion.
45
+ * Throw, or swallow when negated. This function is the single choke point
46
+ * that makes `.not` invert every matcher. `pass` is the un-negated truth of
47
+ * the assertion.
46
48
  * @param {boolean} pass - Whether the positive assertion holds.
47
49
  * @param {boolean} negated - Whether `.not` is active.
48
- * @param {string} message - Message for the failing (positive) direction.
49
- * @param {string} [negatedMessage] - Message for the failing negated direction.
50
+ * @param {string} message - Message for a failed positive assertion.
51
+ * @param {string} [negatedMessage] - Message for a failed negated assertion.
50
52
  */
51
53
  function settle(pass, negated, message, negatedMessage) {
52
54
  if (negated) {
@@ -65,7 +67,8 @@ function settle(pass, negated, message, negatedMessage) {
65
67
  const ASYMMETRIC = Symbol.for("libmock.expect.asymmetric");
66
68
 
67
69
  /**
68
- * Whether `value` is an asymmetric matcher produced by `expect.any` / friends.
70
+ * Whether `value` is an asymmetric matcher from `expect.any` or a sibling
71
+ * helper.
69
72
  * @param {unknown} value - Candidate.
70
73
  * @returns {boolean} True when `value` carries the asymmetric marker.
71
74
  */
@@ -98,7 +101,8 @@ function equals(actual, expected) {
98
101
  }
99
102
  return expected.every((e, i) => equals(actual[i], e));
100
103
  }
101
- // No asymmetric matcher anywhere → exact deep equality is correct and cheap.
104
+ // No asymmetric matcher anywhere, so exact deep equality is correct and
105
+ // cheap.
102
106
  if (!containsAsymmetric(expected)) {
103
107
  return isDeepStrictEqual(actual, expected);
104
108
  }
@@ -128,8 +132,9 @@ function containsAsymmetric(value) {
128
132
  }
129
133
 
130
134
  /**
131
- * Deep subset match: every own enumerable key of `subset` matches the same key
132
- * in `actual` (recursively for plain objects, asymmetric-aware).
135
+ * Deep subset match. Every own enumerable key of `subset` matches the same
136
+ * key in `actual`. The match recurses into plain objects. The match also
137
+ * understands asymmetric matchers.
133
138
  * @param {unknown} actual - Candidate object.
134
139
  * @param {unknown} subset - Expected subset.
135
140
  * @returns {boolean} Whether `actual` contains `subset`.
@@ -164,7 +169,7 @@ function matchesObject(actual, subset) {
164
169
  }
165
170
 
166
171
  /**
167
- * Run a possibly-throwing function and apply the `toThrow` predicate.
172
+ * Run a function that may throw. Then apply the `toThrow` predicate.
168
173
  * @param {() => unknown} fn - The thunk under test.
169
174
  * @param {unknown} matcher - undefined, a string (substring), or a RegExp.
170
175
  * @param {boolean} negated - Whether `.not` is active.
@@ -343,8 +348,9 @@ function matchers(actual, negated) {
343
348
  }
344
349
 
345
350
  /**
346
- * Build the async matcher object for a promise-producing actual. Each matcher
347
- * awaits the promise and applies the underlying matcher to the settled value.
351
+ * Build the async matcher object for an actual value that produces a promise.
352
+ * Each matcher awaits the promise. Then it applies the underlying matcher to
353
+ * the settled value.
348
354
  * @param {unknown} actual - A promise (or thenable) under test.
349
355
  * @param {boolean} negated - Whether `.not` is active.
350
356
  * @param {"resolves" | "rejects"} mode - Which settlement to assert on.
@@ -381,8 +387,9 @@ function asyncMatchers(actual, negated, mode) {
381
387
  (name) =>
382
388
  (...args) => {
383
389
  if (name === "toThrow") {
384
- // `rejects.toThrow(x)` asserts the rejection's message; the settled value
385
- // here is the rejection itself, so wrap it back into a throwing thunk.
390
+ // `rejects.toThrow(x)` asserts the rejection's message. The settled
391
+ // value here is the rejection itself. So wrap it back into a thunk
392
+ // that throws.
386
393
  return wrap((settled) => {
387
394
  const thunk = () => {
388
395
  throw settled;
@@ -438,8 +445,9 @@ export function expect(actual) {
438
445
  }
439
446
 
440
447
  /**
441
- * Asymmetric matcher: matches any value constructed by / typed as `ctor`,
442
- * for use inside `toEqual` / `toMatchObject`. Mirrors Jest/bun `expect.any`.
448
+ * An asymmetric matcher. It matches any value that `ctor` constructed, or any
449
+ * value typed as `ctor`. Use it inside `toEqual` and `toMatchObject`. Mirrors
450
+ * Jest/bun `expect.any`.
443
451
  * @param {Function} ctor - A constructor or primitive wrapper (String, Number…).
444
452
  * @returns {object} An asymmetric matcher.
445
453
  */
@@ -467,7 +475,7 @@ expect.any = (ctor) => ({
467
475
  });
468
476
 
469
477
  /**
470
- * Asymmetric matcher: matches any non-null, non-undefined value.
478
+ * An asymmetric matcher. It matches any non-null, non-undefined value.
471
479
  * @returns {object} An asymmetric matcher.
472
480
  */
473
481
  expect.anything = () => ({
@@ -1,7 +1,7 @@
1
1
  import assert from "node:assert";
2
2
 
3
3
  /**
4
- * Asserts that a function throws with a matching message
4
+ * Asserts that a function throws with a message that matches the pattern
5
5
  * @param {Function} fn - Function to test
6
6
  * @param {RegExp|string} pattern - Pattern to match
7
7
  * @param {string} message - Assertion message
@@ -15,7 +15,8 @@ export function assertThrowsMessage(fn, pattern, message) {
15
15
  }
16
16
 
17
17
  /**
18
- * Asserts that an async function rejects with a matching message
18
+ * Asserts that an async function rejects with a message that matches the
19
+ * pattern
19
20
  * @param {Function} fn - Async function to test
20
21
  * @param {RegExp|string} pattern - Pattern to match
21
22
  * @param {string} message - Assertion message
@@ -29,7 +30,7 @@ export async function assertRejectsMessage(fn, pattern, message) {
29
30
  }
30
31
 
31
32
  /**
32
- * Creates a deferred promise for async testing
33
+ * Creates a deferred promise for async tests
33
34
  * @returns {object} Object with promise, resolve, and reject
34
35
  */
35
36
  export function createDeferred() {
@@ -1,19 +1,19 @@
1
1
  /**
2
- * Cross-file fixture caching helpers. The test runner currently executes one
3
- * test file per process, but fixtures loaded inside a file (e.g. starter
4
- * standard YAML via `createDataLoader(runtime).loadAllData(dir)`) are re-parsed for
5
- * every `test(...)` case unless hoisted.
2
+ * Helpers that cache fixtures across files. The test runner currently executes
3
+ * one test file per process. But each `test(...)` case re-parses the fixtures
4
+ * that a file loads inline, unless you hoist them. One example is the starter
5
+ * standard YAML from `createDataLoader(runtime).loadAllData(dir)`.
6
6
  */
7
7
 
8
8
  const caches = new WeakMap();
9
9
  const stringCaches = new Map();
10
10
 
11
11
  /**
12
- * Wraps an async factory so it is invoked at most once per unique key.
12
+ * Wraps an async factory. Calls the factory at most once per unique key.
13
13
  *
14
14
  * @template T
15
- * @param {string} key - Cache key. Using the same key returns the cached value.
16
- * @param {() => Promise<T>} factory - Factory invoked on miss.
15
+ * @param {string} key - Cache key. The same key returns the cached value.
16
+ * @param {() => Promise<T>} factory - Factory to call on a cache miss.
17
17
  * @returns {Promise<T>}
18
18
  */
19
19
  export async function memoizeAsync(key, factory) {
@@ -29,8 +29,8 @@ export async function memoizeAsync(key, factory) {
29
29
  }
30
30
 
31
31
  /**
32
- * Caches the result of `fn(subject)` keyed by identity of `subject`. Useful
33
- * for expensive derivations over a frozen input object.
32
+ * Caches the result of `fn(subject)`. The identity of `subject` is the key.
33
+ * Use it for expensive derivations over a frozen input object.
34
34
  *
35
35
  * @template S, T
36
36
  * @param {S} subject
@@ -43,7 +43,7 @@ export function memoizeOnSubject(subject, fn) {
43
43
  }
44
44
 
45
45
  /**
46
- * Clears all memoization caches. Only useful in self-tests of this helper.
46
+ * Clears all memoization caches. Use it only in self-tests of this helper.
47
47
  */
48
48
  export function __resetMemoCaches() {
49
49
  stringCaches.clear();
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  /**
10
- * Builds a tool-use message envelope as emitted by the agent SDK.
10
+ * Builds a tool-use message envelope in the shape the agent SDK emits.
11
11
  * Replaces per-file concludeMsg / redirectMsg / tellMsg / shareMsg helpers.
12
12
  *
13
13
  * @param {string} name - Tool name, e.g. "Conclude", "Redirect", "Tell", "Share".
@@ -33,7 +33,8 @@ export function createToolUseMsg(name, input, { id } = {}) {
33
33
  }
34
34
 
35
35
  /**
36
- * Builds an assistant text message envelope as emitted by the agent SDK.
36
+ * Builds an envelope for an assistant text message, in the shape the agent
37
+ * SDK emits.
37
38
  * @param {string} text - Text content.
38
39
  * @returns {object} Assistant message with a single text content block.
39
40
  */
@@ -76,7 +77,8 @@ export function stripAnsi(s) {
76
77
  }
77
78
 
78
79
  /**
79
- * Writes each line followed by a newline to the writer, then ends it.
80
+ * Writes each line to the writer with a newline after it. Then ends the
81
+ * writer.
80
82
  * @param {import("node:stream").Writable} writer
81
83
  * @param {string[]} lines
82
84
  * @returns {Promise<void>}
@@ -120,15 +122,15 @@ export function createTestTrace(overrides = {}) {
120
122
  }
121
123
 
122
124
  /**
123
- * Creates an async-generator agent query stub. The shape of `messages`
125
+ * Creates an async-generator stub for an agent query. The shape of `messages`
124
126
  * determines per-call behaviour:
125
- * - Flat array of message objects: yielded on every invocation.
126
- * - Array of arrays (batches): the Nth invocation yields messages from the
127
- * Nth batch. Subsequent calls past the last batch repeat the last one.
127
+ * - Flat array of message objects: the stub yields them on every call.
128
+ * - Array of arrays (batches): the Nth call yields messages from the Nth
129
+ * batch. Later calls past the last batch repeat the last batch.
128
130
  *
129
131
  * @param {object[] | object[][]} messages
130
- * @param {(params: object) => void} [onParams] - Invoked with call params.
131
- * @returns {Function} Async generator mimicking `query({...})`.
132
+ * @param {(params: object) => void} [onParams] - Receives the call params.
133
+ * @returns {Function} Async generator that mimics `query({...})`.
132
134
  */
133
135
  export function createMockAgentQuery(messages, onParams) {
134
136
  const isBatched = Array.isArray(messages[0]);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Pathway test fixtures for creating realistic test data
2
+ * Pathway test fixtures that create realistic test data
3
3
  * Provides mock disciplines, levels, tracks, skills, and behaviours
4
4
  */
5
5
 
@@ -27,7 +27,7 @@ export function createTestLevel(overrides = {}) {
27
27
  }
28
28
 
29
29
  /**
30
- * Creates a set of mock levels spanning junior to senior
30
+ * Creates a set of mock levels from junior to senior
31
31
  * @returns {object[]} Array of mock levels
32
32
  */
33
33
  export function createTestLevels() {
@@ -260,9 +260,9 @@ export function createTestDriver(overrides = {}) {
260
260
  }
261
261
 
262
262
  /**
263
- * Creates a mock skill matrix entry
263
+ * Creates a mock skill-matrix entry
264
264
  * @param {object} overrides - Properties to override
265
- * @returns {object} Mock skill matrix entry
265
+ * @returns {object} Mock skill-matrix entry
266
266
  */
267
267
  export function createTestSkillEntry(overrides = {}) {
268
268
  return {
@@ -278,9 +278,9 @@ export function createTestSkillEntry(overrides = {}) {
278
278
  }
279
279
 
280
280
  /**
281
- * Creates a mock behaviour profile entry
281
+ * Creates a mock behaviour-profile entry
282
282
  * @param {object} overrides - Properties to override
283
- * @returns {object} Mock behaviour profile entry
283
+ * @returns {object} Mock behaviour-profile entry
284
284
  */
285
285
  export function createTestBehaviourEntry(overrides = {}) {
286
286
  return {
@@ -314,7 +314,7 @@ export function createTestDrivers() {
314
314
  }
315
315
 
316
316
  /**
317
- * Creates a set of mock capabilities spanning delivery / scale / ai.
317
+ * Creates a set of mock capabilities across delivery / scale / ai.
318
318
  * @returns {object[]}
319
319
  */
320
320
  export function createTestCapabilities() {
@@ -416,7 +416,7 @@ export function createTestRoster(overrides = {}) {
416
416
  }
417
417
 
418
418
  /**
419
- * Creates a mock evidence row shared across map and landmark tests.
419
+ * Creates a mock evidence row that map tests and landmark tests share.
420
420
  * @param {object} [overrides]
421
421
  * @returns {object}
422
422
  */
@@ -433,7 +433,7 @@ export function createTestEvidenceRow(overrides = {}) {
433
433
  }
434
434
 
435
435
  /**
436
- * Creates a mock skill augmented with per-level markers (human + agent arrays).
436
+ * Creates a mock skill with per-level markers (human + agent arrays).
437
437
  * @param {object} [overrides]
438
438
  * @returns {object}
439
439
  */
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Test fixture utilities for creating dynamic test data
2
+ * Test fixture utilities that create dynamic test data
3
3
  */
4
4
 
5
5
  /**
6
- * Creates sample request data for testing
6
+ * Creates sample request data for tests
7
7
  * @param {object} overrides - Properties to override
8
8
  * @returns {object} Test request object
9
9
  */
@@ -17,7 +17,7 @@ export function createTestRequest(overrides = {}) {
17
17
  }
18
18
 
19
19
  /**
20
- * Creates sample vector data for testing
20
+ * Creates sample vector data for tests
21
21
  * @param {number} count - Number of vectors to create
22
22
  * @returns {Array} Array of test vectors
23
23
  */
@@ -30,7 +30,7 @@ export function createTestVectors(count = 3) {
30
30
  }
31
31
 
32
32
  /**
33
- * Creates sample message data for testing
33
+ * Creates sample message data for tests
34
34
  * @param {number} count - Number of messages to create
35
35
  * @returns {Array} Array of test messages
36
36
  */
@@ -43,7 +43,7 @@ export function createTestMessages(count = 3) {
43
43
  }
44
44
 
45
45
  /**
46
- * Creates sample chunk data for testing
46
+ * Creates sample chunk data for tests
47
47
  * @param {number} count - Number of chunks to create
48
48
  * @returns {Array} Array of test chunks
49
49
  */
@@ -168,12 +168,12 @@ export function createMockDiscussionClient(overrides = {}) {
168
168
  }
169
169
 
170
170
  /**
171
- * Reject a request that omits `tenant_id`, mirroring `services/bridge`'s
172
- * `requireTenant` guard. Every tenant-scoped RPC carries a `tenant_id` in
173
- * both deployment modes (single-tenant binds the literal `"default"`); an
174
- * empty value is a caller error, not an empty result. The stateful mock
175
- * applies the same guard so production callers that forget to thread a
176
- * `tenant_id` fail in tests exactly as they would against the real service.
171
+ * Reject a request that omits `tenant_id`. This mirrors the `requireTenant`
172
+ * guard in `services/bridge`. Every tenant-scoped RPC carries a `tenant_id`
173
+ * in both deployment modes (single-tenant binds the literal `"default"`).
174
+ * An empty value is a caller error. It is not an empty result. The stateful
175
+ * mock applies the same guard. A production caller that forgets to thread a
176
+ * `tenant_id` fails in tests exactly as it fails against the real service.
177
177
  *
178
178
  * @param {{tenant_id?: string}} obj
179
179
  * @returns {string} the validated tenant id
@@ -208,7 +208,7 @@ function coerceInt64Fields(obj) {
208
208
 
209
209
  /**
210
210
  * Creates a stateful mock discussion client that retains records across
211
- * save/load cycles, coercing proto int64 fields back to numbers.
211
+ * save/load cycles. The client coerces proto int64 fields back to numbers.
212
212
  * @returns {object} Stateful mock discussion client
213
213
  */
214
214
  export function createStatefulDiscussionClient() {
@@ -241,8 +241,8 @@ export function createStatefulDiscussionClient() {
241
241
  const obj = req?.toJSON?.() ?? req;
242
242
  const tenant_id = requireTenant(obj);
243
243
  for (const rec of records.values()) {
244
- // Filter to the requesting tenant after the correlation scan so a
245
- // correlation owned by tenant A is invisible to tenant B.
244
+ // Filter to the tenant that made the request, after the correlation
245
+ // scan. A correlation owned by tenant A stays invisible to tenant B.
246
246
  if (rec.tenant_id !== tenant_id) continue;
247
247
  if (
248
248
  Object.values(rec.pending_callbacks ?? {}).includes(
@@ -274,8 +274,8 @@ export function createStatefulDiscussionClient() {
274
274
  RecordOrigin: spy(async (req) => {
275
275
  const obj = req?.toJSON?.() ?? req;
276
276
  const tenant_id = requireTenant(obj);
277
- // Tenant-scope the origin key so a comment id recorded by tenant A is
278
- // not seen as self-originated by tenant B.
277
+ // Tenant-scope the origin key so tenant B does not see a comment id
278
+ // recorded by tenant A as self-originated.
279
279
  origins.set(`${tenant_id}:${obj.id}`, obj);
280
280
  return {};
281
281
  }),
package/src/mock/clock.js CHANGED
@@ -4,21 +4,22 @@ import { spy } from "./spy.js";
4
4
  * Creates a mock clock with controllable time and a no-wait sleep.
5
5
  *
6
6
  * `now()` returns the current virtual time in ms. `sleep(ms)` advances
7
- * virtual time by `ms` and resolves on the next microtask — no real
8
- * timers are scheduled. `advance(ms)` lets a test move time forward
9
- * without going through `sleep` (e.g. to expire a token).
7
+ * virtual time by `ms` and resolves on the next microtask. It schedules no
8
+ * real timers. `advance(ms)` lets a test move time forward without a call
9
+ * to `sleep` (e.g. to expire a token).
10
10
  *
11
11
  * Pass `{ sleep, now }` from a returned clock to any constructor that
12
12
  * accepts those collaborators to make its tests deterministic.
13
13
  *
14
14
  * `setTimeout(fn, ms)` / `clearTimeout(handle)` / `setInterval(fn, ms)` /
15
- * `clearInterval(handle)` delegate to the host's real timers (matching
16
- * `createDefaultClock`), so a migrated module that schedules work through the
17
- * injected clock keeps its real-timer test behaviour. Virtual `now()` and the
18
- * real timers are intentionally independent — a test that needs a fired timer
19
- * waits on real time as it did before migration; a periodic sweep timer is
20
- * typically `.unref()`'d and never fires during a unit test, which exercises
21
- * its eviction path through an explicit `now` argument instead.
15
+ * `clearInterval(handle)` delegate to the host's real timers, the same as
16
+ * `createDefaultClock`. So a migrated module that schedules work through
17
+ * the injected clock keeps its real-timer test behaviour. Virtual `now()`
18
+ * and the real timers stay independent by design. A test that needs a fired
19
+ * timer waits on real time, as it did before migration. A periodic sweep
20
+ * timer is typically `.unref()`'d and never fires during a unit test. The
21
+ * unit test exercises its eviction path through an explicit `now` argument
22
+ * instead.
22
23
  *
23
24
  * @param {object} [options]
24
25
  * @param {number} [options.start=0] - Initial virtual time in ms.
package/src/mock/data.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Shared test data for common testing scenarios
2
+ * Shared test data for common test scenarios
3
3
  */
4
4
 
5
5
  // Sample request data
@@ -2,11 +2,12 @@ import { createMockStorage } from "./storage.js";
2
2
 
3
3
  /**
4
4
  * Graph-index test triple: a mock storage, an n3 Store, and a GraphIndex wired
5
- * to both. GraphIndex and Store are injected so libmock stays dependency-free.
5
+ * to both. The caller injects GraphIndex and Store so libmock stays
6
+ * dependency-free.
6
7
  * @param {object} opts
7
8
  * @param {Function} opts.GraphIndex - libgraph GraphIndex constructor.
8
9
  * @param {Function} opts.Store - n3 Store constructor.
9
- * @param {object} [opts.storageOverrides] - passed to createMockStorage.
10
+ * @param {object} [opts.storageOverrides] - overrides for createMockStorage.
10
11
  * @param {*} [opts.prefixes] - prefixes arg for GraphIndex (default {}).
11
12
  * @param {string} [opts.indexKey] - jsonl key (default "test-graph.jsonl").
12
13
  * @returns {{ n3Store: object, graphIndex: object, mockStorage: object }}
@@ -25,9 +26,10 @@ export function createGraphIndexFixture({
25
26
  }
26
27
 
27
28
  /**
28
- * The stripped gRPC health service definition consumers' tests fake — the
29
- * `{ Check: { path, requestStream, responseStream } }` shape, not librpc's
30
- * real `healthDefinition` (which librpc's own tests exercise directly).
29
+ * The stripped definition of the gRPC health service that consumers' tests
30
+ * fake. It has the `{ Check: { path, requestStream, responseStream } }`
31
+ * shape. It is not librpc's real `healthDefinition`, which librpc's own
32
+ * tests exercise directly.
31
33
  * @returns {{ Check: { path: string, requestStream: boolean, responseStream: boolean } }}
32
34
  */
33
35
  export function createMockGrpcHealthDefinition() {
@@ -42,7 +44,7 @@ export function createMockGrpcHealthDefinition() {
42
44
 
43
45
  /**
44
46
  * The readline/process/os/formatter/storage bundle librepl's tests inject.
45
- * Mirrors libraries/librepl/test/librepl.test.js's pre-collapse beforeEach.
47
+ * It mirrors libraries/librepl/test/librepl.test.js's pre-collapse beforeEach.
46
48
  * @returns {{ readline: object, process: object, os: object, formatter: Function, storage: object }}
47
49
  */
48
50
  export function createReplEnvironment() {
@@ -2,11 +2,11 @@ import path from "node:path";
2
2
  import { spy } from "./spy.js";
3
3
 
4
4
  /**
5
- * Creates a mock `Finder` collaborator over an in-memory `files` map. Mimics
6
- * the real `Finder` surface (`findUpward`, `findData`, `findProjectRoot`,
7
- * `findPackagePath`, `findGeneratedPath`, `createSymlink`,
8
- * `createPackageSymlinks`) without touching the real filesystem. Every call
9
- * is recorded on `calls`.
5
+ * Creates a mock `Finder` collaborator over an in-memory `files` map. It
6
+ * mimics the real `Finder` surface (`findUpward`, `findData`,
7
+ * `findProjectRoot`, `findPackagePath`, `findGeneratedPath`,
8
+ * `createSymlink`, `createPackageSymlinks`). It does not touch the real
9
+ * filesystem. The mock records every call on `calls`.
10
10
  *
11
11
  * @param {object} [options]
12
12
  * @param {Object<string, true|string>} [options.files] - Existing paths.
package/src/mock/fs.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Readable, Writable } from "node:stream";
2
2
  import { spy } from "./spy.js";
3
3
  /**
4
- * Creates a mock filesystem backed by an in-memory Map
4
+ * Creates a mock filesystem over an in-memory Map
5
5
  * @param {Object<string, string>} files - Initial file contents keyed by path
6
6
  * @returns {object} Mock fs with readFile, writeFile, readdir, stat, mkdir, access, copyFile
7
7
  */
@@ -55,8 +55,8 @@ export function createMockFs(files = {}) {
55
55
  data.delete(src);
56
56
  }),
57
57
  readdir: spy(async (path, opts = {}) => {
58
- // Collect immediate children; an entry is a directory if anything lives
59
- // below it (a deeper key) or it was registered via mkdir/cp.
58
+ // Collect immediate children. An entry is a directory if anything lives
59
+ // below it (a deeper key), or if mkdir/cp registered it.
60
60
  const prefix = path.endsWith("/") ? path : `${path}/`;
61
61
  const isDir = new Map();
62
62
  for (const key of [...data.keys(), ...dirs]) {
@@ -95,7 +95,7 @@ export function createMockFs(files = {}) {
95
95
  }),
96
96
  mkdtemp: spy(async (prefix) => {
97
97
  // Mirror node:fs/promises.mkdtemp: append 6 random chars to the prefix
98
- // and register the directory. Returns the created path.
98
+ // and register the directory. Then return the created path.
99
99
  const path = `${prefix}${Math.random().toString(36).slice(2, 8)}`;
100
100
  dirs.add(path);
101
101
  return path;
@@ -173,8 +173,8 @@ export function createMockFs(files = {}) {
173
173
  }
174
174
  for (const dir of [...dirs].filter(under)) dirs.add(reroot(dir));
175
175
  }),
176
- // Timestamps and permissions are not modeled by the in-memory store; these
177
- // record the call (via spy) so consumers stay testable and assertable.
176
+ // The in-memory store does not model timestamps or permissions. These
177
+ // record the call (with spy) so consumers stay testable and assertable.
178
178
  utimes: spy(async () => {}),
179
179
  chmod: spy(async () => {}),
180
180
  existsSync: spy((path) => data.has(path) || dirs.has(path)),
@@ -230,12 +230,12 @@ export function createMockFs(files = {}) {
230
230
  }
231
231
  return [...names];
232
232
  }),
233
- // Permissions are not modeled by the in-memory store; record the call.
233
+ // The in-memory store does not model permissions. Record the call.
234
234
  chmodSync: spy(() => {}),
235
235
  openSync: spy((path, flags = "r") => {
236
- // For write/append flags, create/truncate; for read flags, require the
236
+ // For write/append flags, create/truncate. For read flags, require the
237
237
  // file to exist (mirror node:fs.openSync ENOENT). Hand back a synthetic
238
- // descriptor that records its backing path.
238
+ // descriptor that records the path it opens.
239
239
  const reading = typeof flags === "string" && flags.startsWith("r");
240
240
  if (reading && !data.has(path)) {
241
241
  const err = new Error(
@@ -251,7 +251,7 @@ export function createMockFs(files = {}) {
251
251
  }),
252
252
  readSync: spy((fd, buffer, offset = 0, length, position = 0) => {
253
253
  // Mirror fs.readSync(fd, buffer, offset, length, position): copy bytes
254
- // from the file's stored content into `buffer`, returning the byte count.
254
+ // from the file's stored content into `buffer`. Return the byte count.
255
255
  const path = openFds.get(fd);
256
256
  if (path === undefined) {
257
257
  const err = new Error("EBADF: bad file descriptor, read");
@@ -9,9 +9,9 @@ const GH_METHODS = [
9
9
  ];
10
10
 
11
11
  /**
12
- * Creates a mock `GhClient` collaborator. Each method is a spy returning the
13
- * configured `responses[method]` value (or a no-op default). Invocations are
14
- * recorded on `calls`.
12
+ * Creates a mock `GhClient` collaborator. Each method is a spy that returns
13
+ * the configured `responses[method]` value (or a no-op default). The mock
14
+ * records every call on `calls`.
15
15
  *
16
16
  * @param {object} [options]
17
17
  * @param {Record<string, unknown>} [options.responses] - Per-method returns.
@@ -40,10 +40,10 @@ const GIT_METHODS = [
40
40
  ];
41
41
 
42
42
  // A response descriptor models one git failure: an `Error` thrown as-is, or
43
- // `{ throw: <message>, stderr?: <text> }` thrown as an Error carrying that
44
- // stderr — mirroring how GitClient's `#runRaw` surfaces a failure (the real
45
- // GitError exposes `.stderr`), so a caller inspecting stderr (e.g. to tell a
46
- // push rejection from an auth failure) sees a faithful shape.
43
+ // `{ throw: <message>, stderr?: <text> }` thrown as an Error that carries
44
+ // that stderr. This mirrors how GitClient's `#runRaw` surfaces a failure
45
+ // (the real GitError exposes `.stderr`). So a caller that inspects stderr
46
+ // (e.g. to tell a push rejection from an auth failure) sees a faithful shape.
47
47
  function isResponseDescriptor(value) {
48
48
  return (
49
49
  value instanceof Error ||
@@ -52,10 +52,11 @@ function isResponseDescriptor(value) {
52
52
  }
53
53
 
54
54
  // A configured response that is an array of response descriptors is a per-call
55
- // sequence: consumed one entry per invocation, reusing the last entry once
56
- // exhausted, so a test can express "push rejected on call 1, succeeds on call
57
- // 2". An array that is plain data (e.g. a `logByAuthor` commit list) is returned
58
- // whole — the descriptor check keeps data returns and failure sequences apart.
55
+ // sequence. The mock takes one entry per invocation. It reuses the last entry
56
+ // after the sequence runs out. So a test can express "push rejected on call 1,
57
+ // succeeds on call 2". The mock returns the whole array when it holds plain
58
+ // data (e.g. a `logByAuthor` commit list). The descriptor check keeps data
59
+ // returns and failure sequences apart.
59
60
  function makeResponder(configured) {
60
61
  const isSequence =
61
62
  Array.isArray(configured) && configured.some(isResponseDescriptor);
@@ -75,7 +76,7 @@ function resolveResponse(responder) {
75
76
  return value;
76
77
  }
77
78
 
78
- // Per-method default returns when no `responses[method]` is configured.
79
+ // Per-method default returns when the caller configures no `responses[method]`.
79
80
  // Methods absent here default to a no-op success `{ stdout, stderr, exitCode }`.
80
81
  const GIT_DEFAULTS = {
81
82
  revListCount: 0,
@@ -90,9 +91,10 @@ const GIT_DEFAULTS = {
90
91
 
91
92
  /**
92
93
  * Creates a mock `GitClient` collaborator. Every method on the real
93
- * `GitClient` surface is a spy returning a no-op success by default, or the
94
- * configured `responses[method]` value. `withAuth(token)` returns a client
95
- * sharing the same `calls` log. Invocations are recorded on `calls`.
94
+ * `GitClient` surface is a spy that returns a no-op success by default, or
95
+ * the configured `responses[method]` value. `withAuth(token)` returns a
96
+ * client that shares the same `calls` log. The mock records every call on
97
+ * `calls`.
96
98
  *
97
99
  * @param {object} [options]
98
100
  * @param {Record<string, unknown>} [options.responses] - Per-method returns.
package/src/mock/grpc.js CHANGED
@@ -77,7 +77,7 @@ export class MockMetadata {
77
77
  /**
78
78
  * Gets metadata value by key
79
79
  * @param {string} key - The metadata key
80
- * @returns {string[]} Array containing the value, or empty array if not found
80
+ * @returns {string[]} Array with the value, or empty array if not found
81
81
  */
82
82
  get(key) {
83
83
  const value = this.data.get(key);
package/src/mock/http.js CHANGED
@@ -31,7 +31,7 @@ export function createMockRequest(options = {}) {
31
31
  }
32
32
 
33
33
  /**
34
- * Creates a mock HTTP response with tracking
34
+ * Creates a mock HTTP response that tracks calls
35
35
  * @returns {object} Mock response
36
36
  */
37
37
  export function createMockResponse() {
package/src/mock/infra.js CHANGED
@@ -1,13 +1,14 @@
1
1
  /**
2
- * Additional infrastructure mocks for services/products tests. Centralizes
3
- * variants that consumers previously inlined.
2
+ * Additional infrastructure mocks for services/products tests. This module
3
+ * centralizes variants that consumers previously inlined.
4
4
  */
5
5
  import { Writable } from "node:stream";
6
6
 
7
7
  /**
8
- * A capturing `Writable` used as the mock `proc.stdout`/`stderr`. It retains
9
- * the `chunks` accessor existing assertions read AND is a real `Writable`, so
10
- * it accepts piped input (e.g. a `pipeline()` from a read stream).
8
+ * A `Writable` that captures output. The mock uses it as
9
+ * `proc.stdout`/`stderr`. It retains the `chunks` accessor that current
10
+ * assertions read. It is also a real `Writable`, so it accepts piped input
11
+ * (e.g. a `pipeline()` from a read stream).
11
12
  */
12
13
  class CaptureWritable extends Writable {
13
14
  constructor() {
@@ -28,15 +29,15 @@ class CaptureWritable extends Writable {
28
29
 
29
30
  /**
30
31
  * Creates a mock Supabase-style client with configurable table and storage
31
- * behaviour. Covers the patterns found across products/map/test/activity/*.
32
+ * behaviour. It covers the patterns across products/map/test/activity/*.
32
33
  *
33
34
  * @param {object} [options]
34
35
  * @param {Record<string, object>} [options.tables] - Map of table name to
35
36
  * override. Each override may expose `select`, `insert`, `upsert`, `delete`
36
37
  * as async functions. Unspecified methods return `{ data: [], error: null }`.
37
- * @param {Record<string, string>} [options.files] - Files exposed via
38
+ * @param {Record<string, string>} [options.files] - Files exposed through
38
39
  * `storage.from(...).list(prefix)` / `.download(path)`.
39
- * @returns {object} Mock client and call-tracking arrays.
40
+ * @returns {object} Mock client and arrays that track calls.
40
41
  */
41
42
  export function createMockSupabaseClient({ tables = {}, files = {} } = {}) {
42
43
  const calls = {
@@ -115,8 +116,8 @@ export function createMockSupabaseClient({ tables = {}, files = {} } = {}) {
115
116
  }
116
117
 
117
118
  /**
118
- * Creates Turtle parsing helpers bound to an injected n3 Parser. Keeps
119
- * libmock free of an n3 dependency while allowing services to share the
119
+ * Creates helpers that parse Turtle with an injected n3 Parser. This keeps
120
+ * libmock free of an n3 dependency. Services can still share the
120
121
  * parseQuads / findAll / findOne idiom.
121
122
  *
122
123
  * @param {import("n3").Parser | Function} ParserOrInstance - n3 Parser class
@@ -156,8 +157,8 @@ export function createTurtleHelpers(
156
157
  }
157
158
 
158
159
  /**
159
- * Build an `AsyncIterable<string>` over a fixed list of input chunks, used as
160
- * the mock `proc.stdin`.
160
+ * Build an `AsyncIterable<string>` over a fixed list of input chunks. The
161
+ * mock uses it as `proc.stdin`.
161
162
  * @param {string[]} chunks - Lines/chunks the iterator yields in order.
162
163
  * @returns {AsyncIterable<string>}
163
164
  */
@@ -170,13 +171,14 @@ export function createMockStdin(chunks = []) {
170
171
  }
171
172
 
172
173
  /**
173
- * Creates a mock `process`-like object matching the `Runtime.proc` surface:
174
- * `cwd()`, `env`, `argv`, `stdin`, `stdout`/`stderr` (capturing `Writable`s),
175
- * `exit(code)`, `kill(pid, signal)`, `pid`, `platform`, `on(event, handler)`,
176
- * and a settable `exitCode`. Writes are captured on `stdout.chunks` /
177
- * `stderr.chunks` (and the streams accept piped input); kill calls on `kills`;
178
- * event handlers on `handlers` (fire them via `emit(event, ...args)` to
179
- * simulate a signal).
174
+ * Creates a mock `process`-like object that matches the `Runtime.proc`
175
+ * surface: `cwd()`, `env`, `argv`, `stdin`, `stdout`/`stderr` (`Writable`s
176
+ * that capture output), `exit(code)`, `kill(pid, signal)`, `pid`,
177
+ * `platform`, `on(event, handler)`, and a settable `exitCode`. The mock
178
+ * captures writes on `stdout.chunks` / `stderr.chunks`, and the streams
179
+ * accept piped input. It records kill calls on `kills`. It records event
180
+ * handlers on `handlers`. Fire them with `emit(event, ...args)` to simulate
181
+ * a signal.
180
182
  *
181
183
  * @param {object} [options]
182
184
  * @param {Record<string, string>} [options.env] - Initial env map.
@@ -184,11 +186,12 @@ export function createMockStdin(chunks = []) {
184
186
  * @param {string[]} [options.argv] - The frozen `argv` array.
185
187
  * @param {string[]} [options.stdin] - Chunks the `stdin` iterator yields.
186
188
  * @param {(pid: number, signal: string|number) => any} [options.kill] - Optional
187
- * `kill` implementation (e.g. to model a liveness probe); calls are always
188
- * recorded on the returned `kills` array regardless.
189
+ * `kill` implementation (e.g. to model a liveness probe). The mock always
190
+ * records calls on the returned `kills` array regardless.
189
191
  * @param {number} [options.pid] - The fake's `pid` (default 1234).
190
192
  * @param {string} [options.platform] - The fake's `platform` string
191
- * (default `"linux"`; set `"darwin"`/`"win32"` to exercise per-platform code).
193
+ * (default `"linux"`). Set `"darwin"`/`"win32"` to exercise per-platform
194
+ * code.
192
195
  * @returns {object}
193
196
  */
194
197
  export function createMockProcess({
@@ -203,8 +206,8 @@ export function createMockProcess({
203
206
  const stdout = new CaptureWritable();
204
207
  const stderr = new CaptureWritable();
205
208
  const kills = [];
206
- // Registered event handlers (e.g. "SIGTERM"/"SIGINT"); a test can fire them
207
- // via `emit(event, ...args)` to simulate a signal without a real process.
209
+ // Registered event handlers (e.g. "SIGTERM"/"SIGINT"). A test can fire them
210
+ // with `emit(event, ...args)` to simulate a signal without a real process.
208
211
  const handlers = {};
209
212
  return {
210
213
  env: { ...env },
@@ -235,8 +238,8 @@ export function createMockProcess({
235
238
  }
236
239
 
237
240
  /**
238
- * Runs `fn` with `console.log`, `console.info`, and `console.warn` suppressed,
239
- * returning whatever `fn` returns. Errors still propagate.
241
+ * Runs `fn` and suppresses `console.log`, `console.info`, and `console.warn`.
242
+ * It returns whatever `fn` returns. Errors still propagate.
240
243
  *
241
244
  * @template T
242
245
  * @param {() => T | Promise<T>} fn
@@ -262,8 +265,9 @@ export async function withSilentConsole(fn) {
262
265
 
263
266
  /**
264
267
  * Creates a bag of async query stubs from a plain values object. A function
265
- * value is passed through untouched; anything else becomes an async function
266
- * returning that value. Collapses landmark-style `stubQueries` boilerplate.
268
+ * value passes through untouched. Anything else becomes an async function
269
+ * that returns that value. This collapses landmark-style `stubQueries`
270
+ * boilerplate.
267
271
  *
268
272
  * @param {Record<string, unknown>} values
269
273
  * @returns {Record<string, Function>}
@@ -1,6 +1,6 @@
1
1
  import { spy } from "./spy.js";
2
2
  /**
3
- * Creates a mock logger with call tracking
3
+ * Creates a mock logger that tracks calls
4
4
  * @param {object} options - Logger options
5
5
  * @param {boolean} options.captureOutput - Whether to capture log output
6
6
  * @returns {object} Mock logger
@@ -72,9 +72,9 @@ export function createMockResourceIndex(options = {}) {
72
72
  },
73
73
 
74
74
  /**
75
- * Find resources by prefix
75
+ * Finds resources by prefix
76
76
  * @param {string} prefix - Prefix to search for
77
- * @returns {Promise<string[]>} List of matching keys
77
+ * @returns {Promise<string[]>} List of keys that match
78
78
  */
79
79
  async findByPrefix(prefix) {
80
80
  const keys = [];
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Creates a mock service callbacks object for agent testing
2
+ * Creates a mock service-callbacks object for agent tests
3
3
  * @param {object} overrides - Method overrides per service
4
4
  * @returns {object} Service callbacks object
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Mock service utilities for testing
2
+ * Mock service utilities for tests
3
3
  */
4
4
 
5
5
  /**
package/src/mock/spy.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * Portable mock function helper. Replaces `mock.fn` from `node:test` so the
3
3
  * test suite can run under either node:test or bun:test.
4
4
  *
5
- * Shape matches node:test's `mock.fn` to keep call-inspection sites
5
+ * The shape matches node:test's `mock.fn` to keep call-inspection sites
6
6
  * (`fn.mock.calls[0].arguments`, `fn.mock.callCount()`, `fn.mock.resetCalls()`)
7
7
  * unchanged across the codebase.
8
8
  *
@@ -1,8 +1,8 @@
1
1
  import { spy } from "./spy.js";
2
2
  /**
3
- * Creates a mock storage instance with tracking
3
+ * Creates a mock storage instance that tracks data
4
4
  * @param {object} overrides - Method overrides
5
- * @returns {object} Mock storage with data tracking
5
+ * @returns {object} Mock storage that tracks data
6
6
  */
7
7
  export function createMockStorage(overrides = {}) {
8
8
  const data = new Map();
@@ -78,7 +78,7 @@ export class MockStorage {
78
78
  }
79
79
 
80
80
  /**
81
- * Alias for put - stores a value by key
81
+ * Alias for put. Stores a value by key
82
82
  * @param {string} key - The storage key
83
83
  * @param {*} value - The value to store
84
84
  * @returns {Promise<void>}
@@ -101,7 +101,7 @@ export class MockStorage {
101
101
  /**
102
102
  * Checks if a key exists
103
103
  * @param {string} key - The storage key
104
- * @returns {Promise<boolean>} True if key exists
104
+ * @returns {Promise<boolean>} True if the key exists
105
105
  */
106
106
  async exists(key) {
107
107
  return this.data.has(key);
@@ -11,11 +11,12 @@ function asyncIterableOf(str) {
11
11
  }
12
12
 
13
13
  /**
14
- * A captured-chunks sink for a spawned child's writable stdin. A real
15
- * `node:stream` Writable (so it is a valid `pipe()` destination, the way a
16
- * supervisor pipes a service's output into its logger) that records every
17
- * written chunk on `chunks` instead of forwarding it anywhere. Mirrors the
18
- * `stdin` the production `createDefaultSubprocess().spawn` exposes.
14
+ * A captured-chunks sink for a spawned child's writable stdin. The sink is a
15
+ * real `node:stream` Writable, so it is a valid `pipe()` destination. A
16
+ * supervisor pipes a service's output into its logger in the same way. The
17
+ * sink records every written chunk on `chunks`. It does not forward the chunk
18
+ * anywhere. It mirrors the `stdin` that the production
19
+ * `createDefaultSubprocess().spawn` exposes.
19
20
  */
20
21
  function createMockStdinSink() {
21
22
  const chunks = [];
@@ -30,14 +31,14 @@ function createMockStdinSink() {
30
31
  }
31
32
 
32
33
  /**
33
- * Creates a mock subprocess collaborator matching the `Runtime.subprocess`
34
- * surface. `run(cmd, args, opts)` resolves to `{ stdout, stderr, exitCode }`
35
- * consulting `responses[cmd]` (default: empty success); `runSync` is its
36
- * synchronous sibling returning the same shape. `spawn` returns a streaming
37
- * quad backed by the same responses (its result carries `stdout`/`stderr`
34
+ * Creates a mock subprocess collaborator that matches the `Runtime.subprocess`
35
+ * surface. `run(cmd, args, opts)` consults `responses[cmd]` (default: empty
36
+ * success) and resolves to `{ stdout, stderr, exitCode }`. `runSync` is its
37
+ * synchronous sibling and returns the same shape. `spawn` returns a streaming
38
+ * quad backed by the same responses. Its result carries `stdout`/`stderr`
38
39
  * AsyncIterables, a captured-chunks `stdin` sink, `exitCode`/`signal` Promises,
39
- * a `kill(signal)` spy recording on `kills`, and `pid`). All invocations are
40
- * recorded on `calls`.
40
+ * a `kill(signal)` spy that records on `kills`, and `pid`. The mock records
41
+ * every invocation on `calls`.
41
42
  *
42
43
  * @param {object} [options]
43
44
  * @param {Record<string, {stdout?: string, stderr?: string, exitCode?: number}>} [options.responses]
@@ -70,11 +71,13 @@ export function createMockSubprocess({ responses = {} } = {}) {
70
71
  return {
71
72
  stdout: asyncIterableOf(r.stdout),
72
73
  stderr: asyncIterableOf(r.stderr),
73
- // A captured-chunks writable; `null` only when a response explicitly
74
- // sets `stdin: null` (matching a child spawned without a stdin pipe).
74
+ // A captured-chunks writable. It is `null` only when a response
75
+ // explicitly sets `stdin: null`. That matches a child spawned without a
76
+ // stdin pipe.
75
77
  stdin: r.stdin === null ? null : createMockStdinSink(),
76
78
  exitCode: Promise.resolve(r.exitCode),
77
- // Terminating signal: `null` (clean exit) unless a response overrides it.
79
+ // The signal that stopped the child is `null` (clean exit) unless a
80
+ // response overrides it.
78
81
  signal: Promise.resolve(r.signal ?? null),
79
82
  kills,
80
83
  kill: spy((signal) => {
package/src/runtime.js CHANGED
@@ -5,9 +5,9 @@ import { createMockSubprocess } from "./mock/subprocess.js";
5
5
  import { createMockFinder } from "./mock/finder.js";
6
6
 
7
7
  /**
8
- * Build a frozen mock runtime bag for tests, matching the production
9
- * `Runtime` typedef. Every field defaults to its canonical
10
- * libmock fake and is independently overridable via `overrides`.
8
+ * Build a frozen mock runtime bag for tests. The bag matches the production
9
+ * `Runtime` typedef. Every field defaults to its canonical libmock fake.
10
+ * Override each field independently through `overrides`.
11
11
  *
12
12
  * @param {object} [overrides] - Per-field replacements.
13
13
  * @param {object} [overrides.fs] - Async fs surface (default `createMockFs()`).