@overkill-dev/doubles 0.0.1 → 0.0.2

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.
Files changed (178) hide show
  1. package/LICENSE +21 -0
  2. package/assert/assertion-extension.d.ts +65 -0
  3. package/assert/assertion-extension.d.ts.map +1 -0
  4. package/assert/assertion-extension.js +250 -0
  5. package/assert/assertion-extension.js.map +1 -0
  6. package/assertion-protocol/assertion-evaluation.d.ts +13 -0
  7. package/assertion-protocol/assertion-evaluation.d.ts.map +1 -0
  8. package/assertion-protocol/assertion-node-shape.d.ts +71 -0
  9. package/assertion-protocol/assertion-node-shape.d.ts.map +1 -0
  10. package/assertion-protocol/assertion-node.d.ts +97 -0
  11. package/assertion-protocol/assertion-node.d.ts.map +1 -0
  12. package/assertion-protocol/assertion-reference.d.ts +73 -0
  13. package/assertion-protocol/assertion-reference.d.ts.map +1 -0
  14. package/assertion-protocol/assertion-reference.js +49 -0
  15. package/assertion-protocol/assertion-reference.js.map +1 -0
  16. package/assertion-protocol/assertions/boolean.d.ts +11 -0
  17. package/assertion-protocol/assertions/boolean.d.ts.map +1 -0
  18. package/assertion-protocol/assertions/collection.d.ts +22 -0
  19. package/assertion-protocol/assertions/collection.d.ts.map +1 -0
  20. package/assertion-protocol/assertions/equality.d.ts +17 -0
  21. package/assertion-protocol/assertions/equality.d.ts.map +1 -0
  22. package/assertion-protocol/assertions/fail.d.ts +13 -0
  23. package/assertion-protocol/assertions/fail.d.ts.map +1 -0
  24. package/assertion-protocol/assertions/numeric.d.ts +29 -0
  25. package/assertion-protocol/assertions/numeric.d.ts.map +1 -0
  26. package/assertion-protocol/assertions/partial.d.ts +14 -0
  27. package/assertion-protocol/assertions/partial.d.ts.map +1 -0
  28. package/assertion-protocol/assertions/presence.d.ts +17 -0
  29. package/assertion-protocol/assertions/presence.d.ts.map +1 -0
  30. package/assertion-protocol/assertions/string.d.ts +28 -0
  31. package/assertion-protocol/assertions/string.d.ts.map +1 -0
  32. package/assertion-protocol/assertions/type-shape.d.ts +42 -0
  33. package/assertion-protocol/assertions/type-shape.d.ts.map +1 -0
  34. package/assertion-protocol/thrown-error-record.d.ts +8 -0
  35. package/assertion-protocol/thrown-error-record.d.ts.map +1 -0
  36. package/assertion-protocol/thrown-error-record.js +17 -0
  37. package/assertion-protocol/thrown-error-record.js.map +1 -0
  38. package/assertion-protocol/thrown-matcher.d.ts +51 -0
  39. package/assertion-protocol/thrown-matcher.d.ts.map +1 -0
  40. package/assertion-protocol/thrown-matcher.js +186 -0
  41. package/assertion-protocol/thrown-matcher.js.map +1 -0
  42. package/compare/comparison-result.d.ts +25 -0
  43. package/compare/comparison-result.d.ts.map +1 -0
  44. package/compare/comparison-state.d.ts +7 -0
  45. package/compare/comparison-state.d.ts.map +1 -0
  46. package/compare/comparison-state.js +20 -0
  47. package/compare/comparison-state.js.map +1 -0
  48. package/compare/comparison.d.ts +12 -0
  49. package/compare/comparison.d.ts.map +1 -0
  50. package/compare/raw-comparison.d.ts +24 -0
  51. package/compare/raw-comparison.d.ts.map +1 -0
  52. package/compare/raw-comparison.js +285 -0
  53. package/compare/raw-comparison.js.map +1 -0
  54. package/compare/serialized-value-shape.d.ts +143 -0
  55. package/compare/serialized-value-shape.d.ts.map +1 -0
  56. package/compare/serialized-value.d.ts +11 -0
  57. package/compare/serialized-value.d.ts.map +1 -0
  58. package/compare/value-classification.d.ts +26 -0
  59. package/compare/value-classification.d.ts.map +1 -0
  60. package/compare/value-classification.js +110 -0
  61. package/compare/value-classification.js.map +1 -0
  62. package/diff/diff-shape.d.ts +117 -0
  63. package/diff/diff-shape.d.ts.map +1 -0
  64. package/doubles/disposal-symbol.d.ts +3 -0
  65. package/doubles/disposal-symbol.d.ts.map +1 -0
  66. package/doubles/disposal-symbol.js +10 -0
  67. package/doubles/disposal-symbol.js.map +1 -0
  68. package/doubles/double-behavior.d.ts +106 -0
  69. package/doubles/double-behavior.d.ts.map +1 -0
  70. package/doubles/double-behavior.js +257 -0
  71. package/doubles/double-behavior.js.map +1 -0
  72. package/doubles/double-chronology.d.ts +21 -0
  73. package/doubles/double-chronology.d.ts.map +1 -0
  74. package/doubles/double-chronology.js +78 -0
  75. package/doubles/double-chronology.js.map +1 -0
  76. package/doubles/double-history-api.d.ts +33 -0
  77. package/doubles/double-history-api.d.ts.map +1 -0
  78. package/doubles/double-history-api.js +125 -0
  79. package/doubles/double-history-api.js.map +1 -0
  80. package/doubles/double-history-record.d.ts +82 -0
  81. package/doubles/double-history-record.d.ts.map +1 -0
  82. package/doubles/double-history-record.js +65 -0
  83. package/doubles/double-history-record.js.map +1 -0
  84. package/doubles/double-history-store.d.ts +21 -0
  85. package/doubles/double-history-store.d.ts.map +1 -0
  86. package/doubles/double-history-store.js +118 -0
  87. package/doubles/double-history-store.js.map +1 -0
  88. package/doubles/double-history.d.ts +141 -0
  89. package/doubles/double-history.d.ts.map +1 -0
  90. package/doubles/double-history.js +32 -0
  91. package/doubles/double-history.js.map +1 -0
  92. package/doubles/double-iterator-event-types.d.ts +25 -0
  93. package/doubles/double-iterator-event-types.d.ts.map +1 -0
  94. package/doubles/double-iterator-tracking.d.ts +12 -0
  95. package/doubles/double-iterator-tracking.d.ts.map +1 -0
  96. package/doubles/double-iterator-tracking.js +161 -0
  97. package/doubles/double-iterator-tracking.js.map +1 -0
  98. package/doubles/double-rule-arguments.d.ts +18 -0
  99. package/doubles/double-rule-arguments.d.ts.map +1 -0
  100. package/doubles/double-rule-callback.d.ts +40 -0
  101. package/doubles/double-rule-callback.d.ts.map +1 -0
  102. package/doubles/double-rule-callback.js +84 -0
  103. package/doubles/double-rule-callback.js.map +1 -0
  104. package/doubles/double-rule-generator.d.ts +108 -0
  105. package/doubles/double-rule-generator.d.ts.map +1 -0
  106. package/doubles/double-rule-generator.js +37 -0
  107. package/doubles/double-rule-generator.js.map +1 -0
  108. package/doubles/double-rule-types.d.ts +162 -0
  109. package/doubles/double-rule-types.d.ts.map +1 -0
  110. package/doubles/double-rule.d.ts +3 -0
  111. package/doubles/double-rule.d.ts.map +1 -0
  112. package/doubles/double-rule.js +113 -0
  113. package/doubles/double-rule.js.map +1 -0
  114. package/doubles/double-runtime.d.ts +9 -0
  115. package/doubles/double-runtime.d.ts.map +1 -0
  116. package/doubles/double-runtime.js +173 -0
  117. package/doubles/double-runtime.js.map +1 -0
  118. package/doubles/double-signature.d.ts +5 -0
  119. package/doubles/double-signature.d.ts.map +1 -0
  120. package/doubles/double-usage-argument-assertion.d.ts +27 -0
  121. package/doubles/double-usage-argument-assertion.d.ts.map +1 -0
  122. package/doubles/double-usage-argument-assertion.js +202 -0
  123. package/doubles/double-usage-argument-assertion.js.map +1 -0
  124. package/doubles/double-usage-contract.d.ts +29 -0
  125. package/doubles/double-usage-contract.d.ts.map +1 -0
  126. package/doubles/double-usage-contract.js +11 -0
  127. package/doubles/double-usage-contract.js.map +1 -0
  128. package/doubles/double-usage-count-assertion.d.ts +6 -0
  129. package/doubles/double-usage-count-assertion.d.ts.map +1 -0
  130. package/doubles/double-usage-count-assertion.js +73 -0
  131. package/doubles/double-usage-count-assertion.js.map +1 -0
  132. package/doubles/double-usage-disposal-assertion.d.ts +7 -0
  133. package/doubles/double-usage-disposal-assertion.d.ts.map +1 -0
  134. package/doubles/double-usage-disposal-assertion.js +175 -0
  135. package/doubles/double-usage-disposal-assertion.js.map +1 -0
  136. package/doubles/double-usage-inspection.d.ts +22 -0
  137. package/doubles/double-usage-inspection.d.ts.map +1 -0
  138. package/doubles/double-usage-inspection.js +59 -0
  139. package/doubles/double-usage-inspection.js.map +1 -0
  140. package/doubles/double-usage-iterator-assertion.d.ts +7 -0
  141. package/doubles/double-usage-iterator-assertion.d.ts.map +1 -0
  142. package/doubles/double-usage-iterator-assertion.js +124 -0
  143. package/doubles/double-usage-iterator-assertion.js.map +1 -0
  144. package/doubles/double-usage-order-assertion.d.ts +3 -0
  145. package/doubles/double-usage-order-assertion.d.ts.map +1 -0
  146. package/doubles/double-usage-order-assertion.js +91 -0
  147. package/doubles/double-usage-order-assertion.js.map +1 -0
  148. package/doubles/double-usage.d.ts +81 -0
  149. package/doubles/double-usage.d.ts.map +1 -0
  150. package/doubles/double-usage.js +228 -0
  151. package/doubles/double-usage.js.map +1 -0
  152. package/doubles/protocol-disposable-double.d.ts +16 -0
  153. package/doubles/protocol-disposable-double.d.ts.map +1 -0
  154. package/doubles/protocol-disposable-double.js +37 -0
  155. package/doubles/protocol-disposable-double.js.map +1 -0
  156. package/doubles/protocol-double-metadata.d.ts +15 -0
  157. package/doubles/protocol-double-metadata.d.ts.map +1 -0
  158. package/doubles/protocol-double-metadata.js +30 -0
  159. package/doubles/protocol-double-metadata.js.map +1 -0
  160. package/doubles/protocol-double.d.ts +50 -0
  161. package/doubles/protocol-double.d.ts.map +1 -0
  162. package/doubles/protocol-double.js +76 -0
  163. package/doubles/protocol-double.js.map +1 -0
  164. package/doubles/protocol-iterator-double.d.ts +93 -0
  165. package/doubles/protocol-iterator-double.d.ts.map +1 -0
  166. package/doubles/protocol-iterator-double.js +512 -0
  167. package/doubles/protocol-iterator-double.js.map +1 -0
  168. package/doubles/test-double.d.ts +62 -0
  169. package/doubles/test-double.d.ts.map +1 -0
  170. package/doubles/test-double.js +192 -0
  171. package/doubles/test-double.js.map +1 -0
  172. package/package.json +36 -6
  173. package/packages/doubles/doubles.entry-point.d.ts +13 -0
  174. package/packages/doubles/doubles.entry-point.d.ts.map +1 -0
  175. package/packages/doubles/doubles.entry-point.js +5 -0
  176. package/packages/doubles/doubles.entry-point.js.map +1 -0
  177. package/readme.md +423 -5
  178. package/sbom.cdx.json +30 -0
