@autometa/assertions 1.0.0-rc.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/LICENSE +21 -0
- package/README.md +19 -0
- package/dist/__tests__/ensure.test-d.d.ts +67 -0
- package/dist/__tests__/helpers/matcher-context.d.ts +18 -0
- package/dist/assertion-error.d.ts +13 -0
- package/dist/core/constants.d.ts +4 -0
- package/dist/core/context.d.ts +14 -0
- package/dist/core/messages.d.ts +10 -0
- package/dist/core/predicates.d.ts +5 -0
- package/dist/ensure.d.ts +33 -0
- package/dist/index.cjs +815 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +809 -0
- package/dist/index.js.map +1 -0
- package/dist/matchers/__tests__/http.note.d.ts +6 -0
- package/dist/matchers/collections.d.ts +6 -0
- package/dist/matchers/equality.d.ts +4 -0
- package/dist/matchers/http.d.ts +57 -0
- package/dist/matchers/instance.d.ts +2 -0
- package/dist/matchers/nullish.d.ts +4 -0
- package/dist/matchers/numeric.d.ts +6 -0
- package/dist/matchers/truthiness.d.ts +3 -0
- package/dist/plugins/runtime-assertions-plugin.d.ts +140 -0
- package/dist/plugins.d.ts +50 -0
- package/package.json +61 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,815 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var util = require('util');
|
|
4
|
+
var expectUtils = require('@jest/expect-utils');
|
|
5
|
+
var jestDiff = require('jest-diff');
|
|
6
|
+
var jestMatcherUtils = require('jest-matcher-utils');
|
|
7
|
+
|
|
8
|
+
// src/assertion-error.ts
|
|
9
|
+
var EnsureError = class extends Error {
|
|
10
|
+
constructor(details) {
|
|
11
|
+
const formattedMessage = buildMessage(details);
|
|
12
|
+
super(formattedMessage);
|
|
13
|
+
this.name = "EnsureError";
|
|
14
|
+
this.matcher = details.matcher;
|
|
15
|
+
this.actual = details.actual;
|
|
16
|
+
this.expected = details.expected;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
function buildMessage({ matcher, message, actual, expected, receivedLabel }) {
|
|
20
|
+
const parts = [message];
|
|
21
|
+
const extras = [];
|
|
22
|
+
if (typeof expected !== "undefined" && !containsSection(message, "Expected:")) {
|
|
23
|
+
extras.push(`Expected: ${formatValue(expected)}`);
|
|
24
|
+
}
|
|
25
|
+
if (typeof actual !== "undefined") {
|
|
26
|
+
const label = receivedLabel ? `Received ${receivedLabel}` : "Received";
|
|
27
|
+
if (!containsSection(message, `${label}:`)) {
|
|
28
|
+
extras.push(`${label}: ${formatValue(actual)}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (!containsSection(message, "Matcher:")) {
|
|
32
|
+
extras.push(`Matcher: ${matcher}`);
|
|
33
|
+
}
|
|
34
|
+
if (extras.length > 0) {
|
|
35
|
+
parts.push("", ...extras);
|
|
36
|
+
}
|
|
37
|
+
return parts.join("\n");
|
|
38
|
+
}
|
|
39
|
+
function formatValue(value) {
|
|
40
|
+
return util.inspect(value, { depth: 4, maxArrayLength: 10, breakLength: 60, sorted: true });
|
|
41
|
+
}
|
|
42
|
+
function containsSection(message, label) {
|
|
43
|
+
return message.split("\n").some((line) => line.trimStart().startsWith(label));
|
|
44
|
+
}
|
|
45
|
+
var MATCHER_CALL = "ensure(received)";
|
|
46
|
+
var EQUALITY_TESTERS = [expectUtils.iterableEquality];
|
|
47
|
+
var SUBSET_TESTERS = [expectUtils.iterableEquality, expectUtils.subsetEquality];
|
|
48
|
+
|
|
49
|
+
// src/core/context.ts
|
|
50
|
+
function shouldFail(pass, negated) {
|
|
51
|
+
return negated ? pass : !pass;
|
|
52
|
+
}
|
|
53
|
+
function buildFailureMessage(matcher, baseMessage, options = {}) {
|
|
54
|
+
const sections = [`${MATCHER_CALL}.${matcher}(expected)`, baseMessage];
|
|
55
|
+
if (Object.prototype.hasOwnProperty.call(options, "expected")) {
|
|
56
|
+
sections.push(`Expected: ${jestMatcherUtils.printExpected(options.expected)}`);
|
|
57
|
+
}
|
|
58
|
+
if (Object.prototype.hasOwnProperty.call(options, "actual")) {
|
|
59
|
+
const label = options.actualLabel ?? "Received";
|
|
60
|
+
sections.push(`${label}: ${jestMatcherUtils.printReceived(options.actual)}`);
|
|
61
|
+
}
|
|
62
|
+
if (options.extra) {
|
|
63
|
+
for (const extra of options.extra) {
|
|
64
|
+
if (extra && extra.trim().length > 0) {
|
|
65
|
+
sections.push(extra);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (options.diff && options.diff.trim().length > 0) {
|
|
70
|
+
sections.push(options.diff);
|
|
71
|
+
}
|
|
72
|
+
return sections.join("\n\n");
|
|
73
|
+
}
|
|
74
|
+
function formatDiff(expected, actual) {
|
|
75
|
+
const difference = jestDiff.diff(expected, actual, { expand: false });
|
|
76
|
+
return difference && difference.trim().length > 0 ? difference : void 0;
|
|
77
|
+
}
|
|
78
|
+
function formatMissingList(title, values) {
|
|
79
|
+
if (values.length === 0) {
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
const items = values.map((value) => ` - ${jestMatcherUtils.printExpected(value)}`).join("\n");
|
|
83
|
+
return `${title}
|
|
84
|
+
${items}`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/core/predicates.ts
|
|
88
|
+
function isRecord(candidate) {
|
|
89
|
+
return typeof candidate === "object" && candidate !== null;
|
|
90
|
+
}
|
|
91
|
+
function isIterable(candidate) {
|
|
92
|
+
return typeof candidate?.[Symbol.iterator] === "function";
|
|
93
|
+
}
|
|
94
|
+
function hasLengthProperty(candidate) {
|
|
95
|
+
return typeof candidate?.length === "number";
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/matchers/collections.ts
|
|
99
|
+
function assertObjectContaining(ctx, shape) {
|
|
100
|
+
const isObject = isRecord(ctx.value);
|
|
101
|
+
if (!isObject) {
|
|
102
|
+
if (!ctx.negated) {
|
|
103
|
+
ctx.fail("toBeObjectContaining", {
|
|
104
|
+
message: buildFailureMessage("toBeObjectContaining", "Expected value to be an object", {
|
|
105
|
+
actual: ctx.value
|
|
106
|
+
}),
|
|
107
|
+
actual: ctx.value
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const pass = expectUtils.equals(ctx.value, shape, SUBSET_TESTERS);
|
|
113
|
+
if (shouldFail(pass, ctx.negated)) {
|
|
114
|
+
const baseMessage = ctx.negated ? "Expected object not to match the provided subset" : "Object does not match the provided subset";
|
|
115
|
+
ctx.fail("toBeObjectContaining", {
|
|
116
|
+
message: buildFailureMessage("toBeObjectContaining", baseMessage, {
|
|
117
|
+
expected: shape,
|
|
118
|
+
actual: ctx.value,
|
|
119
|
+
diff: formatDiff(shape, ctx.value)
|
|
120
|
+
}),
|
|
121
|
+
expected: shape,
|
|
122
|
+
actual: ctx.value
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function assertArrayContaining(ctx, expected) {
|
|
127
|
+
if (!Array.isArray(ctx.value)) {
|
|
128
|
+
if (!ctx.negated) {
|
|
129
|
+
ctx.fail("toBeArrayContaining", {
|
|
130
|
+
message: buildFailureMessage("toBeArrayContaining", "Expected value to be an array", {
|
|
131
|
+
actual: ctx.value
|
|
132
|
+
}),
|
|
133
|
+
actual: ctx.value
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return ctx.value;
|
|
137
|
+
}
|
|
138
|
+
const actual = ctx.value;
|
|
139
|
+
const missing = expected.filter(
|
|
140
|
+
(item) => !actual.some((entry) => expectUtils.equals(entry, item, EQUALITY_TESTERS))
|
|
141
|
+
);
|
|
142
|
+
const pass = missing.length === 0;
|
|
143
|
+
if (shouldFail(pass, ctx.negated)) {
|
|
144
|
+
const baseMessage = ctx.negated ? "Expected array not to contain the provided elements" : "Array is missing expected elements";
|
|
145
|
+
ctx.fail("toBeArrayContaining", {
|
|
146
|
+
message: buildFailureMessage("toBeArrayContaining", baseMessage, {
|
|
147
|
+
expected,
|
|
148
|
+
actual,
|
|
149
|
+
extra: [formatMissingList("Missing elements:", missing)],
|
|
150
|
+
diff: formatDiff(expected, actual)
|
|
151
|
+
}),
|
|
152
|
+
expected,
|
|
153
|
+
actual
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return actual;
|
|
157
|
+
}
|
|
158
|
+
function assertContainEqual(ctx, expected) {
|
|
159
|
+
if (!Array.isArray(ctx.value)) {
|
|
160
|
+
if (!ctx.negated) {
|
|
161
|
+
ctx.fail("toContainEqual", {
|
|
162
|
+
message: buildFailureMessage("toContainEqual", "Expected value to be an array", {
|
|
163
|
+
actual: ctx.value
|
|
164
|
+
}),
|
|
165
|
+
actual: ctx.value
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return ctx.value;
|
|
169
|
+
}
|
|
170
|
+
const actual = ctx.value;
|
|
171
|
+
const pass = actual.some((entry) => expectUtils.equals(entry, expected, EQUALITY_TESTERS));
|
|
172
|
+
if (shouldFail(pass, ctx.negated)) {
|
|
173
|
+
const baseMessage = ctx.negated ? "Expected array not to contain the provided element" : "Array is missing the expected element";
|
|
174
|
+
ctx.fail("toContainEqual", {
|
|
175
|
+
message: buildFailureMessage("toContainEqual", baseMessage, {
|
|
176
|
+
expected,
|
|
177
|
+
actual,
|
|
178
|
+
diff: formatDiff(expected, actual)
|
|
179
|
+
}),
|
|
180
|
+
expected,
|
|
181
|
+
actual
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return actual;
|
|
185
|
+
}
|
|
186
|
+
function assertIterableContaining(ctx, expected) {
|
|
187
|
+
if (!isIterable(ctx.value)) {
|
|
188
|
+
if (!ctx.negated) {
|
|
189
|
+
ctx.fail("toBeIterableContaining", {
|
|
190
|
+
message: buildFailureMessage("toBeIterableContaining", "Expected value to be iterable", {
|
|
191
|
+
actual: ctx.value
|
|
192
|
+
}),
|
|
193
|
+
actual: ctx.value
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
return ctx.value;
|
|
197
|
+
}
|
|
198
|
+
const entries = Array.from(ctx.value);
|
|
199
|
+
const missing = expected.filter(
|
|
200
|
+
(item) => !entries.some((entry) => expectUtils.equals(entry, item, EQUALITY_TESTERS))
|
|
201
|
+
);
|
|
202
|
+
const pass = missing.length === 0;
|
|
203
|
+
if (shouldFail(pass, ctx.negated)) {
|
|
204
|
+
const baseMessage = ctx.negated ? "Expected iterable not to contain the provided elements" : "Iterable is missing expected elements";
|
|
205
|
+
ctx.fail("toBeIterableContaining", {
|
|
206
|
+
message: buildFailureMessage("toBeIterableContaining", baseMessage, {
|
|
207
|
+
expected,
|
|
208
|
+
actual: entries,
|
|
209
|
+
extra: [formatMissingList("Missing elements:", missing)]
|
|
210
|
+
}),
|
|
211
|
+
expected,
|
|
212
|
+
actual: entries
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return ctx.value;
|
|
216
|
+
}
|
|
217
|
+
function assertHasLength(ctx, expected) {
|
|
218
|
+
if (!hasLengthProperty(ctx.value)) {
|
|
219
|
+
if (!ctx.negated) {
|
|
220
|
+
ctx.fail("toHaveLength", {
|
|
221
|
+
message: buildFailureMessage("toHaveLength", "Expected value to have a numeric length property", {
|
|
222
|
+
actual: ctx.value
|
|
223
|
+
}),
|
|
224
|
+
actual: ctx.value
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return NaN;
|
|
228
|
+
}
|
|
229
|
+
const actualLength = ctx.value.length;
|
|
230
|
+
const pass = actualLength === expected;
|
|
231
|
+
if (shouldFail(pass, ctx.negated)) {
|
|
232
|
+
const baseMessage = ctx.negated ? `Expected length to differ from ${expected}` : "Length does not match expectation";
|
|
233
|
+
ctx.fail("toHaveLength", {
|
|
234
|
+
message: buildFailureMessage("toHaveLength", baseMessage, {
|
|
235
|
+
expected,
|
|
236
|
+
actual: actualLength,
|
|
237
|
+
diff: formatDiff(expected, actualLength)
|
|
238
|
+
}),
|
|
239
|
+
expected,
|
|
240
|
+
actual: actualLength
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
return actualLength;
|
|
244
|
+
}
|
|
245
|
+
function assertToBe(ctx, expected) {
|
|
246
|
+
const pass = Object.is(ctx.value, expected);
|
|
247
|
+
if (ctx.negated ? pass : !pass) {
|
|
248
|
+
const baseMessage = ctx.negated ? "Expected values not to be strictly equal" : "Expected values to be strictly equal";
|
|
249
|
+
ctx.fail("toBe", {
|
|
250
|
+
message: buildFailureMessage("toBe", baseMessage, {
|
|
251
|
+
actual: ctx.value,
|
|
252
|
+
expected,
|
|
253
|
+
diff: formatDiff(expected, ctx.value)
|
|
254
|
+
}),
|
|
255
|
+
actual: ctx.value,
|
|
256
|
+
expected
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function assertToEqual(ctx, expected) {
|
|
261
|
+
const pass = expectUtils.equals(ctx.value, expected, EQUALITY_TESTERS);
|
|
262
|
+
if (ctx.negated ? pass : !pass) {
|
|
263
|
+
const baseMessage = ctx.negated ? "Expected values not to be deeply equal" : "Expected values to be deeply equal";
|
|
264
|
+
ctx.fail("toEqual", {
|
|
265
|
+
message: buildFailureMessage("toEqual", baseMessage, {
|
|
266
|
+
actual: ctx.value,
|
|
267
|
+
expected,
|
|
268
|
+
diff: formatDiff(expected, ctx.value)
|
|
269
|
+
}),
|
|
270
|
+
actual: ctx.value,
|
|
271
|
+
expected
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
function assertToStrictEqual(ctx, expected) {
|
|
276
|
+
const pass = expectUtils.equals(ctx.value, expected, EQUALITY_TESTERS, true);
|
|
277
|
+
if (ctx.negated ? pass : !pass) {
|
|
278
|
+
const baseMessage = ctx.negated ? "Expected values not to be strictly equal (including prototypes and property definitions)" : "Expected values to be strictly equal (including prototypes and property definitions)";
|
|
279
|
+
ctx.fail("toStrictEqual", {
|
|
280
|
+
message: buildFailureMessage("toStrictEqual", baseMessage, {
|
|
281
|
+
actual: ctx.value,
|
|
282
|
+
expected,
|
|
283
|
+
diff: formatDiff(expected, ctx.value)
|
|
284
|
+
}),
|
|
285
|
+
actual: ctx.value,
|
|
286
|
+
expected
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/matchers/instance.ts
|
|
292
|
+
function assertToBeInstanceOf(ctx, ctor) {
|
|
293
|
+
if (typeof ctor !== "function") {
|
|
294
|
+
ctx.fail("toBeInstanceOf", {
|
|
295
|
+
message: buildFailureMessage("toBeInstanceOf", "Constructor must be a callable function", {
|
|
296
|
+
expected: ctor
|
|
297
|
+
}),
|
|
298
|
+
expected: ctor
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
const pass = ctx.value instanceof ctor;
|
|
302
|
+
if (ctx.negated ? pass : !pass) {
|
|
303
|
+
const label = ctor.name || "<anonymous>";
|
|
304
|
+
const baseMessage = ctx.negated ? `Expected value not to be an instance of ${label}` : `Expected value to be an instance of ${label}`;
|
|
305
|
+
ctx.fail("toBeInstanceOf", {
|
|
306
|
+
message: buildFailureMessage("toBeInstanceOf", baseMessage, {
|
|
307
|
+
expected: ctor,
|
|
308
|
+
actual: ctx.value
|
|
309
|
+
}),
|
|
310
|
+
expected: ctor,
|
|
311
|
+
actual: ctx.value
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
return ctx.value;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// src/matchers/nullish.ts
|
|
318
|
+
var NIL_MESSAGE = "Value is null or undefined";
|
|
319
|
+
function assertToBeDefined(ctx) {
|
|
320
|
+
const isDefined = ctx.value !== null && typeof ctx.value !== "undefined";
|
|
321
|
+
if (ctx.negated ? isDefined : !isDefined) {
|
|
322
|
+
const baseMessage = ctx.negated ? "Expected value to be null or undefined" : NIL_MESSAGE;
|
|
323
|
+
ctx.fail("toBeDefined", {
|
|
324
|
+
message: buildFailureMessage("toBeDefined", baseMessage, {
|
|
325
|
+
actual: ctx.value
|
|
326
|
+
}),
|
|
327
|
+
actual: ctx.value
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
return ctx.value;
|
|
331
|
+
}
|
|
332
|
+
function assertToBeUndefined(ctx) {
|
|
333
|
+
const isUndefined = typeof ctx.value === "undefined";
|
|
334
|
+
if (ctx.negated ? isUndefined : !isUndefined) {
|
|
335
|
+
const baseMessage = ctx.negated ? "Expected value not to be undefined" : "Expected value to be undefined";
|
|
336
|
+
ctx.fail("toBeUndefined", {
|
|
337
|
+
message: buildFailureMessage("toBeUndefined", baseMessage, {
|
|
338
|
+
actual: ctx.value
|
|
339
|
+
}),
|
|
340
|
+
actual: ctx.value
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
return void 0;
|
|
344
|
+
}
|
|
345
|
+
function assertToBeNull(ctx) {
|
|
346
|
+
const isNull = ctx.value === null;
|
|
347
|
+
if (ctx.negated ? isNull : !isNull) {
|
|
348
|
+
const baseMessage = ctx.negated ? "Expected value not to be null" : "Expected value to be null";
|
|
349
|
+
ctx.fail("toBeNull", {
|
|
350
|
+
message: buildFailureMessage("toBeNull", baseMessage, {
|
|
351
|
+
actual: ctx.value
|
|
352
|
+
}),
|
|
353
|
+
actual: ctx.value
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/matchers/numeric.ts
|
|
360
|
+
function requireFiniteNumber(ctx, matcher) {
|
|
361
|
+
const value = ctx.value;
|
|
362
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
363
|
+
ctx.fail(matcher, {
|
|
364
|
+
message: buildFailureMessage(
|
|
365
|
+
matcher,
|
|
366
|
+
"Expected value to be a finite number",
|
|
367
|
+
{ actual: value }
|
|
368
|
+
),
|
|
369
|
+
actual: value,
|
|
370
|
+
expected: "finite number"
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
return value;
|
|
374
|
+
}
|
|
375
|
+
function requireFiniteExpected(ctx, matcher, expected, name = "expected") {
|
|
376
|
+
if (typeof expected !== "number" || !Number.isFinite(expected)) {
|
|
377
|
+
ctx.fail(matcher, {
|
|
378
|
+
message: buildFailureMessage(
|
|
379
|
+
matcher,
|
|
380
|
+
`Expected ${name} to be a finite number`,
|
|
381
|
+
{ actual: expected }
|
|
382
|
+
),
|
|
383
|
+
actual: expected,
|
|
384
|
+
expected: "finite number"
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
function assertToBeGreaterThan(ctx, expected) {
|
|
389
|
+
const actual = requireFiniteNumber(ctx, "toBeGreaterThan");
|
|
390
|
+
requireFiniteExpected(ctx, "toBeGreaterThan", expected);
|
|
391
|
+
const pass = actual > expected;
|
|
392
|
+
if (shouldFail(pass, ctx.negated)) {
|
|
393
|
+
const baseMessage = ctx.negated ? `Expected value not to be greater than ${expected}` : `Expected value to be greater than ${expected}`;
|
|
394
|
+
ctx.fail("toBeGreaterThan", {
|
|
395
|
+
message: buildFailureMessage("toBeGreaterThan", baseMessage, {
|
|
396
|
+
expected,
|
|
397
|
+
actual
|
|
398
|
+
}),
|
|
399
|
+
actual,
|
|
400
|
+
expected
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
return actual;
|
|
404
|
+
}
|
|
405
|
+
function assertToBeGreaterThanOrEqual(ctx, expected) {
|
|
406
|
+
const actual = requireFiniteNumber(ctx, "toBeGreaterThanOrEqual");
|
|
407
|
+
requireFiniteExpected(
|
|
408
|
+
ctx,
|
|
409
|
+
"toBeGreaterThanOrEqual",
|
|
410
|
+
expected
|
|
411
|
+
);
|
|
412
|
+
const pass = actual >= expected;
|
|
413
|
+
if (shouldFail(pass, ctx.negated)) {
|
|
414
|
+
const baseMessage = ctx.negated ? `Expected value not to be greater than or equal to ${expected}` : `Expected value to be greater than or equal to ${expected}`;
|
|
415
|
+
ctx.fail("toBeGreaterThanOrEqual", {
|
|
416
|
+
message: buildFailureMessage("toBeGreaterThanOrEqual", baseMessage, {
|
|
417
|
+
expected,
|
|
418
|
+
actual
|
|
419
|
+
}),
|
|
420
|
+
actual,
|
|
421
|
+
expected
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
return actual;
|
|
425
|
+
}
|
|
426
|
+
function assertToBeLessThan(ctx, expected) {
|
|
427
|
+
const actual = requireFiniteNumber(ctx, "toBeLessThan");
|
|
428
|
+
requireFiniteExpected(ctx, "toBeLessThan", expected);
|
|
429
|
+
const pass = actual < expected;
|
|
430
|
+
if (shouldFail(pass, ctx.negated)) {
|
|
431
|
+
const baseMessage = ctx.negated ? `Expected value not to be less than ${expected}` : `Expected value to be less than ${expected}`;
|
|
432
|
+
ctx.fail("toBeLessThan", {
|
|
433
|
+
message: buildFailureMessage("toBeLessThan", baseMessage, {
|
|
434
|
+
expected,
|
|
435
|
+
actual
|
|
436
|
+
}),
|
|
437
|
+
actual,
|
|
438
|
+
expected
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
return actual;
|
|
442
|
+
}
|
|
443
|
+
function assertToBeLessThanOrEqual(ctx, expected) {
|
|
444
|
+
const actual = requireFiniteNumber(ctx, "toBeLessThanOrEqual");
|
|
445
|
+
requireFiniteExpected(
|
|
446
|
+
ctx,
|
|
447
|
+
"toBeLessThanOrEqual",
|
|
448
|
+
expected
|
|
449
|
+
);
|
|
450
|
+
const pass = actual <= expected;
|
|
451
|
+
if (shouldFail(pass, ctx.negated)) {
|
|
452
|
+
const baseMessage = ctx.negated ? `Expected value not to be less than or equal to ${expected}` : `Expected value to be less than or equal to ${expected}`;
|
|
453
|
+
ctx.fail("toBeLessThanOrEqual", {
|
|
454
|
+
message: buildFailureMessage("toBeLessThanOrEqual", baseMessage, {
|
|
455
|
+
expected,
|
|
456
|
+
actual
|
|
457
|
+
}),
|
|
458
|
+
actual,
|
|
459
|
+
expected
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
return actual;
|
|
463
|
+
}
|
|
464
|
+
function assertToBeCloseTo(ctx, expected, precision = 2) {
|
|
465
|
+
const actual = requireFiniteNumber(ctx, "toBeCloseTo");
|
|
466
|
+
requireFiniteExpected(ctx, "toBeCloseTo", expected);
|
|
467
|
+
if (!Number.isInteger(precision) || precision < 0 || precision > 20) {
|
|
468
|
+
ctx.fail("toBeCloseTo", {
|
|
469
|
+
message: buildFailureMessage(
|
|
470
|
+
"toBeCloseTo",
|
|
471
|
+
"Expected precision to be an integer between 0 and 20",
|
|
472
|
+
{ actual: precision }
|
|
473
|
+
),
|
|
474
|
+
actual: precision,
|
|
475
|
+
expected: "integer between 0 and 20"
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
const tolerance = Math.pow(10, -precision) / 2;
|
|
479
|
+
const difference = Math.abs(actual - expected);
|
|
480
|
+
const epsilon = Number.EPSILON * Math.max(1, Math.abs(actual), Math.abs(expected)) * 2;
|
|
481
|
+
const pass = difference <= tolerance + epsilon;
|
|
482
|
+
if (shouldFail(pass, ctx.negated)) {
|
|
483
|
+
const baseMessage = ctx.negated ? `Expected value not to be close to ${expected} (precision ${precision})` : `Expected value to be close to ${expected} (precision ${precision})`;
|
|
484
|
+
ctx.fail("toBeCloseTo", {
|
|
485
|
+
message: buildFailureMessage("toBeCloseTo", baseMessage, {
|
|
486
|
+
expected,
|
|
487
|
+
actual,
|
|
488
|
+
extra: [
|
|
489
|
+
`Difference: ${difference}`,
|
|
490
|
+
`Tolerance: ${tolerance}`
|
|
491
|
+
]
|
|
492
|
+
}),
|
|
493
|
+
actual,
|
|
494
|
+
expected
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
return actual;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// src/matchers/truthiness.ts
|
|
501
|
+
function assertToBeTruthy(ctx) {
|
|
502
|
+
const pass = Boolean(ctx.value);
|
|
503
|
+
if (ctx.negated ? pass : !pass) {
|
|
504
|
+
const baseMessage = ctx.negated ? "Expected value to be falsy" : "Expected value to be truthy";
|
|
505
|
+
ctx.fail("toBeTruthy", {
|
|
506
|
+
message: buildFailureMessage("toBeTruthy", baseMessage, {
|
|
507
|
+
actual: ctx.value
|
|
508
|
+
}),
|
|
509
|
+
actual: ctx.value
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function assertToBeFalsy(ctx) {
|
|
514
|
+
const pass = !ctx.value;
|
|
515
|
+
if (ctx.negated ? pass : !pass) {
|
|
516
|
+
const baseMessage = ctx.negated ? "Expected value to be truthy" : "Expected value to be falsy";
|
|
517
|
+
ctx.fail("toBeFalsy", {
|
|
518
|
+
message: buildFailureMessage("toBeFalsy", baseMessage, {
|
|
519
|
+
actual: ctx.value
|
|
520
|
+
}),
|
|
521
|
+
actual: ctx.value
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// src/ensure.ts
|
|
527
|
+
function ensure(value, options = {}) {
|
|
528
|
+
const state = {
|
|
529
|
+
value,
|
|
530
|
+
negated: false,
|
|
531
|
+
...options.label !== void 0 ? { label: options.label } : {}
|
|
532
|
+
};
|
|
533
|
+
return new EnsureChainImpl(state);
|
|
534
|
+
}
|
|
535
|
+
var EnsureChainImpl = class _EnsureChainImpl {
|
|
536
|
+
constructor(state) {
|
|
537
|
+
this.state = state;
|
|
538
|
+
}
|
|
539
|
+
get value() {
|
|
540
|
+
return this.state.value;
|
|
541
|
+
}
|
|
542
|
+
get not() {
|
|
543
|
+
const toggled = !this.state.negated;
|
|
544
|
+
const nextState = {
|
|
545
|
+
value: this.state.value,
|
|
546
|
+
negated: toggled,
|
|
547
|
+
...this.state.label !== void 0 ? { label: this.state.label } : {}
|
|
548
|
+
};
|
|
549
|
+
return new _EnsureChainImpl(
|
|
550
|
+
nextState
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
toBe(expected) {
|
|
554
|
+
assertToBe(this.createContext(), expected);
|
|
555
|
+
return this;
|
|
556
|
+
}
|
|
557
|
+
toEqual(expected) {
|
|
558
|
+
assertToEqual(this.createContext(), expected);
|
|
559
|
+
return this;
|
|
560
|
+
}
|
|
561
|
+
toStrictEqual(expected) {
|
|
562
|
+
assertToStrictEqual(this.createContext(), expected);
|
|
563
|
+
return this;
|
|
564
|
+
}
|
|
565
|
+
toBeDefined() {
|
|
566
|
+
const defined = assertToBeDefined(this.createContext());
|
|
567
|
+
const next = this.state.negated ? this : this.rewrap(defined);
|
|
568
|
+
return next;
|
|
569
|
+
}
|
|
570
|
+
toBeUndefined() {
|
|
571
|
+
const result = assertToBeUndefined(this.createContext());
|
|
572
|
+
const next = this.state.negated ? this : this.rewrap(result);
|
|
573
|
+
return next;
|
|
574
|
+
}
|
|
575
|
+
toBeNull() {
|
|
576
|
+
const result = assertToBeNull(this.createContext());
|
|
577
|
+
const next = this.state.negated ? this : this.rewrap(result);
|
|
578
|
+
return next;
|
|
579
|
+
}
|
|
580
|
+
toBeTruthy() {
|
|
581
|
+
assertToBeTruthy(this.createContext());
|
|
582
|
+
return this;
|
|
583
|
+
}
|
|
584
|
+
toBeFalsy() {
|
|
585
|
+
assertToBeFalsy(this.createContext());
|
|
586
|
+
return this;
|
|
587
|
+
}
|
|
588
|
+
toBeGreaterThan(expected) {
|
|
589
|
+
const actual = assertToBeGreaterThan(this.createContext(), expected);
|
|
590
|
+
const next = this.state.negated ? this : this.rewrap(actual);
|
|
591
|
+
return next;
|
|
592
|
+
}
|
|
593
|
+
toBeGreaterThanOrEqual(expected) {
|
|
594
|
+
const actual = assertToBeGreaterThanOrEqual(this.createContext(), expected);
|
|
595
|
+
const next = this.state.negated ? this : this.rewrap(actual);
|
|
596
|
+
return next;
|
|
597
|
+
}
|
|
598
|
+
toBeLessThan(expected) {
|
|
599
|
+
const actual = assertToBeLessThan(this.createContext(), expected);
|
|
600
|
+
const next = this.state.negated ? this : this.rewrap(actual);
|
|
601
|
+
return next;
|
|
602
|
+
}
|
|
603
|
+
toBeLessThanOrEqual(expected) {
|
|
604
|
+
const actual = assertToBeLessThanOrEqual(this.createContext(), expected);
|
|
605
|
+
const next = this.state.negated ? this : this.rewrap(actual);
|
|
606
|
+
return next;
|
|
607
|
+
}
|
|
608
|
+
toBeCloseTo(expected, precision) {
|
|
609
|
+
const actual = assertToBeCloseTo(this.createContext(), expected, precision);
|
|
610
|
+
const next = this.state.negated ? this : this.rewrap(actual);
|
|
611
|
+
return next;
|
|
612
|
+
}
|
|
613
|
+
toBeInstanceOf(ctor) {
|
|
614
|
+
const instance = assertToBeInstanceOf(this.createContext(), ctor);
|
|
615
|
+
const next = this.state.negated ? this : this.rewrap(instance);
|
|
616
|
+
return next;
|
|
617
|
+
}
|
|
618
|
+
toBeObjectContaining(shape) {
|
|
619
|
+
assertObjectContaining(this.createContext(), shape);
|
|
620
|
+
return this;
|
|
621
|
+
}
|
|
622
|
+
toBeArrayContaining(expected) {
|
|
623
|
+
const array = assertArrayContaining(this.createContext(), expected);
|
|
624
|
+
const next = this.state.negated ? this : this.rewrap(array);
|
|
625
|
+
return next;
|
|
626
|
+
}
|
|
627
|
+
toContainEqual(expected) {
|
|
628
|
+
const array = assertContainEqual(this.createContext(), expected);
|
|
629
|
+
const next = this.state.negated ? this : this.rewrap(array);
|
|
630
|
+
return next;
|
|
631
|
+
}
|
|
632
|
+
toBeIterableContaining(expected) {
|
|
633
|
+
const iterable = assertIterableContaining(this.createContext(), expected);
|
|
634
|
+
const next = this.state.negated ? this : this.rewrap(iterable);
|
|
635
|
+
return next;
|
|
636
|
+
}
|
|
637
|
+
toHaveLength(expected) {
|
|
638
|
+
assertHasLength(this.createContext(), expected);
|
|
639
|
+
const next = this.state.negated ? this : this.rewrap(this.state.value);
|
|
640
|
+
return next;
|
|
641
|
+
}
|
|
642
|
+
createContext() {
|
|
643
|
+
return {
|
|
644
|
+
value: this.state.value,
|
|
645
|
+
negated: this.state.negated,
|
|
646
|
+
fail: (matcher, details) => this.fail(matcher, details),
|
|
647
|
+
...this.state.label !== void 0 ? { label: this.state.label } : {}
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
rewrap(value) {
|
|
651
|
+
const nextState = {
|
|
652
|
+
value,
|
|
653
|
+
negated: this.state.negated,
|
|
654
|
+
...this.state.label !== void 0 ? { label: this.state.label } : {}
|
|
655
|
+
};
|
|
656
|
+
return new _EnsureChainImpl(
|
|
657
|
+
nextState
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
fail(matcher, details) {
|
|
661
|
+
const errorDetails = {
|
|
662
|
+
matcher,
|
|
663
|
+
message: details.message,
|
|
664
|
+
...details.actual !== void 0 ? { actual: details.actual } : {},
|
|
665
|
+
...details.expected !== void 0 ? { expected: details.expected } : {},
|
|
666
|
+
...this.state.label !== void 0 ? { receivedLabel: this.state.label } : {}
|
|
667
|
+
};
|
|
668
|
+
throw new EnsureError(errorDetails);
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
// src/plugins.ts
|
|
673
|
+
function createEnsureFactory(ensureFn, plugins) {
|
|
674
|
+
const withAlways = (invoker, always) => {
|
|
675
|
+
Object.defineProperty(invoker, "always", {
|
|
676
|
+
value: always,
|
|
677
|
+
enumerable: false,
|
|
678
|
+
configurable: false,
|
|
679
|
+
writable: false
|
|
680
|
+
});
|
|
681
|
+
return invoker;
|
|
682
|
+
};
|
|
683
|
+
const positiveEnsure = withAlways(ensureFn, ensureFn);
|
|
684
|
+
const pluginEntries = Object.keys(plugins).map((key) => {
|
|
685
|
+
const plugin = plugins[key];
|
|
686
|
+
if (!plugin) {
|
|
687
|
+
throw new Error(`Assertion plugin "${String(key)}" is not defined.`);
|
|
688
|
+
}
|
|
689
|
+
const factory = plugin({ ensure: positiveEnsure, isNot: false });
|
|
690
|
+
return [key, factory];
|
|
691
|
+
});
|
|
692
|
+
const negatedEnsureFn = (value, options) => {
|
|
693
|
+
return ensureFn(value, options).not;
|
|
694
|
+
};
|
|
695
|
+
const negativeEnsure = withAlways(negatedEnsureFn, ensureFn);
|
|
696
|
+
const negativePluginEntries = Object.keys(plugins).map((key) => {
|
|
697
|
+
const plugin = plugins[key];
|
|
698
|
+
if (!plugin) {
|
|
699
|
+
throw new Error(`Assertion plugin "${String(key)}" is not defined.`);
|
|
700
|
+
}
|
|
701
|
+
const factory = plugin({ ensure: negativeEnsure, isNot: true });
|
|
702
|
+
return [key, factory];
|
|
703
|
+
});
|
|
704
|
+
return (world) => {
|
|
705
|
+
const facade = (value, options) => ensureFn(value, options);
|
|
706
|
+
Object.defineProperty(facade, "world", {
|
|
707
|
+
value: world,
|
|
708
|
+
enumerable: false,
|
|
709
|
+
configurable: false,
|
|
710
|
+
writable: false
|
|
711
|
+
});
|
|
712
|
+
for (const [key, buildFacet] of pluginEntries) {
|
|
713
|
+
const facet = buildFacet(world);
|
|
714
|
+
Object.defineProperty(facade, key, {
|
|
715
|
+
value: facet,
|
|
716
|
+
enumerable: true,
|
|
717
|
+
configurable: false,
|
|
718
|
+
writable: false
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
const notFacade = {};
|
|
722
|
+
for (const [key, buildFacet] of negativePluginEntries) {
|
|
723
|
+
const facet = buildFacet(world);
|
|
724
|
+
Object.defineProperty(notFacade, key, {
|
|
725
|
+
value: facet,
|
|
726
|
+
enumerable: true,
|
|
727
|
+
configurable: false,
|
|
728
|
+
writable: false
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
Object.defineProperty(facade, "not", {
|
|
732
|
+
value: notFacade,
|
|
733
|
+
enumerable: true,
|
|
734
|
+
configurable: false,
|
|
735
|
+
writable: false
|
|
736
|
+
});
|
|
737
|
+
return facade;
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
function createDefaultEnsureFactory() {
|
|
741
|
+
return createEnsureFactory(ensure, {});
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// src/plugins/runtime-assertions-plugin.ts
|
|
745
|
+
var runtimeAssertionsPlugin = () => ({ ensure: ensure2 }) => (world) => {
|
|
746
|
+
const defaultTableLabel = "step data table";
|
|
747
|
+
const defaultDocstringLabel = "step docstring";
|
|
748
|
+
function table(shape, options) {
|
|
749
|
+
return world.runtime.getTable(shape, options);
|
|
750
|
+
}
|
|
751
|
+
function consumeTable(shape, options) {
|
|
752
|
+
return world.runtime.consumeTable(shape, options);
|
|
753
|
+
}
|
|
754
|
+
function requireTable(shape, options) {
|
|
755
|
+
const { label, ...tableOptions } = options ?? {};
|
|
756
|
+
const table2 = consumeTable(shape, tableOptions);
|
|
757
|
+
return ensure2.always(table2, {
|
|
758
|
+
label: label ?? `Expected ${shape} ${defaultTableLabel} to be attached to the current step.`
|
|
759
|
+
}).toBeDefined().value;
|
|
760
|
+
}
|
|
761
|
+
function consumeRawTable(options) {
|
|
762
|
+
const tableInstance = consumeTable("headerless", options);
|
|
763
|
+
return tableInstance?.raw();
|
|
764
|
+
}
|
|
765
|
+
function requireRawTable(options) {
|
|
766
|
+
const { label, ...tableOptions } = options ?? {};
|
|
767
|
+
const raw = consumeRawTable(tableOptions);
|
|
768
|
+
return ensure2.always(raw, {
|
|
769
|
+
label: label ?? `Expected ${defaultTableLabel} to be attached to the current step.`
|
|
770
|
+
}).toBeDefined().value;
|
|
771
|
+
}
|
|
772
|
+
return {
|
|
773
|
+
hasTable(options) {
|
|
774
|
+
ensure2(world.runtime.hasTable, {
|
|
775
|
+
label: options?.label ?? `${defaultTableLabel} is present`
|
|
776
|
+
}).toBeTruthy();
|
|
777
|
+
},
|
|
778
|
+
hasDocstring(options) {
|
|
779
|
+
ensure2(world.runtime.hasDocstring, {
|
|
780
|
+
label: options?.label ?? `${defaultDocstringLabel} is present`
|
|
781
|
+
}).toBeTruthy();
|
|
782
|
+
},
|
|
783
|
+
docstring() {
|
|
784
|
+
return world.runtime.getDocstring();
|
|
785
|
+
},
|
|
786
|
+
consumeDocstring() {
|
|
787
|
+
return world.runtime.consumeDocstring();
|
|
788
|
+
},
|
|
789
|
+
requireDocstring(options) {
|
|
790
|
+
const docstring = world.runtime.consumeDocstring();
|
|
791
|
+
return ensure2.always(docstring, {
|
|
792
|
+
label: options?.label ?? `Expected ${defaultDocstringLabel} to be attached to the current step.`
|
|
793
|
+
}).toBeDefined().value;
|
|
794
|
+
},
|
|
795
|
+
table,
|
|
796
|
+
consumeTable,
|
|
797
|
+
requireTable,
|
|
798
|
+
rawTable() {
|
|
799
|
+
return world.runtime.getRawTable();
|
|
800
|
+
},
|
|
801
|
+
consumeRawTable,
|
|
802
|
+
requireRawTable,
|
|
803
|
+
stepMetadata() {
|
|
804
|
+
return world.runtime.getStepMetadata();
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
exports.EnsureError = EnsureError;
|
|
810
|
+
exports.createDefaultEnsureFactory = createDefaultEnsureFactory;
|
|
811
|
+
exports.createEnsureFactory = createEnsureFactory;
|
|
812
|
+
exports.ensure = ensure;
|
|
813
|
+
exports.runtimeAssertionsPlugin = runtimeAssertionsPlugin;
|
|
814
|
+
//# sourceMappingURL=out.js.map
|
|
815
|
+
//# sourceMappingURL=index.cjs.map
|