bupkis 0.2.0 → 0.4.0
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/CHANGELOG.md +27 -0
- package/README.md +35 -11
- package/dist/commonjs/assertion/assertion-async.d.ts +2 -1
- package/dist/commonjs/assertion/assertion-async.d.ts.map +1 -1
- package/dist/commonjs/assertion/assertion-async.js +84 -2
- package/dist/commonjs/assertion/assertion-async.js.map +1 -1
- package/dist/commonjs/assertion/assertion-sync.d.ts +1 -1
- package/dist/commonjs/assertion/assertion-sync.d.ts.map +1 -1
- package/dist/commonjs/assertion/assertion-sync.js +5 -1
- package/dist/commonjs/assertion/assertion-sync.js.map +1 -1
- package/dist/commonjs/assertion/assertion-types.d.ts +6 -2
- package/dist/commonjs/assertion/assertion-types.d.ts.map +1 -1
- package/dist/commonjs/assertion/assertion.d.ts +1 -1
- package/dist/commonjs/assertion/assertion.d.ts.map +1 -1
- package/dist/commonjs/assertion/assertion.js +1 -14
- package/dist/commonjs/assertion/assertion.js.map +1 -1
- package/dist/commonjs/assertion/impl/async.d.ts +122 -21
- package/dist/commonjs/assertion/impl/async.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/async.js +118 -90
- package/dist/commonjs/assertion/impl/async.js.map +1 -1
- package/dist/commonjs/assertion/impl/callback.d.ts +104 -0
- package/dist/commonjs/assertion/impl/callback.d.ts.map +1 -0
- package/dist/commonjs/assertion/impl/callback.js +694 -0
- package/dist/commonjs/assertion/impl/callback.js.map +1 -0
- package/dist/commonjs/assertion/impl/index.d.ts +1 -1
- package/dist/commonjs/assertion/impl/index.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/index.js.map +1 -1
- package/dist/commonjs/assertion/impl/sync-basic.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/sync-basic.js +1 -1
- package/dist/commonjs/assertion/impl/sync-basic.js.map +1 -1
- package/dist/commonjs/assertion/impl/sync-collection.d.ts +1 -1
- package/dist/commonjs/assertion/impl/sync-collection.js +3 -3
- package/dist/commonjs/assertion/impl/sync-collection.js.map +1 -1
- package/dist/commonjs/assertion/impl/sync-esoteric.js +1 -1
- package/dist/commonjs/assertion/impl/sync-esoteric.js.map +1 -1
- package/dist/commonjs/assertion/impl/sync-parametric.d.ts +22 -28
- package/dist/commonjs/assertion/impl/sync-parametric.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/sync-parametric.js +35 -50
- package/dist/commonjs/assertion/impl/sync-parametric.js.map +1 -1
- package/dist/commonjs/assertion/impl/sync.d.ts +68 -30
- package/dist/commonjs/assertion/impl/sync.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/sync.js +4 -1
- package/dist/commonjs/assertion/impl/sync.js.map +1 -1
- package/dist/commonjs/bootstrap.d.ts +147 -52
- package/dist/commonjs/bootstrap.d.ts.map +1 -1
- package/dist/commonjs/bootstrap.js +2 -3
- package/dist/commonjs/bootstrap.js.map +1 -1
- package/dist/commonjs/constant.d.ts +1 -1
- package/dist/commonjs/constant.d.ts.map +1 -1
- package/dist/commonjs/constant.js +8 -1
- package/dist/commonjs/constant.js.map +1 -1
- package/dist/commonjs/error.d.ts +22 -2
- package/dist/commonjs/error.d.ts.map +1 -1
- package/dist/commonjs/error.js +44 -4
- package/dist/commonjs/error.js.map +1 -1
- package/dist/commonjs/expect.d.ts.map +1 -1
- package/dist/commonjs/expect.js +1 -1
- package/dist/commonjs/expect.js.map +1 -1
- package/dist/commonjs/guards.d.ts +96 -5
- package/dist/commonjs/guards.d.ts.map +1 -1
- package/dist/commonjs/guards.js +104 -25
- package/dist/commonjs/guards.js.map +1 -1
- package/dist/commonjs/index.d.ts +146 -51
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/schema.d.ts +84 -18
- package/dist/commonjs/schema.d.ts.map +1 -1
- package/dist/commonjs/schema.js +107 -22
- package/dist/commonjs/schema.js.map +1 -1
- package/dist/commonjs/types.d.ts +171 -9
- package/dist/commonjs/types.d.ts.map +1 -1
- package/dist/commonjs/use.d.ts.map +1 -1
- package/dist/commonjs/use.js +15 -1
- package/dist/commonjs/use.js.map +1 -1
- package/dist/commonjs/util.d.ts +66 -50
- package/dist/commonjs/util.d.ts.map +1 -1
- package/dist/commonjs/util.js +169 -156
- package/dist/commonjs/util.js.map +1 -1
- package/dist/commonjs/value-to-schema.d.ts +122 -0
- package/dist/commonjs/value-to-schema.d.ts.map +1 -0
- package/dist/commonjs/value-to-schema.js +329 -0
- package/dist/commonjs/value-to-schema.js.map +1 -0
- package/dist/esm/assertion/assertion-async.d.ts +2 -1
- package/dist/esm/assertion/assertion-async.d.ts.map +1 -1
- package/dist/esm/assertion/assertion-async.js +85 -3
- package/dist/esm/assertion/assertion-async.js.map +1 -1
- package/dist/esm/assertion/assertion-sync.d.ts +1 -1
- package/dist/esm/assertion/assertion-sync.d.ts.map +1 -1
- package/dist/esm/assertion/assertion-sync.js +6 -2
- package/dist/esm/assertion/assertion-sync.js.map +1 -1
- package/dist/esm/assertion/assertion-types.d.ts +6 -2
- package/dist/esm/assertion/assertion-types.d.ts.map +1 -1
- package/dist/esm/assertion/assertion.d.ts +1 -1
- package/dist/esm/assertion/assertion.d.ts.map +1 -1
- package/dist/esm/assertion/assertion.js +1 -14
- package/dist/esm/assertion/assertion.js.map +1 -1
- package/dist/esm/assertion/impl/async.d.ts +122 -21
- package/dist/esm/assertion/impl/async.d.ts.map +1 -1
- package/dist/esm/assertion/impl/async.js +118 -90
- package/dist/esm/assertion/impl/async.js.map +1 -1
- package/dist/esm/assertion/impl/callback.d.ts +104 -0
- package/dist/esm/assertion/impl/callback.d.ts.map +1 -0
- package/dist/esm/assertion/impl/callback.js +691 -0
- package/dist/esm/assertion/impl/callback.js.map +1 -0
- package/dist/esm/assertion/impl/index.d.ts +1 -1
- package/dist/esm/assertion/impl/index.d.ts.map +1 -1
- package/dist/esm/assertion/impl/index.js +1 -1
- package/dist/esm/assertion/impl/index.js.map +1 -1
- package/dist/esm/assertion/impl/sync-basic.d.ts.map +1 -1
- package/dist/esm/assertion/impl/sync-basic.js +2 -2
- package/dist/esm/assertion/impl/sync-basic.js.map +1 -1
- package/dist/esm/assertion/impl/sync-collection.d.ts +1 -1
- package/dist/esm/assertion/impl/sync-collection.js +3 -3
- package/dist/esm/assertion/impl/sync-collection.js.map +1 -1
- package/dist/esm/assertion/impl/sync-esoteric.js +2 -2
- package/dist/esm/assertion/impl/sync-esoteric.js.map +1 -1
- package/dist/esm/assertion/impl/sync-parametric.d.ts +22 -28
- package/dist/esm/assertion/impl/sync-parametric.d.ts.map +1 -1
- package/dist/esm/assertion/impl/sync-parametric.js +36 -51
- package/dist/esm/assertion/impl/sync-parametric.js.map +1 -1
- package/dist/esm/assertion/impl/sync.d.ts +68 -30
- package/dist/esm/assertion/impl/sync.d.ts.map +1 -1
- package/dist/esm/assertion/impl/sync.js +3 -1
- package/dist/esm/assertion/impl/sync.js.map +1 -1
- package/dist/esm/bootstrap.d.ts +147 -52
- package/dist/esm/bootstrap.d.ts.map +1 -1
- package/dist/esm/bootstrap.js +1 -2
- package/dist/esm/bootstrap.js.map +1 -1
- package/dist/esm/constant.d.ts +1 -1
- package/dist/esm/constant.d.ts.map +1 -1
- package/dist/esm/constant.js +7 -0
- package/dist/esm/constant.js.map +1 -1
- package/dist/esm/error.d.ts +22 -2
- package/dist/esm/error.d.ts.map +1 -1
- package/dist/esm/error.js +43 -4
- package/dist/esm/error.js.map +1 -1
- package/dist/esm/expect.d.ts.map +1 -1
- package/dist/esm/expect.js +2 -2
- package/dist/esm/expect.js.map +1 -1
- package/dist/esm/guards.d.ts +96 -5
- package/dist/esm/guards.d.ts.map +1 -1
- package/dist/esm/guards.js +98 -21
- package/dist/esm/guards.js.map +1 -1
- package/dist/esm/index.d.ts +146 -51
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/schema.d.ts +84 -18
- package/dist/esm/schema.d.ts.map +1 -1
- package/dist/esm/schema.js +107 -22
- package/dist/esm/schema.js.map +1 -1
- package/dist/esm/types.d.ts +171 -9
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/use.d.ts.map +1 -1
- package/dist/esm/use.js +15 -1
- package/dist/esm/use.js.map +1 -1
- package/dist/esm/util.d.ts +66 -50
- package/dist/esm/util.d.ts.map +1 -1
- package/dist/esm/util.js +153 -154
- package/dist/esm/util.js.map +1 -1
- package/dist/esm/value-to-schema.d.ts +122 -0
- package/dist/esm/value-to-schema.d.ts.map +1 -0
- package/dist/esm/value-to-schema.js +325 -0
- package/dist/esm/value-to-schema.js.map +1 -0
- package/package.json +16 -13
- package/src/assertion/assertion-async.ts +113 -3
- package/src/assertion/assertion-sync.ts +5 -2
- package/src/assertion/assertion-types.ts +14 -4
- package/src/assertion/assertion.ts +2 -17
- package/src/assertion/impl/async.ts +137 -93
- package/src/assertion/impl/callback.ts +882 -0
- package/src/assertion/impl/index.ts +1 -1
- package/src/assertion/impl/sync-basic.ts +5 -2
- package/src/assertion/impl/sync-collection.ts +3 -3
- package/src/assertion/impl/sync-esoteric.ts +2 -2
- package/src/assertion/impl/sync-parametric.ts +47 -54
- package/src/assertion/impl/sync.ts +3 -0
- package/src/bootstrap.ts +1 -2
- package/src/constant.ts +10 -0
- package/src/error.ts +57 -3
- package/src/expect.ts +6 -2
- package/src/guards.ts +125 -18
- package/src/index.ts +3 -0
- package/src/schema.ts +121 -23
- package/src/types.ts +205 -10
- package/src/use.ts +22 -0
- package/src/util.ts +168 -223
- package/src/value-to-schema.ts +489 -0
|
@@ -0,0 +1,882 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Callback-based assertion implementations.
|
|
3
|
+
*
|
|
4
|
+
* For callback invocation, error handling, and value validation in both
|
|
5
|
+
* synchronous and asynchronous contexts.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { inspect } from 'node:util';
|
|
11
|
+
import { z } from 'zod/v4';
|
|
12
|
+
|
|
13
|
+
import { isA, isNonNullObject, isString } from '../../guards.js';
|
|
14
|
+
import { ConstructibleSchema, FunctionSchema } from '../../schema.js';
|
|
15
|
+
import {
|
|
16
|
+
valueToSchema,
|
|
17
|
+
type ValueToSchemaOptions,
|
|
18
|
+
valueToSchemaOptionsForDeepEqual,
|
|
19
|
+
valueToSchemaOptionsForSatisfies,
|
|
20
|
+
} from '../../value-to-schema.js';
|
|
21
|
+
import { createAssertion, createAsyncAssertion } from '../create.js';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Creates a standardized error object for when a callback or nodeback is not
|
|
25
|
+
* called.
|
|
26
|
+
*
|
|
27
|
+
* @param type - The type of callback ('callback' or 'nodeback')
|
|
28
|
+
* @returns Error object with consistent structure for sync assertions
|
|
29
|
+
*/
|
|
30
|
+
/* c8 ignore next */
|
|
31
|
+
const createNotCalledError = (type: 'callback' | 'nodeback') => ({
|
|
32
|
+
actual: 'not called',
|
|
33
|
+
expected: `${type} to be called`,
|
|
34
|
+
message: `Expected ${type} to be called, but it was not called`,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Creates a standardized error object for when a callback or nodeback is not
|
|
39
|
+
* called in async contexts. Uses consistent field naming for async assertions.
|
|
40
|
+
*
|
|
41
|
+
* @param type - The type of callback ('callback' or 'nodeback')
|
|
42
|
+
* @returns Error object with consistent structure for async assertions
|
|
43
|
+
*/
|
|
44
|
+
/* c8 ignore next */
|
|
45
|
+
const createAsyncNotCalledError = (type: 'callback' | 'nodeback') => ({
|
|
46
|
+
actual: `${type} not called`,
|
|
47
|
+
expected: `${type} to be called`,
|
|
48
|
+
message: `Expected ${type} to be called, but it was not`,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates error objects for nodeback error state mismatches in sync contexts.
|
|
53
|
+
* Handles cases where an error is expected but not present, or vice versa.
|
|
54
|
+
*
|
|
55
|
+
* @param hasError - Whether the nodeback was called with an error
|
|
56
|
+
* @param expectError - Whether an error was expected
|
|
57
|
+
* @param error - The actual error value (if any)
|
|
58
|
+
* @returns Error object if there's a mismatch, undefined if the state matches
|
|
59
|
+
* expectations
|
|
60
|
+
*/
|
|
61
|
+
const createErrorMismatchError = (
|
|
62
|
+
hasError: boolean,
|
|
63
|
+
expectError: boolean,
|
|
64
|
+
error?: unknown,
|
|
65
|
+
) => {
|
|
66
|
+
if (hasError && !expectError) {
|
|
67
|
+
return {
|
|
68
|
+
actual: 'called with error',
|
|
69
|
+
expected: 'called without error',
|
|
70
|
+
message: `Expected nodeback to be called without error, but it was called with error: ${inspect(
|
|
71
|
+
error,
|
|
72
|
+
{ depth: 2 },
|
|
73
|
+
)}`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (!hasError && expectError) {
|
|
77
|
+
return {
|
|
78
|
+
actual: 'called without error',
|
|
79
|
+
expected: 'called with error',
|
|
80
|
+
message:
|
|
81
|
+
'Expected nodeback to be called with an error, but it was called without error',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Creates error objects for nodeback error state mismatches in async contexts.
|
|
89
|
+
* Handles cases where an error is expected but not present, or vice versa. Uses
|
|
90
|
+
* consistent field naming and messaging for async assertions.
|
|
91
|
+
*
|
|
92
|
+
* @param hasError - Whether the nodeback was called with an error
|
|
93
|
+
* @param expectError - Whether an error was expected
|
|
94
|
+
* @param error - The actual error value (if any)
|
|
95
|
+
* @returns Error object if there's a mismatch, undefined if the state matches
|
|
96
|
+
* expectations
|
|
97
|
+
*/
|
|
98
|
+
const createAsyncErrorMismatchError = (
|
|
99
|
+
hasError: boolean,
|
|
100
|
+
expectError: boolean,
|
|
101
|
+
error?: unknown,
|
|
102
|
+
) => {
|
|
103
|
+
if (hasError && !expectError) {
|
|
104
|
+
return {
|
|
105
|
+
actual: 'called with error',
|
|
106
|
+
expected: 'called without error',
|
|
107
|
+
message: `Expected nodeback to be called without error, but it was called with error: ${inspect(
|
|
108
|
+
error,
|
|
109
|
+
{ depth: 2 },
|
|
110
|
+
)}`,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (!hasError && expectError) {
|
|
114
|
+
return {
|
|
115
|
+
actual: 'called without error',
|
|
116
|
+
expected: 'called with error',
|
|
117
|
+
message:
|
|
118
|
+
'Expected nodeback to be called with an error, but it was called without an error',
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return undefined;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Creates a standardized error object for exact value comparison failures. Used
|
|
126
|
+
* when a callback/nodeback is called with a value that doesn't match the
|
|
127
|
+
* expected value using Object.is() strict equality.
|
|
128
|
+
*
|
|
129
|
+
* @param actual - The actual value the callback was called with
|
|
130
|
+
* @param expected - The expected value
|
|
131
|
+
* @param callbackType - The type of callback for error messaging
|
|
132
|
+
* @returns Error object with formatted comparison message
|
|
133
|
+
*/
|
|
134
|
+
const createValueMismatchError = (
|
|
135
|
+
actual: unknown,
|
|
136
|
+
expected: unknown,
|
|
137
|
+
callbackType: 'callback' | 'nodeback',
|
|
138
|
+
) => ({
|
|
139
|
+
actual,
|
|
140
|
+
expected,
|
|
141
|
+
message: `Expected ${callbackType} to be called with exactly ${inspect(
|
|
142
|
+
expected,
|
|
143
|
+
{ depth: 2 },
|
|
144
|
+
)}, but it was called with ${inspect(actual, { depth: 2 })}`,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Creates a Zod schema for validating error parameters in callback assertions.
|
|
149
|
+
* Handles string literals, RegExp patterns, and object structures for error
|
|
150
|
+
* matching.
|
|
151
|
+
*
|
|
152
|
+
* @param param - The error parameter to create a schema for
|
|
153
|
+
* @returns Zod schema that can validate the error against the parameter
|
|
154
|
+
* @throws TypeError if the parameter type is not supported
|
|
155
|
+
*/
|
|
156
|
+
const createErrorSchema = (param: unknown): z.ZodType => {
|
|
157
|
+
if (isString(param)) {
|
|
158
|
+
return z
|
|
159
|
+
.looseObject({
|
|
160
|
+
message: z.coerce.string().pipe(z.literal(param)),
|
|
161
|
+
})
|
|
162
|
+
.or(z.coerce.string().pipe(z.literal(param)));
|
|
163
|
+
}
|
|
164
|
+
if (isA(param, RegExp)) {
|
|
165
|
+
return z
|
|
166
|
+
.looseObject({
|
|
167
|
+
message: z.coerce.string().regex(param),
|
|
168
|
+
})
|
|
169
|
+
.or(z.coerce.string().regex(param));
|
|
170
|
+
}
|
|
171
|
+
if (isNonNullObject(param)) {
|
|
172
|
+
return valueToSchema(param, valueToSchemaOptionsForDeepEqual);
|
|
173
|
+
}
|
|
174
|
+
throw new TypeError(
|
|
175
|
+
`Invalid parameter schema: ${inspect(param, { depth: 2 })}`,
|
|
176
|
+
);
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Validates a value against a parameter using valueToSchema with specified
|
|
181
|
+
* options. Centralizes the common pattern of schema creation and validation
|
|
182
|
+
* used across many callback assertions.
|
|
183
|
+
*
|
|
184
|
+
* @param value - The value to validate
|
|
185
|
+
* @param param - The parameter to validate against
|
|
186
|
+
* @param options - Options to pass to valueToSchema
|
|
187
|
+
* @returns Undefined if validation succeeds, ZodError if validation fails
|
|
188
|
+
*/
|
|
189
|
+
const validateValue = (
|
|
190
|
+
value: unknown,
|
|
191
|
+
param: unknown,
|
|
192
|
+
options: ValueToSchemaOptions = {},
|
|
193
|
+
) => {
|
|
194
|
+
const schema = valueToSchema(param, options);
|
|
195
|
+
const result = schema.safeParse(value);
|
|
196
|
+
return result.success ? undefined : result.error;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Traps the invocation of a single-parameter callback function for synchronous
|
|
201
|
+
* testing. Executes the provided function with a callback and captures whether
|
|
202
|
+
* it was called, what arguments it received, and any errors thrown during
|
|
203
|
+
* execution.
|
|
204
|
+
*
|
|
205
|
+
* @param fn - The function to execute that should call the provided callback
|
|
206
|
+
* @returns Object containing invocation details: args, called, error, and value
|
|
207
|
+
*/
|
|
208
|
+
const trapCallbackInvocation = (fn: (...args: unknown[]) => unknown) => {
|
|
209
|
+
let called = false;
|
|
210
|
+
let error: unknown;
|
|
211
|
+
let value: unknown;
|
|
212
|
+
let args: unknown[] = [];
|
|
213
|
+
|
|
214
|
+
const callback = (...cbArgs: unknown[]) => {
|
|
215
|
+
called = true;
|
|
216
|
+
args = cbArgs;
|
|
217
|
+
if (cbArgs.length >= 1) {
|
|
218
|
+
value = cbArgs[0];
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
fn(callback);
|
|
224
|
+
} catch (thrownError) {
|
|
225
|
+
error = thrownError;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return { args, called, error, value };
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Traps the invocation of a nodeback (error-first callback) function for
|
|
233
|
+
* synchronous testing. Executes the provided function with a nodeback and
|
|
234
|
+
* captures whether it was called, what arguments it received, and any errors
|
|
235
|
+
* thrown during execution.
|
|
236
|
+
*
|
|
237
|
+
* @param fn - The function to execute that should call the provided nodeback
|
|
238
|
+
* @returns Object containing invocation details: args, called, error, and value
|
|
239
|
+
*/
|
|
240
|
+
const trapNodebackInvocation = (fn: (...args: unknown[]) => unknown) => {
|
|
241
|
+
let called = false;
|
|
242
|
+
let error: unknown;
|
|
243
|
+
let value: unknown;
|
|
244
|
+
let args: unknown[] = [];
|
|
245
|
+
|
|
246
|
+
const nodeback = (err: unknown, val?: unknown) => {
|
|
247
|
+
called = true;
|
|
248
|
+
args = [err, val];
|
|
249
|
+
error = err;
|
|
250
|
+
value = val;
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
fn(nodeback);
|
|
255
|
+
} catch (thrownError) {
|
|
256
|
+
error = thrownError;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return { args, called, error, value };
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Traps the invocation of a single-parameter callback function for asynchronous
|
|
264
|
+
* testing. Returns a Promise that resolves with invocation details once the
|
|
265
|
+
* callback is called or an error occurs. Uses a Proxy to catch errors during
|
|
266
|
+
* function execution.
|
|
267
|
+
*
|
|
268
|
+
* @param fn - The function to execute that should call the provided callback
|
|
269
|
+
* @returns Promise resolving to object with invocation details: args, called,
|
|
270
|
+
* error, and value
|
|
271
|
+
*/
|
|
272
|
+
const trapAsyncCallbackInvocation = async (
|
|
273
|
+
fn: (...args: unknown[]) => unknown,
|
|
274
|
+
) => {
|
|
275
|
+
return new Promise<{
|
|
276
|
+
args: unknown[];
|
|
277
|
+
called: boolean;
|
|
278
|
+
error: unknown;
|
|
279
|
+
value: unknown;
|
|
280
|
+
}>((resolve, _reject) => {
|
|
281
|
+
let called = false;
|
|
282
|
+
let error: unknown;
|
|
283
|
+
let value: unknown;
|
|
284
|
+
let args: unknown[] = [];
|
|
285
|
+
|
|
286
|
+
const callback = (...cbArgs: unknown[]) => {
|
|
287
|
+
called = true;
|
|
288
|
+
args = cbArgs;
|
|
289
|
+
if (cbArgs.length >= 1) {
|
|
290
|
+
value = cbArgs[0];
|
|
291
|
+
}
|
|
292
|
+
resolve({ args, called, error, value });
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const proxiedFn = new Proxy(fn, {
|
|
296
|
+
apply(target, thisArg, argumentsList) {
|
|
297
|
+
try {
|
|
298
|
+
return Reflect.apply(target, thisArg, argumentsList);
|
|
299
|
+
} catch (thrownError) {
|
|
300
|
+
error = thrownError;
|
|
301
|
+
resolve({ args, called, error, value });
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
try {
|
|
307
|
+
proxiedFn(callback);
|
|
308
|
+
} catch (thrownError) {
|
|
309
|
+
error = thrownError;
|
|
310
|
+
resolve({ args, called, error, value });
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Traps the invocation of a nodeback (error-first callback) function for
|
|
317
|
+
* asynchronous testing. Returns a Promise that resolves with invocation details
|
|
318
|
+
* once the nodeback is called or an error occurs. Uses a Proxy to catch errors
|
|
319
|
+
* during function execution. Always resolves (never rejects) to allow assertion
|
|
320
|
+
* logic to handle error conditions.
|
|
321
|
+
*
|
|
322
|
+
* @param fn - The function to execute that should call the provided nodeback
|
|
323
|
+
* @returns Promise resolving to object with invocation details: args, called,
|
|
324
|
+
* error, and value
|
|
325
|
+
*/
|
|
326
|
+
const trapAsyncNodebackInvocation = async (
|
|
327
|
+
fn: (...args: unknown[]) => unknown,
|
|
328
|
+
) => {
|
|
329
|
+
return new Promise<{
|
|
330
|
+
args: unknown[];
|
|
331
|
+
called: boolean;
|
|
332
|
+
error: unknown;
|
|
333
|
+
value: unknown;
|
|
334
|
+
}>((resolve, _reject) => {
|
|
335
|
+
let called = false;
|
|
336
|
+
let error: unknown;
|
|
337
|
+
let value: unknown;
|
|
338
|
+
let args: unknown[] = [];
|
|
339
|
+
|
|
340
|
+
const nodeback = (err: unknown, val?: unknown) => {
|
|
341
|
+
called = true;
|
|
342
|
+
args = [err, val];
|
|
343
|
+
error = err;
|
|
344
|
+
value = val;
|
|
345
|
+
|
|
346
|
+
// Always resolve with the result data, don't reject on nodeback errors
|
|
347
|
+
// The assertion logic will check if error is truthy
|
|
348
|
+
resolve({ args, called, error, value });
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
const proxiedFn = new Proxy(fn, {
|
|
352
|
+
apply(target, thisArg, argumentsList) {
|
|
353
|
+
try {
|
|
354
|
+
return Reflect.apply(target, thisArg, argumentsList);
|
|
355
|
+
} catch (thrownError) {
|
|
356
|
+
error = thrownError;
|
|
357
|
+
resolve({ args, called, error, value });
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
try {
|
|
363
|
+
proxiedFn(nodeback);
|
|
364
|
+
} catch (thrownError) {
|
|
365
|
+
error = thrownError;
|
|
366
|
+
resolve({ args, called, error, value });
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
export const CallbackSyncAssertions = [
|
|
372
|
+
// Basic callback invocation - synchronous
|
|
373
|
+
createAssertion(
|
|
374
|
+
[FunctionSchema, ['to call callback', 'to invoke callback']],
|
|
375
|
+
(subject) => {
|
|
376
|
+
const { called } = trapCallbackInvocation(subject);
|
|
377
|
+
return called;
|
|
378
|
+
},
|
|
379
|
+
),
|
|
380
|
+
|
|
381
|
+
createAssertion(
|
|
382
|
+
[FunctionSchema, ['to call nodeback', 'to invoke nodeback']],
|
|
383
|
+
(subject) => {
|
|
384
|
+
const { called } = trapNodebackInvocation(subject);
|
|
385
|
+
return called;
|
|
386
|
+
},
|
|
387
|
+
),
|
|
388
|
+
|
|
389
|
+
// Callback with value - deep equality check
|
|
390
|
+
createAssertion(
|
|
391
|
+
[
|
|
392
|
+
FunctionSchema,
|
|
393
|
+
['to call callback with', 'to invoke callback with'],
|
|
394
|
+
z.unknown(),
|
|
395
|
+
],
|
|
396
|
+
(subject, param) => {
|
|
397
|
+
const { called, value } = trapCallbackInvocation(subject);
|
|
398
|
+
/* c8 ignore next */
|
|
399
|
+
if (!called) {
|
|
400
|
+
return createNotCalledError('callback');
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return validateValue(value, param, valueToSchemaOptionsForDeepEqual);
|
|
404
|
+
},
|
|
405
|
+
),
|
|
406
|
+
|
|
407
|
+
// Callback with exact value - strict equality check
|
|
408
|
+
createAssertion(
|
|
409
|
+
[
|
|
410
|
+
FunctionSchema,
|
|
411
|
+
[
|
|
412
|
+
'to call callback with exactly',
|
|
413
|
+
'to call callback with exact value',
|
|
414
|
+
'to invoke callback with exactly',
|
|
415
|
+
'to invoke callback with exact value',
|
|
416
|
+
],
|
|
417
|
+
z.unknown(),
|
|
418
|
+
],
|
|
419
|
+
(subject, expected) => {
|
|
420
|
+
const { called, value } = trapCallbackInvocation(subject);
|
|
421
|
+
/* c8 ignore next */
|
|
422
|
+
if (!called) {
|
|
423
|
+
return createNotCalledError('callback');
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (!Object.is(value, expected)) {
|
|
427
|
+
return createValueMismatchError(value, expected, 'callback');
|
|
428
|
+
}
|
|
429
|
+
},
|
|
430
|
+
),
|
|
431
|
+
|
|
432
|
+
// Nodeback with value - deep equality check
|
|
433
|
+
createAssertion(
|
|
434
|
+
[
|
|
435
|
+
FunctionSchema,
|
|
436
|
+
['to call nodeback with', 'to invoke nodeback with'],
|
|
437
|
+
z.unknown(),
|
|
438
|
+
],
|
|
439
|
+
(subject, param) => {
|
|
440
|
+
const { called, error, value } = trapNodebackInvocation(subject);
|
|
441
|
+
/* c8 ignore next */
|
|
442
|
+
if (!called) {
|
|
443
|
+
return createNotCalledError('nodeback');
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const errorResult = createErrorMismatchError(!!error, false, error);
|
|
447
|
+
if (errorResult) {
|
|
448
|
+
return errorResult;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return validateValue(value, param, valueToSchemaOptionsForDeepEqual);
|
|
452
|
+
},
|
|
453
|
+
),
|
|
454
|
+
|
|
455
|
+
// Nodeback with exact value - strict equality check
|
|
456
|
+
createAssertion(
|
|
457
|
+
[
|
|
458
|
+
FunctionSchema,
|
|
459
|
+
[
|
|
460
|
+
'to call nodeback with exactly',
|
|
461
|
+
'to call nodeback with exact value',
|
|
462
|
+
'to invoke nodeback with exactly',
|
|
463
|
+
'to invoke nodeback with exact value',
|
|
464
|
+
],
|
|
465
|
+
z.unknown(),
|
|
466
|
+
],
|
|
467
|
+
(subject, expected) => {
|
|
468
|
+
const { called, error, value } = trapNodebackInvocation(subject);
|
|
469
|
+
/* c8 ignore next */
|
|
470
|
+
if (!called) {
|
|
471
|
+
return createNotCalledError('nodeback');
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const errorResult = createErrorMismatchError(!!error, false, error);
|
|
475
|
+
if (errorResult) {
|
|
476
|
+
return errorResult;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (!Object.is(value, expected)) {
|
|
480
|
+
return createValueMismatchError(value, expected, 'nodeback');
|
|
481
|
+
}
|
|
482
|
+
},
|
|
483
|
+
),
|
|
484
|
+
|
|
485
|
+
// Nodeback with error - synchronous
|
|
486
|
+
createAssertion(
|
|
487
|
+
[
|
|
488
|
+
FunctionSchema,
|
|
489
|
+
['to call nodeback with error', 'to invoke nodeback with error'],
|
|
490
|
+
],
|
|
491
|
+
(subject) => {
|
|
492
|
+
const { called, error } = trapNodebackInvocation(subject);
|
|
493
|
+
/* c8 ignore next */
|
|
494
|
+
if (!called) {
|
|
495
|
+
return createNotCalledError('nodeback');
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return createErrorMismatchError(!!error, true, error);
|
|
499
|
+
},
|
|
500
|
+
),
|
|
501
|
+
|
|
502
|
+
// Nodeback with specific error class - synchronous
|
|
503
|
+
createAssertion(
|
|
504
|
+
[
|
|
505
|
+
FunctionSchema,
|
|
506
|
+
[
|
|
507
|
+
'to call nodeback with a',
|
|
508
|
+
'to call nodeback with an',
|
|
509
|
+
'to invoke nodeback with a',
|
|
510
|
+
'to invoke nodeback with an',
|
|
511
|
+
],
|
|
512
|
+
ConstructibleSchema,
|
|
513
|
+
],
|
|
514
|
+
(subject, ctor) => {
|
|
515
|
+
const { called, error } = trapNodebackInvocation(subject);
|
|
516
|
+
/* c8 ignore next */
|
|
517
|
+
if (!called) {
|
|
518
|
+
return createNotCalledError('nodeback');
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const errorResult = createErrorMismatchError(!!error, true, error);
|
|
522
|
+
if (errorResult) {
|
|
523
|
+
return errorResult;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
if (!isA(error, ctor)) {
|
|
527
|
+
return {
|
|
528
|
+
actual: error,
|
|
529
|
+
expected: `instance of ${ctor.name}`,
|
|
530
|
+
message: `Expected nodeback to be called with an instance of ${ctor.name}, but it was called with ${inspect(
|
|
531
|
+
error,
|
|
532
|
+
{ depth: 2 },
|
|
533
|
+
)}`,
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
),
|
|
538
|
+
|
|
539
|
+
// Nodeback with specific error pattern - synchronous
|
|
540
|
+
createAssertion(
|
|
541
|
+
[
|
|
542
|
+
FunctionSchema,
|
|
543
|
+
['to call nodeback with error', 'to invoke nodeback with error'],
|
|
544
|
+
z.union([z.string(), z.instanceof(RegExp), z.looseObject({})]),
|
|
545
|
+
],
|
|
546
|
+
(subject, param) => {
|
|
547
|
+
const { called, error } = trapNodebackInvocation(subject);
|
|
548
|
+
/* c8 ignore next */
|
|
549
|
+
if (!called) {
|
|
550
|
+
return createNotCalledError('nodeback');
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const errorResult = createErrorMismatchError(!!error, true, error);
|
|
554
|
+
if (errorResult) {
|
|
555
|
+
return errorResult;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const schema = createErrorSchema(param);
|
|
559
|
+
const result = schema.safeParse(error);
|
|
560
|
+
if (!result.success) {
|
|
561
|
+
return result.error;
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
),
|
|
565
|
+
|
|
566
|
+
// Callback satisfying pattern - partial matching
|
|
567
|
+
createAssertion(
|
|
568
|
+
[
|
|
569
|
+
FunctionSchema,
|
|
570
|
+
[
|
|
571
|
+
'to call callback with value satisfying',
|
|
572
|
+
'to invoke callback with value satisfying',
|
|
573
|
+
],
|
|
574
|
+
z.union([z.string(), z.instanceof(RegExp), z.looseObject({})]),
|
|
575
|
+
],
|
|
576
|
+
(subject, param) => {
|
|
577
|
+
const { called, value } = trapCallbackInvocation(subject);
|
|
578
|
+
/* c8 ignore next */
|
|
579
|
+
if (!called) {
|
|
580
|
+
return createNotCalledError('callback');
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return validateValue(value, param, valueToSchemaOptionsForSatisfies);
|
|
584
|
+
},
|
|
585
|
+
),
|
|
586
|
+
|
|
587
|
+
// Nodeback satisfying pattern - partial matching
|
|
588
|
+
createAssertion(
|
|
589
|
+
[
|
|
590
|
+
FunctionSchema,
|
|
591
|
+
[
|
|
592
|
+
'to call nodeback with value satisfying',
|
|
593
|
+
'to invoke nodeback with value satisfying',
|
|
594
|
+
],
|
|
595
|
+
z.union([z.string(), z.instanceof(RegExp), z.looseObject({})]),
|
|
596
|
+
],
|
|
597
|
+
(subject, param) => {
|
|
598
|
+
const { called, error, value } = trapNodebackInvocation(subject);
|
|
599
|
+
/* c8 ignore next */
|
|
600
|
+
if (!called) {
|
|
601
|
+
return createNotCalledError('nodeback');
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const errorResult = createErrorMismatchError(!!error, false, error);
|
|
605
|
+
if (errorResult) {
|
|
606
|
+
return errorResult;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return validateValue(value, param, valueToSchemaOptionsForSatisfies);
|
|
610
|
+
},
|
|
611
|
+
),
|
|
612
|
+
] as const;
|
|
613
|
+
|
|
614
|
+
export const CallbackAsyncAssertions = [
|
|
615
|
+
// Async versions
|
|
616
|
+
createAsyncAssertion(
|
|
617
|
+
[
|
|
618
|
+
FunctionSchema,
|
|
619
|
+
['to eventually call callback', 'to eventually invoke callback'],
|
|
620
|
+
],
|
|
621
|
+
async (subject) => {
|
|
622
|
+
const { called } = await trapAsyncCallbackInvocation(subject);
|
|
623
|
+
/* c8 ignore next */
|
|
624
|
+
if (!called) {
|
|
625
|
+
return {
|
|
626
|
+
actual: 'callback not called',
|
|
627
|
+
expected: 'callback to be called',
|
|
628
|
+
message: `Expected callback to be called, but it was not`,
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
},
|
|
632
|
+
),
|
|
633
|
+
|
|
634
|
+
createAsyncAssertion(
|
|
635
|
+
[
|
|
636
|
+
FunctionSchema,
|
|
637
|
+
['to eventually call nodeback', 'to eventually invoke nodeback'],
|
|
638
|
+
],
|
|
639
|
+
async (subject) => {
|
|
640
|
+
const { called } = await trapAsyncNodebackInvocation(subject);
|
|
641
|
+
/* c8 ignore next */
|
|
642
|
+
if (!called) {
|
|
643
|
+
return {
|
|
644
|
+
actual: 'nodeback not called',
|
|
645
|
+
expected: 'nodeback to be called',
|
|
646
|
+
message: `Expected nodeback to be called, but it was not`,
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
),
|
|
651
|
+
|
|
652
|
+
// Async callback with value - deep equality check
|
|
653
|
+
createAsyncAssertion(
|
|
654
|
+
[
|
|
655
|
+
FunctionSchema,
|
|
656
|
+
[
|
|
657
|
+
'to eventually call callback with',
|
|
658
|
+
'to eventually invoke callback with',
|
|
659
|
+
],
|
|
660
|
+
z.unknown(),
|
|
661
|
+
],
|
|
662
|
+
async (subject, param) => {
|
|
663
|
+
const { called, value } = await trapAsyncCallbackInvocation(subject);
|
|
664
|
+
/* c8 ignore next */
|
|
665
|
+
if (!called) {
|
|
666
|
+
return createAsyncNotCalledError('callback');
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
return validateValue(value, param, valueToSchemaOptionsForDeepEqual);
|
|
670
|
+
},
|
|
671
|
+
),
|
|
672
|
+
|
|
673
|
+
// Async callback with exact value - strict equality check
|
|
674
|
+
createAsyncAssertion(
|
|
675
|
+
[
|
|
676
|
+
FunctionSchema,
|
|
677
|
+
[
|
|
678
|
+
'to eventually call callback with exactly',
|
|
679
|
+
'to eventually call callback with exact value',
|
|
680
|
+
'to eventually invoke callback with exactly',
|
|
681
|
+
'to eventually invoke callback with exact value',
|
|
682
|
+
],
|
|
683
|
+
z.unknown(),
|
|
684
|
+
],
|
|
685
|
+
async (subject, expected) => {
|
|
686
|
+
const { called, value } = await trapAsyncCallbackInvocation(subject);
|
|
687
|
+
/* c8 ignore next */
|
|
688
|
+
if (!called) {
|
|
689
|
+
return createAsyncNotCalledError('callback');
|
|
690
|
+
}
|
|
691
|
+
return Object.is(value, expected);
|
|
692
|
+
},
|
|
693
|
+
),
|
|
694
|
+
|
|
695
|
+
// Async nodeback with value - deep equality check
|
|
696
|
+
createAsyncAssertion(
|
|
697
|
+
[
|
|
698
|
+
FunctionSchema,
|
|
699
|
+
[
|
|
700
|
+
'to eventually call nodeback with',
|
|
701
|
+
'to eventually invoke nodeback with',
|
|
702
|
+
],
|
|
703
|
+
z.unknown(),
|
|
704
|
+
],
|
|
705
|
+
async (subject, param) => {
|
|
706
|
+
const { called, error, value } =
|
|
707
|
+
await trapAsyncNodebackInvocation(subject);
|
|
708
|
+
/* c8 ignore next */
|
|
709
|
+
if (!called) {
|
|
710
|
+
return createAsyncNotCalledError('nodeback');
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
const errorResult = createAsyncErrorMismatchError(!!error, false, error);
|
|
714
|
+
if (errorResult) {
|
|
715
|
+
return errorResult;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
return validateValue(value, param, valueToSchemaOptionsForDeepEqual);
|
|
719
|
+
},
|
|
720
|
+
),
|
|
721
|
+
|
|
722
|
+
// Async nodeback with exact value - strict equality check
|
|
723
|
+
createAsyncAssertion(
|
|
724
|
+
[
|
|
725
|
+
FunctionSchema,
|
|
726
|
+
[
|
|
727
|
+
'to eventually call nodeback with exactly',
|
|
728
|
+
'to eventually call nodeback with exact value',
|
|
729
|
+
'to eventually invoke nodeback with exactly',
|
|
730
|
+
'to eventually invoke nodeback with exact value',
|
|
731
|
+
],
|
|
732
|
+
z.unknown(),
|
|
733
|
+
],
|
|
734
|
+
async (subject, expected) => {
|
|
735
|
+
const { called, error, value } =
|
|
736
|
+
await trapAsyncNodebackInvocation(subject);
|
|
737
|
+
/* c8 ignore next */
|
|
738
|
+
if (!called) {
|
|
739
|
+
return createAsyncNotCalledError('nodeback');
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
const errorResult = createAsyncErrorMismatchError(!!error, false, error);
|
|
743
|
+
if (errorResult) {
|
|
744
|
+
return errorResult;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
return Object.is(value, expected);
|
|
748
|
+
},
|
|
749
|
+
),
|
|
750
|
+
|
|
751
|
+
createAsyncAssertion(
|
|
752
|
+
[
|
|
753
|
+
FunctionSchema,
|
|
754
|
+
[
|
|
755
|
+
'to eventually call nodeback with error',
|
|
756
|
+
'to eventually invoke nodeback with error',
|
|
757
|
+
],
|
|
758
|
+
],
|
|
759
|
+
async (subject) => {
|
|
760
|
+
const { called, error } = await trapAsyncNodebackInvocation(subject);
|
|
761
|
+
/* c8 ignore next */
|
|
762
|
+
if (!called) {
|
|
763
|
+
return createAsyncNotCalledError('nodeback');
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
return createAsyncErrorMismatchError(!!error, true, error);
|
|
767
|
+
},
|
|
768
|
+
),
|
|
769
|
+
|
|
770
|
+
createAsyncAssertion(
|
|
771
|
+
[
|
|
772
|
+
FunctionSchema,
|
|
773
|
+
[
|
|
774
|
+
'to eventually call nodeback with a',
|
|
775
|
+
'to eventually call nodeback with an',
|
|
776
|
+
'to eventually invoke nodeback with a',
|
|
777
|
+
'to eventually invoke nodeback with an',
|
|
778
|
+
],
|
|
779
|
+
ConstructibleSchema,
|
|
780
|
+
],
|
|
781
|
+
async (subject, ctor) => {
|
|
782
|
+
const { called, error } = await trapAsyncNodebackInvocation(subject);
|
|
783
|
+
/* c8 ignore next */
|
|
784
|
+
if (!called) {
|
|
785
|
+
return createAsyncNotCalledError('nodeback');
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
const errorResult = createAsyncErrorMismatchError(!!error, true, error);
|
|
789
|
+
if (errorResult) {
|
|
790
|
+
return errorResult;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
if (!isA(error, ctor)) {
|
|
794
|
+
return {
|
|
795
|
+
actual: error,
|
|
796
|
+
expected: `instance of ${ctor.name}`,
|
|
797
|
+
message: `Expected nodeback to be called with an instance of ${ctor.name}, but it was called with ${inspect(
|
|
798
|
+
error,
|
|
799
|
+
{ depth: 2 },
|
|
800
|
+
)}`,
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
},
|
|
804
|
+
),
|
|
805
|
+
|
|
806
|
+
createAsyncAssertion(
|
|
807
|
+
[
|
|
808
|
+
FunctionSchema,
|
|
809
|
+
[
|
|
810
|
+
'to eventually call nodeback with error',
|
|
811
|
+
'to eventually invoke nodeback with error',
|
|
812
|
+
],
|
|
813
|
+
z.union([z.string(), z.instanceof(RegExp), z.looseObject({})]),
|
|
814
|
+
],
|
|
815
|
+
async (subject, param) => {
|
|
816
|
+
const { called, error } = await trapAsyncNodebackInvocation(subject);
|
|
817
|
+
/* c8 ignore next */
|
|
818
|
+
if (!called) {
|
|
819
|
+
return createAsyncNotCalledError('nodeback');
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
const errorResult = createAsyncErrorMismatchError(!!error, true, error);
|
|
823
|
+
if (errorResult) {
|
|
824
|
+
return errorResult;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
const schema = createErrorSchema(param);
|
|
828
|
+
const result = schema.safeParse(error);
|
|
829
|
+
if (!result.success) {
|
|
830
|
+
return result.error;
|
|
831
|
+
}
|
|
832
|
+
},
|
|
833
|
+
),
|
|
834
|
+
|
|
835
|
+
// Async callback satisfying pattern - partial matching
|
|
836
|
+
createAsyncAssertion(
|
|
837
|
+
[
|
|
838
|
+
FunctionSchema,
|
|
839
|
+
[
|
|
840
|
+
'to eventually call callback with value satisfying',
|
|
841
|
+
'to eventually invoke callback with value satisfying',
|
|
842
|
+
],
|
|
843
|
+
z.union([z.string(), z.instanceof(RegExp), z.looseObject({})]),
|
|
844
|
+
],
|
|
845
|
+
async (subject, param) => {
|
|
846
|
+
const { called, value } = await trapAsyncCallbackInvocation(subject);
|
|
847
|
+
/* c8 ignore next */
|
|
848
|
+
if (!called) {
|
|
849
|
+
return createAsyncNotCalledError('callback');
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
return validateValue(value, param, valueToSchemaOptionsForSatisfies);
|
|
853
|
+
},
|
|
854
|
+
),
|
|
855
|
+
|
|
856
|
+
// Async nodeback satisfying pattern - partial matching
|
|
857
|
+
createAsyncAssertion(
|
|
858
|
+
[
|
|
859
|
+
FunctionSchema,
|
|
860
|
+
[
|
|
861
|
+
'to eventually call nodeback with value satisfying',
|
|
862
|
+
'to eventually invoke nodeback with value satisfying',
|
|
863
|
+
],
|
|
864
|
+
z.union([z.string(), z.instanceof(RegExp), z.looseObject({})]),
|
|
865
|
+
],
|
|
866
|
+
async (subject, param) => {
|
|
867
|
+
const { called, error, value } =
|
|
868
|
+
await trapAsyncNodebackInvocation(subject);
|
|
869
|
+
/* c8 ignore next */
|
|
870
|
+
if (!called) {
|
|
871
|
+
return createAsyncNotCalledError('nodeback');
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
const errorResult = createAsyncErrorMismatchError(!!error, false, error);
|
|
875
|
+
if (errorResult) {
|
|
876
|
+
return errorResult;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
return validateValue(value, param, valueToSchemaOptionsForSatisfies);
|
|
880
|
+
},
|
|
881
|
+
),
|
|
882
|
+
] as const;
|