qunitx 1.2.10 → 1.2.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.build-hash +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/deno/index.js +78 -49
- package/dist/deno/module.js +4 -3
- package/dist/deno/test.js +7 -5
- package/dist/node/index.js +8 -1
- package/dist/node/module.js +4 -3
- package/dist/node/test.js +7 -5
- package/dist/shared/assert.d.ts +0 -2
- package/dist/shared/assert.js +17 -21
- package/dist/shared/filter-stack.d.ts +1 -0
- package/dist/shared/filter-stack.js +21 -0
- package/dist/shared/index.js +23 -16
- package/dist/shared/module-context.d.ts +1 -1
- package/dist/shared/module-context.js +6 -4
- package/package.json +1 -1
- package/shims/deno/index.ts +2 -0
- package/shims/deno/module.ts +5 -3
- package/shims/deno/test.ts +10 -5
- package/shims/shared/assert.ts +17 -22
- package/shims/shared/filter-stack.ts +35 -0
- package/shims/shared/index.ts +36 -19
- package/shims/shared/module-context.ts +6 -4
package/dist/node/test.js
CHANGED
|
@@ -26,16 +26,18 @@ function test(testName, runtimeOptions, testContent) {
|
|
|
26
26
|
const hookMeta = { context: userContext };
|
|
27
27
|
(async () => {
|
|
28
28
|
try {
|
|
29
|
-
|
|
29
|
+
const chain = context.module.moduleChain;
|
|
30
|
+
for (const mod of chain) {
|
|
30
31
|
for (const hook of mod.beforeEachHooks) {
|
|
31
32
|
await hook.call(userContext, context.assert, hookMeta);
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
await targetTestContent.call(userContext, context.assert, { testName, options: targetRuntimeOptions, context: userContext });
|
|
35
|
-
await context.assert.waitForAsyncOps();
|
|
36
|
-
for (
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
if (context.asyncOps.length > 0) await context.assert.waitForAsyncOps();
|
|
37
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
38
|
+
const hooks = chain[i].afterEachHooks;
|
|
39
|
+
for (let j = hooks.length - 1; j >= 0; j--) {
|
|
40
|
+
await hooks[j].call(userContext, context.assert, hookMeta);
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
resolve();
|
package/dist/shared/assert.d.ts
CHANGED
|
@@ -30,8 +30,6 @@ export default class Assert {
|
|
|
30
30
|
test: TestState;
|
|
31
31
|
/** @internal */
|
|
32
32
|
constructor(module: ModuleState | null, test?: TestState);
|
|
33
|
-
/** @internal */
|
|
34
|
-
private _incrementAssertionCount;
|
|
35
33
|
/**
|
|
36
34
|
* Sets the number of milliseconds after which the current test will fail if not yet complete.
|
|
37
35
|
*
|
package/dist/shared/assert.js
CHANGED
|
@@ -14,10 +14,6 @@ class Assert {
|
|
|
14
14
|
constructor(module, test) {
|
|
15
15
|
this.test = test || module.testContext;
|
|
16
16
|
}
|
|
17
|
-
/** @internal */
|
|
18
|
-
_incrementAssertionCount() {
|
|
19
|
-
this.test.totalExecutedAssertions++;
|
|
20
|
-
}
|
|
21
17
|
/**
|
|
22
18
|
* Sets the number of milliseconds after which the current test will fail if not yet complete.
|
|
23
19
|
*
|
|
@@ -145,7 +141,7 @@ class Assert {
|
|
|
145
141
|
* ```
|
|
146
142
|
*/
|
|
147
143
|
pushResult(resultInfo = {}) {
|
|
148
|
-
this.
|
|
144
|
+
this.test.totalExecutedAssertions++;
|
|
149
145
|
if (!resultInfo.result) {
|
|
150
146
|
throw new Assert.AssertionError({
|
|
151
147
|
actual: resultInfo.actual,
|
|
@@ -169,7 +165,7 @@ class Assert {
|
|
|
169
165
|
* ```
|
|
170
166
|
*/
|
|
171
167
|
ok(state, message) {
|
|
172
|
-
this.
|
|
168
|
+
this.test.totalExecutedAssertions++;
|
|
173
169
|
if (!state) {
|
|
174
170
|
throw new Assert.AssertionError({
|
|
175
171
|
actual: state,
|
|
@@ -192,7 +188,7 @@ class Assert {
|
|
|
192
188
|
* ```
|
|
193
189
|
*/
|
|
194
190
|
notOk(state, message) {
|
|
195
|
-
this.
|
|
191
|
+
this.test.totalExecutedAssertions++;
|
|
196
192
|
if (state) {
|
|
197
193
|
throw new Assert.AssertionError({
|
|
198
194
|
actual: state,
|
|
@@ -214,7 +210,7 @@ class Assert {
|
|
|
214
210
|
* ```
|
|
215
211
|
*/
|
|
216
212
|
true(state, message) {
|
|
217
|
-
this.
|
|
213
|
+
this.test.totalExecutedAssertions++;
|
|
218
214
|
if (state !== true) {
|
|
219
215
|
throw new Assert.AssertionError({
|
|
220
216
|
actual: state,
|
|
@@ -236,7 +232,7 @@ class Assert {
|
|
|
236
232
|
* ```
|
|
237
233
|
*/
|
|
238
234
|
false(state, message) {
|
|
239
|
-
this.
|
|
235
|
+
this.test.totalExecutedAssertions++;
|
|
240
236
|
if (state !== false) {
|
|
241
237
|
throw new Assert.AssertionError({
|
|
242
238
|
actual: state,
|
|
@@ -262,7 +258,7 @@ class Assert {
|
|
|
262
258
|
* ```
|
|
263
259
|
*/
|
|
264
260
|
equal(actual, expected, message) {
|
|
265
|
-
this.
|
|
261
|
+
this.test.totalExecutedAssertions++;
|
|
266
262
|
if (actual != expected) {
|
|
267
263
|
throw new Assert.AssertionError({
|
|
268
264
|
actual,
|
|
@@ -286,7 +282,7 @@ class Assert {
|
|
|
286
282
|
* ```
|
|
287
283
|
*/
|
|
288
284
|
notEqual(actual, expected, message) {
|
|
289
|
-
this.
|
|
285
|
+
this.test.totalExecutedAssertions++;
|
|
290
286
|
if (actual == expected) {
|
|
291
287
|
throw new Assert.AssertionError({
|
|
292
288
|
actual,
|
|
@@ -314,7 +310,7 @@ class Assert {
|
|
|
314
310
|
* ```
|
|
315
311
|
*/
|
|
316
312
|
propEqual(actual, expected, message) {
|
|
317
|
-
this.
|
|
313
|
+
this.test.totalExecutedAssertions++;
|
|
318
314
|
const targetActual = objectValues(actual);
|
|
319
315
|
const targetExpected = objectValues(expected);
|
|
320
316
|
if (!Assert.QUnit.equiv(targetActual, targetExpected)) {
|
|
@@ -340,7 +336,7 @@ class Assert {
|
|
|
340
336
|
* ```
|
|
341
337
|
*/
|
|
342
338
|
notPropEqual(actual, expected, message) {
|
|
343
|
-
this.
|
|
339
|
+
this.test.totalExecutedAssertions++;
|
|
344
340
|
const targetActual = objectValues(actual);
|
|
345
341
|
const targetExpected = objectValues(expected);
|
|
346
342
|
if (Assert.QUnit.equiv(targetActual, targetExpected)) {
|
|
@@ -366,7 +362,7 @@ class Assert {
|
|
|
366
362
|
* ```
|
|
367
363
|
*/
|
|
368
364
|
propContains(actual, expected, message) {
|
|
369
|
-
this.
|
|
365
|
+
this.test.totalExecutedAssertions++;
|
|
370
366
|
const targetActual = objectValuesSubset(actual, expected);
|
|
371
367
|
const targetExpected = objectValues(expected, false);
|
|
372
368
|
if (!Assert.QUnit.equiv(targetActual, targetExpected)) {
|
|
@@ -392,7 +388,7 @@ class Assert {
|
|
|
392
388
|
* ```
|
|
393
389
|
*/
|
|
394
390
|
notPropContains(actual, expected, message) {
|
|
395
|
-
this.
|
|
391
|
+
this.test.totalExecutedAssertions++;
|
|
396
392
|
const targetActual = objectValuesSubset(actual, expected);
|
|
397
393
|
const targetExpected = objectValues(expected);
|
|
398
394
|
if (Assert.QUnit.equiv(targetActual, targetExpected)) {
|
|
@@ -418,7 +414,7 @@ class Assert {
|
|
|
418
414
|
* ```
|
|
419
415
|
*/
|
|
420
416
|
deepEqual(actual, expected, message) {
|
|
421
|
-
this.
|
|
417
|
+
this.test.totalExecutedAssertions++;
|
|
422
418
|
if (!Assert.QUnit.equiv(actual, expected)) {
|
|
423
419
|
throw new Assert.AssertionError({
|
|
424
420
|
actual,
|
|
@@ -442,7 +438,7 @@ class Assert {
|
|
|
442
438
|
* ```
|
|
443
439
|
*/
|
|
444
440
|
notDeepEqual(actual, expected, message) {
|
|
445
|
-
this.
|
|
441
|
+
this.test.totalExecutedAssertions++;
|
|
446
442
|
if (Assert.QUnit.equiv(actual, expected)) {
|
|
447
443
|
throw new Assert.AssertionError({
|
|
448
444
|
actual,
|
|
@@ -466,7 +462,7 @@ class Assert {
|
|
|
466
462
|
* ```
|
|
467
463
|
*/
|
|
468
464
|
strictEqual(actual, expected, message) {
|
|
469
|
-
this.
|
|
465
|
+
this.test.totalExecutedAssertions++;
|
|
470
466
|
if (actual !== expected) {
|
|
471
467
|
throw new Assert.AssertionError({
|
|
472
468
|
actual,
|
|
@@ -490,7 +486,7 @@ class Assert {
|
|
|
490
486
|
* ```
|
|
491
487
|
*/
|
|
492
488
|
notStrictEqual(actual, expected, message) {
|
|
493
|
-
this.
|
|
489
|
+
this.test.totalExecutedAssertions++;
|
|
494
490
|
if (actual === expected) {
|
|
495
491
|
throw new Assert.AssertionError({
|
|
496
492
|
actual,
|
|
@@ -517,7 +513,7 @@ class Assert {
|
|
|
517
513
|
* ```
|
|
518
514
|
*/
|
|
519
515
|
throws(blockFn, expectedInput, assertionMessage) {
|
|
520
|
-
this.
|
|
516
|
+
this.test.totalExecutedAssertions++;
|
|
521
517
|
const [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, "throws");
|
|
522
518
|
if (typeof blockFn !== "function") {
|
|
523
519
|
throw new Assert.AssertionError({
|
|
@@ -575,7 +571,7 @@ class Assert {
|
|
|
575
571
|
* ```
|
|
576
572
|
*/
|
|
577
573
|
async rejects(promise, expectedInput, assertionMessage) {
|
|
578
|
-
this.
|
|
574
|
+
this.test.totalExecutedAssertions++;
|
|
579
575
|
const [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, "rejects");
|
|
580
576
|
const then = promise && promise.then;
|
|
581
577
|
if (typeof then !== "function") {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function filterStack(stack: string | undefined): string | undefined;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const FILTER_PATTERNS = [
|
|
2
|
+
/\bnode:internal\/test_runner\//,
|
|
3
|
+
/\bnode:async_hooks\b/
|
|
4
|
+
];
|
|
5
|
+
function isDebugEnabled() {
|
|
6
|
+
try {
|
|
7
|
+
const proc = globalThis.process;
|
|
8
|
+
if (proc?.env?.QUNITX_DEBUG === "1") return true;
|
|
9
|
+
const deno = globalThis.Deno;
|
|
10
|
+
if (deno?.env?.get?.("QUNITX_DEBUG") === "1") return true;
|
|
11
|
+
} catch {
|
|
12
|
+
}
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
function filterStack(stack) {
|
|
16
|
+
if (!stack || isDebugEnabled()) return stack;
|
|
17
|
+
return stack.split("\n").filter((line) => !FILTER_PATTERNS.some((p) => p.test(line))).join("\n");
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
filterStack
|
|
21
|
+
};
|
package/dist/shared/index.js
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
const hasOwn = Object.prototype.hasOwnProperty;
|
|
2
|
+
const objToString = Object.prototype.toString;
|
|
2
3
|
function objectType(obj) {
|
|
3
|
-
if (
|
|
4
|
-
|
|
4
|
+
if (obj === null) return "null";
|
|
5
|
+
const t = typeof obj;
|
|
6
|
+
switch (t) {
|
|
7
|
+
case "undefined":
|
|
8
|
+
case "string":
|
|
9
|
+
case "boolean":
|
|
10
|
+
case "function":
|
|
11
|
+
case "symbol":
|
|
12
|
+
case "bigint":
|
|
13
|
+
return t;
|
|
14
|
+
case "number":
|
|
15
|
+
return obj !== obj ? "nan" : "number";
|
|
5
16
|
}
|
|
6
|
-
|
|
7
|
-
return "null";
|
|
8
|
-
}
|
|
9
|
-
const type = Object.prototype.toString.call(obj).slice(8, -1);
|
|
17
|
+
const type = objToString.call(obj).slice(8, -1);
|
|
10
18
|
switch (type) {
|
|
11
19
|
case "Number":
|
|
12
|
-
|
|
13
|
-
return "nan";
|
|
14
|
-
}
|
|
15
|
-
return "number";
|
|
20
|
+
return isNaN(obj) ? "nan" : "number";
|
|
16
21
|
case "String":
|
|
17
22
|
case "Boolean":
|
|
18
23
|
case "Array":
|
|
@@ -24,23 +29,25 @@ function objectType(obj) {
|
|
|
24
29
|
case "Symbol":
|
|
25
30
|
return type.toLowerCase();
|
|
26
31
|
default:
|
|
27
|
-
return
|
|
32
|
+
return "object";
|
|
28
33
|
}
|
|
29
34
|
}
|
|
30
35
|
function objectValues(obj, allowArray = true) {
|
|
31
|
-
const vals = allowArray &&
|
|
36
|
+
const vals = allowArray && Array.isArray(obj) ? [] : {};
|
|
32
37
|
for (const key in obj) {
|
|
33
38
|
if (hasOwn.call(obj, key)) {
|
|
34
39
|
const val = obj[key];
|
|
35
|
-
|
|
40
|
+
const t = typeof val;
|
|
41
|
+
const isObjectish = val !== null && (t === "object" || t === "function");
|
|
42
|
+
vals[key] = isObjectish ? objectValues(val, allowArray) : val;
|
|
36
43
|
}
|
|
37
44
|
}
|
|
38
45
|
return vals;
|
|
39
46
|
}
|
|
40
47
|
function objectValuesSubset(obj, model) {
|
|
41
|
-
if (obj
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
if (obj === null) return obj;
|
|
49
|
+
const objT = typeof obj;
|
|
50
|
+
if (objT !== "object" && objT !== "function") return obj;
|
|
44
51
|
const subset = {};
|
|
45
52
|
for (const key in model) {
|
|
46
53
|
if (hasOwn.call(model, key) && hasOwn.call(obj, key)) {
|
|
@@ -4,7 +4,7 @@ import TestContext from './test-context.d.ts';
|
|
|
4
4
|
export default class ModuleContext {
|
|
5
5
|
static Assert: typeof Assert;
|
|
6
6
|
static currentModuleChain: ModuleContext[];
|
|
7
|
-
static get lastModule(): ModuleContext
|
|
7
|
+
static get lastModule(): ModuleContext;
|
|
8
8
|
name: string;
|
|
9
9
|
assert: Assert;
|
|
10
10
|
userContext: Record<string, unknown>;
|
|
@@ -3,7 +3,8 @@ class ModuleContext {
|
|
|
3
3
|
static Assert;
|
|
4
4
|
static currentModuleChain = [];
|
|
5
5
|
static get lastModule() {
|
|
6
|
-
|
|
6
|
+
const chain = this.currentModuleChain;
|
|
7
|
+
return chain[chain.length - 1];
|
|
7
8
|
}
|
|
8
9
|
name;
|
|
9
10
|
assert;
|
|
@@ -15,9 +16,10 @@ class ModuleContext {
|
|
|
15
16
|
afterEachHooks = [];
|
|
16
17
|
tests = [];
|
|
17
18
|
constructor(name) {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
this
|
|
19
|
+
const chain = ModuleContext.currentModuleChain;
|
|
20
|
+
const parentModule = chain[chain.length - 1];
|
|
21
|
+
chain.push(this);
|
|
22
|
+
this.moduleChain = chain.slice();
|
|
21
23
|
this.name = parentModule ? `${parentModule.name} > ${name}` : name;
|
|
22
24
|
this.assert = new ModuleContext.Assert(this);
|
|
23
25
|
this.userContext = parentModule ? Object.create(parentModule.userContext) : /* @__PURE__ */ Object.create(null);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qunitx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.16",
|
|
5
5
|
"description": "Universal test library — run the same test file in Node.js, Deno, and the browser with QUnit's battle-tested assertion API",
|
|
6
6
|
"author": "Izel Nakri",
|
|
7
7
|
"license": "MIT",
|
package/shims/deno/index.ts
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
import '../../vendor/qunit.js';
|
|
28
28
|
import { AssertionError as DenoAssertionError } from 'jsr:@std/assert';
|
|
29
29
|
import Assert from '../shared/assert.ts';
|
|
30
|
+
import { filterStack } from '../shared/filter-stack.ts';
|
|
30
31
|
import ModuleContext from '../shared/module-context.ts';
|
|
31
32
|
import TestContext from '../shared/test-context.ts';
|
|
32
33
|
import type { AssertionErrorOptions } from '../types.ts';
|
|
@@ -55,6 +56,7 @@ export class AssertionError extends DenoAssertionError {
|
|
|
55
56
|
constructor(object: AssertionErrorOptions) {
|
|
56
57
|
super(object.message ?? 'Assertion failed');
|
|
57
58
|
if (object.stackStartFn) Error.captureStackTrace(this, object.stackStartFn);
|
|
59
|
+
this.stack = filterStack(this.stack);
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
|
package/shims/deno/module.ts
CHANGED
|
@@ -73,10 +73,12 @@ export default function module(
|
|
|
73
73
|
const allAsyncOps = moduleContext.tests.flatMap((t) => t.asyncOps);
|
|
74
74
|
if (allAsyncOps.length > 0) await Promise.all(allAsyncOps);
|
|
75
75
|
|
|
76
|
-
const
|
|
76
|
+
const tests = moduleContext.tests;
|
|
77
|
+
const lastTest = tests[tests.length - 1];
|
|
77
78
|
if (lastTest) {
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
// Indexed reverse iteration avoids `afterHooks.toReversed()`'s per-call alloc.
|
|
80
|
+
for (let i = afterHooks.length - 1; i >= 0; i--) {
|
|
81
|
+
await afterHooks[i]!.call(lastTest.userContext, lastTest.assert!, { context: lastTest.userContext });
|
|
80
82
|
}
|
|
81
83
|
}
|
|
82
84
|
|
package/shims/deno/test.ts
CHANGED
|
@@ -74,7 +74,8 @@ export default function test(
|
|
|
74
74
|
|
|
75
75
|
(async () => {
|
|
76
76
|
try {
|
|
77
|
-
|
|
77
|
+
const chain = context.module!.moduleChain;
|
|
78
|
+
for (const mod of chain) {
|
|
78
79
|
for (const hook of mod.beforeEachHooks) {
|
|
79
80
|
await hook.call(userContext, context.assert!, hookMeta);
|
|
80
81
|
}
|
|
@@ -82,11 +83,15 @@ export default function test(
|
|
|
82
83
|
|
|
83
84
|
await targetTestContent.call(userContext, context.assert!, { testName, options: targetRuntimeOptions, context: userContext });
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
// Skip the microtask hop when no `assert.async()` callbacks were registered.
|
|
87
|
+
if (context.asyncOps.length > 0) await context.assert!.waitForAsyncOps();
|
|
86
88
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
// Indexed reverse iteration avoids the per-test allocations from
|
|
90
|
+
// `chain.toReversed()` + per-module `hooks.toReversed()`.
|
|
91
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
92
|
+
const hooks = chain[i]!.afterEachHooks;
|
|
93
|
+
for (let j = hooks.length - 1; j >= 0; j--) {
|
|
94
|
+
await hooks[j]!.call(userContext, context.assert!, hookMeta);
|
|
90
95
|
}
|
|
91
96
|
}
|
|
92
97
|
|
package/shims/shared/assert.ts
CHANGED
|
@@ -40,11 +40,6 @@ export default class Assert {
|
|
|
40
40
|
this.test = test || (module as ModuleState).testContext;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
/** @internal */
|
|
44
|
-
private _incrementAssertionCount() {
|
|
45
|
-
this.test.totalExecutedAssertions++;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
43
|
/**
|
|
49
44
|
* Sets the number of milliseconds after which the current test will fail if not yet complete.
|
|
50
45
|
*
|
|
@@ -186,7 +181,7 @@ export default class Assert {
|
|
|
186
181
|
* ```
|
|
187
182
|
*/
|
|
188
183
|
pushResult(resultInfo: PushResultInfo = {}): this {
|
|
189
|
-
this.
|
|
184
|
+
this.test.totalExecutedAssertions++;
|
|
190
185
|
if (!resultInfo.result) {
|
|
191
186
|
throw new Assert.AssertionError({
|
|
192
187
|
actual: resultInfo.actual,
|
|
@@ -212,7 +207,7 @@ export default class Assert {
|
|
|
212
207
|
* ```
|
|
213
208
|
*/
|
|
214
209
|
ok(state: unknown, message?: string): void {
|
|
215
|
-
this.
|
|
210
|
+
this.test.totalExecutedAssertions++;
|
|
216
211
|
if (!state) {
|
|
217
212
|
throw new Assert.AssertionError({
|
|
218
213
|
actual: state,
|
|
@@ -236,7 +231,7 @@ export default class Assert {
|
|
|
236
231
|
* ```
|
|
237
232
|
*/
|
|
238
233
|
notOk(state: unknown, message?: string): void {
|
|
239
|
-
this.
|
|
234
|
+
this.test.totalExecutedAssertions++;
|
|
240
235
|
if (state) {
|
|
241
236
|
throw new Assert.AssertionError({
|
|
242
237
|
actual: state,
|
|
@@ -259,7 +254,7 @@ export default class Assert {
|
|
|
259
254
|
* ```
|
|
260
255
|
*/
|
|
261
256
|
true(state: unknown, message?: string): void {
|
|
262
|
-
this.
|
|
257
|
+
this.test.totalExecutedAssertions++;
|
|
263
258
|
if (state !== true) {
|
|
264
259
|
throw new Assert.AssertionError({
|
|
265
260
|
actual: state,
|
|
@@ -282,7 +277,7 @@ export default class Assert {
|
|
|
282
277
|
* ```
|
|
283
278
|
*/
|
|
284
279
|
false(state: unknown, message?: string): void {
|
|
285
|
-
this.
|
|
280
|
+
this.test.totalExecutedAssertions++;
|
|
286
281
|
if (state !== false) {
|
|
287
282
|
throw new Assert.AssertionError({
|
|
288
283
|
actual: state,
|
|
@@ -309,7 +304,7 @@ export default class Assert {
|
|
|
309
304
|
* ```
|
|
310
305
|
*/
|
|
311
306
|
equal(actual: unknown, expected: unknown, message?: string): void {
|
|
312
|
-
this.
|
|
307
|
+
this.test.totalExecutedAssertions++;
|
|
313
308
|
if (actual != expected) {
|
|
314
309
|
throw new Assert.AssertionError({
|
|
315
310
|
actual,
|
|
@@ -334,7 +329,7 @@ export default class Assert {
|
|
|
334
329
|
* ```
|
|
335
330
|
*/
|
|
336
331
|
notEqual(actual: unknown, expected: unknown, message?: string): void {
|
|
337
|
-
this.
|
|
332
|
+
this.test.totalExecutedAssertions++;
|
|
338
333
|
if (actual == expected) {
|
|
339
334
|
throw new Assert.AssertionError({
|
|
340
335
|
actual,
|
|
@@ -363,7 +358,7 @@ export default class Assert {
|
|
|
363
358
|
* ```
|
|
364
359
|
*/
|
|
365
360
|
propEqual(actual: unknown, expected: unknown, message?: string): void {
|
|
366
|
-
this.
|
|
361
|
+
this.test.totalExecutedAssertions++;
|
|
367
362
|
const targetActual = objectValues(actual);
|
|
368
363
|
const targetExpected = objectValues(expected);
|
|
369
364
|
if (!Assert.QUnit.equiv(targetActual, targetExpected)) {
|
|
@@ -390,7 +385,7 @@ export default class Assert {
|
|
|
390
385
|
* ```
|
|
391
386
|
*/
|
|
392
387
|
notPropEqual(actual: unknown, expected: unknown, message?: string): void {
|
|
393
|
-
this.
|
|
388
|
+
this.test.totalExecutedAssertions++;
|
|
394
389
|
const targetActual = objectValues(actual);
|
|
395
390
|
const targetExpected = objectValues(expected);
|
|
396
391
|
if (Assert.QUnit.equiv(targetActual, targetExpected)) {
|
|
@@ -417,7 +412,7 @@ export default class Assert {
|
|
|
417
412
|
* ```
|
|
418
413
|
*/
|
|
419
414
|
propContains(actual: unknown, expected: unknown, message?: string): void {
|
|
420
|
-
this.
|
|
415
|
+
this.test.totalExecutedAssertions++;
|
|
421
416
|
const targetActual = objectValuesSubset(actual, expected);
|
|
422
417
|
const targetExpected = objectValues(expected, false);
|
|
423
418
|
if (!Assert.QUnit.equiv(targetActual, targetExpected)) {
|
|
@@ -444,7 +439,7 @@ export default class Assert {
|
|
|
444
439
|
* ```
|
|
445
440
|
*/
|
|
446
441
|
notPropContains(actual: unknown, expected: unknown, message?: string): void {
|
|
447
|
-
this.
|
|
442
|
+
this.test.totalExecutedAssertions++;
|
|
448
443
|
const targetActual = objectValuesSubset(actual, expected);
|
|
449
444
|
const targetExpected = objectValues(expected);
|
|
450
445
|
if (Assert.QUnit.equiv(targetActual, targetExpected)) {
|
|
@@ -471,7 +466,7 @@ export default class Assert {
|
|
|
471
466
|
* ```
|
|
472
467
|
*/
|
|
473
468
|
deepEqual(actual: unknown, expected: unknown, message?: string): void {
|
|
474
|
-
this.
|
|
469
|
+
this.test.totalExecutedAssertions++;
|
|
475
470
|
if (!Assert.QUnit.equiv(actual, expected)) {
|
|
476
471
|
throw new Assert.AssertionError({
|
|
477
472
|
actual,
|
|
@@ -496,7 +491,7 @@ export default class Assert {
|
|
|
496
491
|
* ```
|
|
497
492
|
*/
|
|
498
493
|
notDeepEqual(actual: unknown, expected: unknown, message?: string): void {
|
|
499
|
-
this.
|
|
494
|
+
this.test.totalExecutedAssertions++;
|
|
500
495
|
if (Assert.QUnit.equiv(actual, expected)) {
|
|
501
496
|
throw new Assert.AssertionError({
|
|
502
497
|
actual,
|
|
@@ -521,7 +516,7 @@ export default class Assert {
|
|
|
521
516
|
* ```
|
|
522
517
|
*/
|
|
523
518
|
strictEqual(actual: unknown, expected: unknown, message?: string): void {
|
|
524
|
-
this.
|
|
519
|
+
this.test.totalExecutedAssertions++;
|
|
525
520
|
if (actual !== expected) {
|
|
526
521
|
throw new Assert.AssertionError({
|
|
527
522
|
actual,
|
|
@@ -546,7 +541,7 @@ export default class Assert {
|
|
|
546
541
|
* ```
|
|
547
542
|
*/
|
|
548
543
|
notStrictEqual(actual: unknown, expected: unknown, message?: string): void {
|
|
549
|
-
this.
|
|
544
|
+
this.test.totalExecutedAssertions++;
|
|
550
545
|
if (actual === expected) {
|
|
551
546
|
throw new Assert.AssertionError({
|
|
552
547
|
actual,
|
|
@@ -574,7 +569,7 @@ export default class Assert {
|
|
|
574
569
|
* ```
|
|
575
570
|
*/
|
|
576
571
|
throws(blockFn: unknown, expectedInput?: unknown, assertionMessage?: string): void {
|
|
577
|
-
this.
|
|
572
|
+
this.test.totalExecutedAssertions++;
|
|
578
573
|
const [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, 'throws');
|
|
579
574
|
if (typeof blockFn !== 'function') {
|
|
580
575
|
throw new Assert.AssertionError({
|
|
@@ -637,7 +632,7 @@ export default class Assert {
|
|
|
637
632
|
* ```
|
|
638
633
|
*/
|
|
639
634
|
async rejects(promise: unknown, expectedInput?: unknown, assertionMessage?: string): Promise<void> {
|
|
640
|
-
this.
|
|
635
|
+
this.test.totalExecutedAssertions++;
|
|
641
636
|
const [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, 'rejects');
|
|
642
637
|
const then = promise && (promise as PromiseLike<unknown>).then;
|
|
643
638
|
if (typeof then !== 'function') {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Strips runtime-internal frames from an Error's `.stack` so failing-test output
|
|
2
|
+
// shows the user's code first and qunitx's wrapper frames second, with no trailing
|
|
3
|
+
// pages of `node:internal/test_runner/...` and `node:async_hooks:...` lines.
|
|
4
|
+
//
|
|
5
|
+
// Filtered prefixes are stable Node-internal modules (their paths haven't
|
|
6
|
+
// changed across recent Node versions) and unambiguously not user code. We do
|
|
7
|
+
// NOT filter qunitx's own dist frames — they're exactly two short lines per
|
|
8
|
+
// failure and are useful when a bug actually lands in qunitx itself.
|
|
9
|
+
//
|
|
10
|
+
// QUNITX_DEBUG=1 disables filtering entirely, for the rare case where someone
|
|
11
|
+
// is debugging qunitx and wants the full V8 stack.
|
|
12
|
+
const FILTER_PATTERNS = [
|
|
13
|
+
/\bnode:internal\/test_runner\//,
|
|
14
|
+
/\bnode:async_hooks\b/,
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
function isDebugEnabled(): boolean {
|
|
18
|
+
try {
|
|
19
|
+
const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;
|
|
20
|
+
if (proc?.env?.QUNITX_DEBUG === '1') return true;
|
|
21
|
+
const deno = (globalThis as { Deno?: { env?: { get(key: string): string | undefined } } }).Deno;
|
|
22
|
+
if (deno?.env?.get?.('QUNITX_DEBUG') === '1') return true;
|
|
23
|
+
} catch {
|
|
24
|
+
// Deno without --allow-env throws on env access; treat as non-debug.
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function filterStack(stack: string | undefined): string | undefined {
|
|
30
|
+
if (!stack || isDebugEnabled()) return stack;
|
|
31
|
+
return stack
|
|
32
|
+
.split('\n')
|
|
33
|
+
.filter((line) => !FILTER_PATTERNS.some((p) => p.test(line)))
|
|
34
|
+
.join('\n');
|
|
35
|
+
}
|