package/readme.md CHANGED
@@ -1,7 +1,425 @@
1
- # @overkill-dev/doubles
1
+ # `@overkill-dev/doubles`
2
2
 
3
- This version is a placeholder published only to claim the npm name `@overkill-dev/doubles` so a Trusted Publisher
4
- can subsequently be configured for it. It contains no real package content and is published already
5
- deprecated.
3
+ Explicit function-first test doubles for Overkill.
6
4
 
7
- Workaround context: https://github.com/npm/cli/issues/8544
5
+ Use this package when a test can inject a function or constructor directly.
6
+ It does not patch modules, replace object methods, manage sandboxes, or keep a
7
+ restore registry.
8
+
9
+ ## Import
10
+
11
+ ```ts
12
+ import {
13
+ doubleUsage,
14
+ rule,
15
+ testAsyncDisposable,
16
+ testAsyncIterable,
17
+ testAsyncIterator,
18
+ testDisposable,
19
+ testDouble,
20
+ testIterable,
21
+ testIterator
22
+ } from '@overkill-dev/doubles';
23
+ ```
24
+
25
+ Public runtime values:
26
+
27
+ - `testDouble`: creates callable or constructable test doubles.
28
+ - `testIterator`: creates one consumable sync iterator double.
29
+ - `testIterable`: creates a reusable sync iterable double.
30
+ - `testAsyncIterator`: creates one consumable async iterator double.
31
+ - `testAsyncIterable`: creates a reusable async iterable double.
32
+ - `testDisposable`: creates a sync disposable double for `using`.
33
+ - `testAsyncDisposable`: creates an async disposable double for `await using`.
34
+ - `rule`: builds reusable behavior rules.
35
+ - `doubleUsage`: assertion references for `scope.assert(...)`.
36
+
37
+ ## Create A Double
38
+
39
+ Untyped doubles are callable and return `undefined`:
40
+
41
+ ```ts
42
+ const log = testDouble();
43
+
44
+ log('saved');
45
+ ```
46
+
47
+ Typed doubles keep their function signature:
48
+
49
+ ```ts
50
+ type SaveUser = (user: { readonly id: string; readonly name: string; }) => boolean;
51
+
52
+ const saveUser = testDouble.returns<SaveUser>(true);
53
+
54
+ saveUser({ id: '42', name: 'Ada' });
55
+ ```
56
+
57
+ Constructor doubles keep their constructor signature:
58
+
59
+ ```ts
60
+ type ClientConstructor = new (baseUrl: string) => Client;
61
+
62
+ const client = createClient();
63
+ const Client = testDouble.constructs<ClientConstructor>(client);
64
+
65
+ new Client('https://api.example.test');
66
+ ```
67
+
68
+ ## Fixed Behavior
69
+
70
+ - `testDouble()`: creates an untyped function double that returns `undefined`.
71
+ - `testDouble.returns(value)`: returns `value` from every call.
72
+ - `testDouble.returns<Fn>(value)`: returns `value` and keeps `Fn`.
73
+ - `testDouble.returns<Fn>()`: valid for `void` functions.
74
+ - `testDouble.resolves(value)`: returns a promise resolved with `value`.
75
+ - `testDouble.rejects(reason)`: returns a rejected promise.
76
+ - `testDouble.throws(thrown)`: throws `thrown` from every call.
77
+ - `testDouble.constructs(instance)`: returns `instance` from `new Double(...)`.
78
+ - `testDouble.yields(values, returnValue?)`: returns a fresh tracked sync
79
+ iterator from a finite value array.
80
+ - `testDouble.yieldsFrom(factory)`: returns a fresh tracked sync iterator that
81
+ delegates with `yield*`. The factory receives the double call arguments and
82
+ runs lazily on first iterator consumption.
83
+ - `testDouble.yieldsAsync(values, returnValue?)`: returns a fresh tracked async
84
+ iterator from a finite value array.
85
+ - `testDouble.yieldsAsyncFrom(factory)`: returns a fresh tracked async iterator
86
+ that delegates with async `yield*`. The factory receives the double call
87
+ arguments and may return a sync or async iterable.
88
+
89
+ ## Rules
90
+
91
+ Rules choose behavior for specific calls or constructions:
92
+
93
+ ```ts
94
+ type LoadUser = (id: string) => Promise<User>;
95
+
96
+ const loadUser = testDouble<LoadUser>({
97
+ rules: [
98
+ rule.when('admin').resolves(adminUser),
99
+ rule.when('guest').resolves(guestUser),
100
+ rule.onCall(2).rejects(new Error('unexpected retry'))
101
+ ],
102
+ fallback: rule.rejects(new Error('unknown user id'))
103
+ });
104
+ ```
105
+
106
+ Rule starters:
107
+
108
+ - `rule.when(...args)`: matches a call by a partial-deep argument prefix.
109
+ - `rule.whenConstructedWith(...args)`: matches a construction by a partial-deep argument prefix.
110
+ - `rule.onCall(index)`: matches the call at zero-based `index`.
111
+ - `rule.onConstruction(index)`: matches the construction at zero-based `index`.
112
+
113
+ Rule terminators:
114
+
115
+ - `.returns(value)`: returns a value.
116
+ - `.resolves(value)`: returns a resolved promise.
117
+ - `.rejects(reason)`: returns a rejected promise.
118
+ - `.throws(thrown)`: throws a value.
119
+ - `.constructs(instance)`: returns an instance from construction rules.
120
+ - `.calls(fn)`: calls `fn` for custom behavior.
121
+ - `.callsCallback(index, arguments, returnValue, receiver?)`: calls a callback
122
+ argument synchronously, then returns `returnValue`.
123
+ - `.callsCallbackAsync(index, arguments, returnValue, receiver?)`: returns
124
+ `returnValue`, then calls a callback argument in a microtask.
125
+ - `.sequence(entries)`: uses entries in order for repeated matches.
126
+ - `.yields(values, returnValue?)`: returns a fresh tracked sync iterator.
127
+ - `.yieldsFrom(factory)`: returns a fresh tracked sync iterator delegated from
128
+ the call arguments.
129
+ - `.yieldsAsync(values, returnValue?)`: returns a fresh tracked async iterator.
130
+ - `.yieldsAsyncFrom(factory)`: returns a fresh tracked async iterator delegated
131
+ from the call arguments.
132
+
133
+ Behavior factories can also be used directly in `fallback`:
134
+
135
+ - `rule.returns(value)`
136
+ - `rule.resolves(value)`
137
+ - `rule.rejects(reason)`
138
+ - `rule.throws(thrown)`
139
+ - `rule.constructs(instance)`
140
+ - `rule.calls(fn)`
141
+ - `rule.callsCallback(index, arguments, returnValue, receiver?)`
142
+ - `rule.callsCallbackAsync(index, arguments, returnValue, receiver?)`
143
+ - `rule.sequence(entries)`
144
+ - `rule.yields(values, returnValue?)`
145
+ - `rule.yieldsFrom(factory)`
146
+ - `rule.yieldsAsync(values, returnValue?)`
147
+ - `rule.yieldsAsyncFrom(factory)`
148
+
149
+ A fallback can separate call and construction behavior for a value that is both
150
+ callable and constructable:
151
+
152
+ ```ts
153
+ const Client = testDouble<ClientFactory>({
154
+ fallback: {
155
+ call: rule.returns(clientFromCall),
156
+ construction: rule.constructs(clientFromNew)
157
+ }
158
+ });
159
+ ```
160
+
161
+ Callback-style dependencies can invoke a callback argument without dropping to
162
+ custom behavior:
163
+
164
+ ```ts
165
+ type ReadUser = (id: string, callback: (error: Error | null, user: User) => void) => undefined;
166
+
167
+ const readUser = testDouble<ReadUser>({
168
+ fallback: rule.callsCallback(1, [ null, user ], undefined)
169
+ });
170
+ ```
171
+
172
+ ## History
173
+
174
+ Every double records usage. History properties are non-enumerable.
175
+
176
+ - `interactionCount`: calls plus constructions.
177
+ - `interactions`: all calls and constructions in order for this double.
178
+ - `firstInteraction`, `lastInteraction`, `nthInteraction(index)`: selected interaction records.
179
+ - `callCount`: normal function calls.
180
+ - `calls`: call records in order.
181
+ - `firstCall`, `lastCall`, `nthCall(index)`: selected call records.
182
+ - `constructionCount`: `new Double(...)` usages.
183
+ - `constructions`: construction records in order.
184
+ - `firstConstruction`, `lastConstruction`, `nthConstruction(index)`: selected construction records.
185
+ - `results`: returned and thrown results in order.
186
+ - `firstResult`, `lastResult`: selected result records.
187
+ - `iteratorEventCount`: tracked iterator protocol events.
188
+ - `iteratorEvents`: tracked `next`, `return`, and `throw` outcomes in order.
189
+ - `firstIteratorEvent`, `lastIteratorEvent`, `nthIteratorEvent(index)`:
190
+ selected iterator event records.
191
+ - `reset()`: clears this double's public history and rewinds double-owned ordered behavior.
192
+
193
+ Records include:
194
+
195
+ - `arguments`: the argument tuple.
196
+ - `index`: the zero-based call or construction index for that mode.
197
+ - `kind`: `call` or `construction`.
198
+ - `order`: the per-double interaction order.
199
+ - `result`: returned or thrown result data.
200
+ - `thisValue`: only on call records.
201
+ - `instance`: only on construction records.
202
+
203
+ Iterator records are created only for iterators produced by `yields`,
204
+ `yieldsFrom`, `yieldsAsync`, and `yieldsAsyncFrom`. They include:
205
+
206
+ - `kind`: `yield`, `return`, or `throw`.
207
+ - `protocol`: `sync` or `async`.
208
+ - `method`: `next`, `return`, or `throw`.
209
+ - `arguments`: the iterator method arguments.
210
+ - `value`: yielded or returned values.
211
+ - `thrown`: thrown values.
212
+ - `callIndex`, `iteratorIndex`, and `index`: related call and iterator event
213
+ positions.
214
+
215
+ ## Protocol Doubles
216
+
217
+ Use protocol doubles when the dependency itself is an iterator, iterable, or
218
+ disposable object rather than a function that returns one.
219
+
220
+ ```ts
221
+ const values = testIterator.yields([ 'created', 'updated' ]);
222
+
223
+ values.next();
224
+
225
+ scope.assert(doubleUsage.iterated, values);
226
+ scope.assert(doubleUsage.yieldedExactly, values, [ 'created' ]);
227
+ ```
228
+
229
+ `testIterator` creates one consumable well-formed iterator. It works with
230
+ `for...of`, exposes platform iterator helpers when the runtime provides them,
231
+ and records `next`, `return`, and `throw` through method doubles.
232
+
233
+ ```ts
234
+ const source = testIterable.yields([ 'created', 'updated' ]);
235
+
236
+ [ ...source ];
237
+ [ ...source ];
238
+
239
+ scope.assert(doubleUsage.yieldedExactly, source, [
240
+ 'created',
241
+ 'updated',
242
+ 'created',
243
+ 'updated'
244
+ ]);
245
+ ```
246
+
247
+ `testIterable` creates a reusable iterable. Each `[Symbol.iterator]()` call
248
+ returns a fresh well-formed iterator. Async variants mirror these shapes with
249
+ `for await...of`.
250
+
251
+ Disposable protocol methods are inspectable doubles too:
252
+
253
+ ```ts
254
+ const resource = testDisposable({
255
+ dispose: { fallback: rule.throws(new Error('expected')) }
256
+ });
257
+
258
+ using value = resource;
259
+
260
+ scope.assert(doubleUsage.disposedOnce, resource);
261
+ scope.assert(doubleUsage.calledOnce, resource.dispose);
262
+ ```
263
+
264
+ `testAsyncDisposable` installs `[Symbol.asyncDispose]()` for `await using`,
265
+ exposes `.asyncDispose` for inspection, and defaults to resolving `undefined`.
266
+
267
+ ## Assertions
268
+
269
+ `doubleUsage` contains assertion references for Overkill's engine-owned
270
+ assertion context:
271
+
272
+ ```ts
273
+ test('saves a user', (scope) => {
274
+ const saveUser = testDouble.returns<SaveUser>(true);
275
+
276
+ saveUser({ id: '42', name: 'Ada' });
277
+
278
+ scope.assert(doubleUsage.calledOnceWith, saveUser, [ { id: '42' } ]);
279
+
280
+ return scope.assert.collect();
281
+ });
282
+ ```
283
+
284
+ Argument assertions always receive one `args` tuple array.
285
+
286
+ - `*With`: partial-deep matching with exact arity.
287
+ - `*WithPrefix`: partial-deep matching on the argument prefix. The tuple must not be empty.
288
+ - `*WithExactly`: exact-deep matching with exact arity. These assertions are positive only.
289
+
290
+ Examples:
291
+
292
+ ```ts
293
+ scope.assert(doubleUsage.calledWith, saveUser, [ { id: '42' } ]);
294
+ scope.assert(doubleUsage.calledWithPrefix, writeMetric, [ 'signup' ]);
295
+ scope.assert(doubleUsage.calledWithExactly, saveUser, [ { id: '42', name: 'Ada' } ]);
296
+ scope.assert(doubleUsage.calledWith, ping, []);
297
+ ```
298
+
299
+ ### Counts
300
+
301
+ - `doubleUsage.interacted(double)`: at least one call or construction.
302
+ - `doubleUsage.notInteracted(double)`: no calls or constructions.
303
+ - `doubleUsage.interactionCount(double, count)`: exact call plus construction count.
304
+ - `doubleUsage.interactedOnce(double)`: exactly one call or construction.
305
+ - `doubleUsage.called(double)`: at least one call.
306
+ - `doubleUsage.notCalled(double)`: no calls.
307
+ - `doubleUsage.callCount(double, count)`: exact call count.
308
+ - `doubleUsage.calledOnce(double)`: exactly one call.
309
+ - `doubleUsage.constructed(double)`: at least one construction.
310
+ - `doubleUsage.notConstructed(double)`: no constructions.
311
+ - `doubleUsage.constructionCount(double, count)`: exact construction count.
312
+ - `doubleUsage.constructedOnce(double)`: exactly one construction.
313
+ - `doubleUsage.disposed(disposable)`: at least one disposal.
314
+ - `doubleUsage.notDisposed(disposable)`: no disposal.
315
+ - `doubleUsage.disposeCount(disposable, count)`: exact disposal count.
316
+ - `doubleUsage.disposedOnce(disposable)`: exactly one disposal.
317
+ - `doubleUsage.disposeOrder([a, b, ...])`: disposal order.
318
+ - `doubleUsage.iterated(double)`: at least one tracked iterator event.
319
+ - `doubleUsage.notIterated(double)`: no tracked iterator events.
320
+ - `doubleUsage.iteratorEventCount(double, count)`: exact tracked iterator event
321
+ count.
322
+ - `doubleUsage.yieldCount(double, count)`: exact yielded value count.
323
+ - `doubleUsage.yieldedExactly(double, values)`: exact yielded values across all
324
+ tracked iterators in event order.
325
+
326
+ ### Any Matching Usage
327
+
328
+ - `doubleUsage.interactedWith(double, args)`
329
+ - `doubleUsage.interactedWithPrefix(double, args)`
330
+ - `doubleUsage.interactedWithExactly(double, args)`
331
+ - `doubleUsage.calledWith(double, args)`
332
+ - `doubleUsage.calledWithPrefix(double, args)`
333
+ - `doubleUsage.calledWithExactly(double, args)`
334
+ - `doubleUsage.constructedWith(double, args)`
335
+ - `doubleUsage.constructedWithPrefix(double, args)`
336
+ - `doubleUsage.constructedWithExactly(double, args)`
337
+
338
+ ### Negative Matching Usage
339
+
340
+ - `doubleUsage.notInteractedWith(double, args)`
341
+ - `doubleUsage.notInteractedWithPrefix(double, args)`
342
+ - `doubleUsage.notCalledWith(double, args)`
343
+ - `doubleUsage.notCalledWithPrefix(double, args)`
344
+ - `doubleUsage.notConstructedWith(double, args)`
345
+ - `doubleUsage.notConstructedWithPrefix(double, args)`
346
+
347
+ There are no negative `*WithExactly` assertions. Use `not*With` or
348
+ `not*WithPrefix` for negative argument checks.
349
+
350
+ ### Once Matching Usage
351
+
352
+ These assertions require exactly one relevant event, then check its arguments:
353
+
354
+ - `doubleUsage.interactedOnceWith(double, args)`
355
+ - `doubleUsage.interactedOnceWithPrefix(double, args)`
356
+ - `doubleUsage.interactedOnceWithExactly(double, args)`
357
+ - `doubleUsage.calledOnceWith(double, args)`
358
+ - `doubleUsage.calledOnceWithPrefix(double, args)`
359
+ - `doubleUsage.calledOnceWithExactly(double, args)`
360
+ - `doubleUsage.constructedOnceWith(double, args)`
361
+ - `doubleUsage.constructedOnceWithPrefix(double, args)`
362
+ - `doubleUsage.constructedOnceWithExactly(double, args)`
363
+
364
+ ### Last Matching Usage
365
+
366
+ - `doubleUsage.lastInteractedWith(double, args)`
367
+ - `doubleUsage.lastInteractedWithPrefix(double, args)`
368
+ - `doubleUsage.lastInteractedWithExactly(double, args)`
369
+ - `doubleUsage.lastCalledWith(double, args)`
370
+ - `doubleUsage.lastCalledWithPrefix(double, args)`
371
+ - `doubleUsage.lastCalledWithExactly(double, args)`
372
+ - `doubleUsage.lastConstructedWith(double, args)`
373
+ - `doubleUsage.lastConstructedWithPrefix(double, args)`
374
+ - `doubleUsage.lastConstructedWithExactly(double, args)`
375
+
376
+ ### Indexed Matching Usage
377
+
378
+ Indexes are zero-based:
379
+
380
+ - `doubleUsage.nthInteractionWith(double, index, args)`
381
+ - `doubleUsage.nthInteractionWithPrefix(double, index, args)`
382
+ - `doubleUsage.nthInteractionWithExactly(double, index, args)`
383
+ - `doubleUsage.nthCallWith(double, index, args)`
384
+ - `doubleUsage.nthCallWithPrefix(double, index, args)`
385
+ - `doubleUsage.nthCallWithExactly(double, index, args)`
386
+ - `doubleUsage.nthConstructionWith(double, index, args)`
387
+ - `doubleUsage.nthConstructionWithPrefix(double, index, args)`
388
+ - `doubleUsage.nthConstructionWithExactly(double, index, args)`
389
+
390
+ ### Order
391
+
392
+ Order assertions compare usage across doubles:
393
+
394
+ ```ts
395
+ scope.assert(doubleUsage.callOrder, [ loadUser, saveUser, publishEvent ]);
396
+ ```
397
+
398
+ - `doubleUsage.interactionOrder([first, second, ...])`
399
+ - `doubleUsage.callOrder([first, second, ...])`
400
+ - `doubleUsage.constructionOrder([first, second, ...])`
401
+
402
+ The list must contain at least two doubles. Each double must have at least one
403
+ relevant event. For each adjacent pair, all relevant events on the previous
404
+ double must happen before any relevant event on the next double.
405
+
406
+ Order is tracked inside the doubles package. Resetting a double clears its
407
+ public history, but it does not reset the hidden chronology used for
408
+ cross-double order assertions.
409
+
410
+ ## Types
411
+
412
+ Exported types:
413
+
414
+ - `TestDouble<Signature>`: a function or constructor with history attached.
415
+ - `TestDoubleFactory`: the `testDouble` factory shape.
416
+ - `DoubleHistory<Signature>`: the introspection API attached to each double.
417
+ - `DoubleInvocation<Arguments>`: invocation data passed to answer callbacks.
418
+ - `DoubleCall<Arguments, ReturnValue, ThisValue>`: a recorded function call.
419
+ - `DoubleConstruction<Arguments, Instance>`: a recorded construction.
420
+ - `DoubleInteraction`: a call or construction record.
421
+ - `DoubleResult<Value>`: a returned or thrown result.
422
+ - `DoubleReturnedResult<Value>`: a returned result.
423
+ - `DoubleThrownResult`: a thrown result.
424
+ - `RuleFactory`: the `rule` namespace shape.
425
+ - `DoubleUsageAssertions`: the `doubleUsage` namespace shape.
package/sbom.cdx.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
3
+ "bomFormat": "CycloneDX",
4
+ "specVersion": "1.6",
5
+ "version": 1,
6
+ "metadata": {
7
+ "tools": {
8
+ "components": [
9
+ {
10
+ "type": "application",
11
+ "name": "packtory",
12
+ "version": "0.0.78"
13
+ }
14
+ ]
15
+ },
16
+ "component": {
17
+ "type": "library",
18
+ "name": "@overkill-dev/doubles",
19
+ "version": "0.0.2",
20
+ "bom-ref": "pkg:npm/@overkill-dev/doubles@0.0.2",
21
+ "purl": "pkg:npm/@overkill-dev/doubles@0.0.2"
22
+ }
23
+ },
24
+ "components": [],
25
+ "dependencies": [
26
+ {
27
+ "ref": "pkg:npm/@overkill-dev/doubles@0.0.2"
28
+ }
29
+ ]
30
+ }