qunitx 1.2.4 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -3
- package/dist/.build-hash +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/browser/index.d.ts +99 -2
- package/dist/browser/index.js +87 -8
- package/dist/deno/index.js +64 -26
- package/dist/deno/module.d.ts +3 -0
- package/dist/deno/module.js +7 -3
- package/dist/deno/test.d.ts +2 -0
- package/dist/deno/test.js +27 -15
- package/dist/node/module.d.ts +37 -0
- package/dist/node/module.js +7 -3
- package/dist/node/test.d.ts +35 -0
- package/dist/node/test.js +27 -15
- package/dist/shared/assert.js +1 -0
- package/dist/shared/module-context.d.ts +1 -1
- package/dist/shared/test-context.d.ts +4 -1
- package/dist/shared/test-context.js +21 -0
- package/dist/types.d.ts +7 -3
- package/package.json +8 -7
- package/shims/deno/module.ts +31 -9
- package/shims/deno/test.ts +33 -19
- package/shims/shared/assert.ts +1 -0
- package/shims/shared/module-context.ts +1 -1
- package/shims/shared/test-context.ts +25 -1
- package/shims/types.ts +5 -4
package/dist/deno/index.js
CHANGED
|
@@ -150,7 +150,7 @@ var require_qunit = __commonJS({
|
|
|
150
150
|
var g = getGlobalThis();
|
|
151
151
|
var console$1 = g.console;
|
|
152
152
|
var setTimeout$1 = g.setTimeout;
|
|
153
|
-
var
|
|
153
|
+
var clearTimeout2 = g.clearTimeout;
|
|
154
154
|
var process$1 = g.process;
|
|
155
155
|
var window$1 = g.window;
|
|
156
156
|
var document = window$1 && window$1.document;
|
|
@@ -1317,7 +1317,7 @@ var require_qunit = __commonJS({
|
|
|
1317
1317
|
}
|
|
1318
1318
|
this.test.timeout = duration;
|
|
1319
1319
|
if (config.timeout) {
|
|
1320
|
-
|
|
1320
|
+
clearTimeout2(config.timeout);
|
|
1321
1321
|
config.timeout = null;
|
|
1322
1322
|
if (config.timeoutHandler && this.test.timeout > 0) {
|
|
1323
1323
|
this.test.internalResetTimeout(this.test.timeout);
|
|
@@ -2341,7 +2341,7 @@ var require_qunit = __commonJS({
|
|
|
2341
2341
|
finish: function finish() {
|
|
2342
2342
|
config.current = this;
|
|
2343
2343
|
if (setTimeout$1) {
|
|
2344
|
-
|
|
2344
|
+
clearTimeout2(this.timeout);
|
|
2345
2345
|
config.timeoutHandler = null;
|
|
2346
2346
|
}
|
|
2347
2347
|
this.callback = void 0;
|
|
@@ -2554,7 +2554,7 @@ var require_qunit = __commonJS({
|
|
|
2554
2554
|
* @param {number} timeoutDuration
|
|
2555
2555
|
*/
|
|
2556
2556
|
internalResetTimeout: function internalResetTimeout(timeoutDuration) {
|
|
2557
|
-
|
|
2557
|
+
clearTimeout2(config.timeout);
|
|
2558
2558
|
config.timeout = setTimeout$1(config.timeoutHandler(timeoutDuration), timeoutDuration);
|
|
2559
2559
|
},
|
|
2560
2560
|
/**
|
|
@@ -2662,10 +2662,10 @@ var require_qunit = __commonJS({
|
|
|
2662
2662
|
internalRecover(test4);
|
|
2663
2663
|
};
|
|
2664
2664
|
};
|
|
2665
|
-
|
|
2665
|
+
clearTimeout2(config.timeout);
|
|
2666
2666
|
config.timeout = setTimeout$1(config.timeoutHandler(timeoutDuration), timeoutDuration);
|
|
2667
2667
|
} else {
|
|
2668
|
-
|
|
2668
|
+
clearTimeout2(config.timeout);
|
|
2669
2669
|
config.timeout = setTimeout$1(function() {
|
|
2670
2670
|
config.timeout = null;
|
|
2671
2671
|
if (!config._deprecated_timeout_shown) {
|
|
@@ -2960,12 +2960,12 @@ var require_qunit = __commonJS({
|
|
|
2960
2960
|
return;
|
|
2961
2961
|
}
|
|
2962
2962
|
if (setTimeout$1) {
|
|
2963
|
-
|
|
2963
|
+
clearTimeout2(config.timeout);
|
|
2964
2964
|
config.timeout = setTimeout$1(function() {
|
|
2965
2965
|
if (test4.pauses.size > 0) {
|
|
2966
2966
|
return;
|
|
2967
2967
|
}
|
|
2968
|
-
|
|
2968
|
+
clearTimeout2(config.timeout);
|
|
2969
2969
|
config.timeout = null;
|
|
2970
2970
|
config.blocking = false;
|
|
2971
2971
|
config.pq.advance();
|
|
@@ -6167,6 +6167,7 @@ var Assert = class _Assert {
|
|
|
6167
6167
|
throw new Error("assert.timeout() expects a positive integer.");
|
|
6168
6168
|
}
|
|
6169
6169
|
this.test.timeout = number;
|
|
6170
|
+
this.test.setTimeoutDuration(number);
|
|
6170
6171
|
}
|
|
6171
6172
|
/**
|
|
6172
6173
|
* Records a named step. Use with {@linkcode Assert.prototype.verifySteps} to assert that
|
|
@@ -6797,6 +6798,26 @@ var TestContext = class _TestContext {
|
|
|
6797
6798
|
set timeout(value) {
|
|
6798
6799
|
this.#timeout = value;
|
|
6799
6800
|
}
|
|
6801
|
+
rejectTimeout;
|
|
6802
|
+
#timeoutHandle;
|
|
6803
|
+
#timedOut = false;
|
|
6804
|
+
setTimeoutDuration(ms) {
|
|
6805
|
+
if (this.#timeoutHandle !== void 0) {
|
|
6806
|
+
clearTimeout(this.#timeoutHandle);
|
|
6807
|
+
this.#timeoutHandle = void 0;
|
|
6808
|
+
}
|
|
6809
|
+
if (!this.rejectTimeout) return;
|
|
6810
|
+
this.#timeoutHandle = setTimeout(() => {
|
|
6811
|
+
this.#timedOut = true;
|
|
6812
|
+
this.rejectTimeout(new Error(`Test timed out after ${ms}ms`));
|
|
6813
|
+
}, ms);
|
|
6814
|
+
}
|
|
6815
|
+
clearTimeoutHandle() {
|
|
6816
|
+
if (this.#timeoutHandle !== void 0) {
|
|
6817
|
+
clearTimeout(this.#timeoutHandle);
|
|
6818
|
+
this.#timeoutHandle = void 0;
|
|
6819
|
+
}
|
|
6820
|
+
}
|
|
6800
6821
|
#steps = [];
|
|
6801
6822
|
get steps() {
|
|
6802
6823
|
return this.#steps;
|
|
@@ -6828,6 +6849,7 @@ var TestContext = class _TestContext {
|
|
|
6828
6849
|
}
|
|
6829
6850
|
}
|
|
6830
6851
|
finish() {
|
|
6852
|
+
if (this.#timedOut) return;
|
|
6831
6853
|
if (this.totalExecutedAssertions === 0) {
|
|
6832
6854
|
this.assert.pushResult({
|
|
6833
6855
|
result: false,
|
|
@@ -7686,7 +7708,7 @@ function module(moduleName, runtimeOptions, moduleContent) {
|
|
|
7686
7708
|
const firstTest = moduleContext.tests[0];
|
|
7687
7709
|
const beforeAssert = firstTest ? firstTest.assert : moduleContext.assert;
|
|
7688
7710
|
for (const hook of beforeHooks) {
|
|
7689
|
-
await hook.call(moduleContext.userContext, beforeAssert);
|
|
7711
|
+
await hook.call(moduleContext.userContext, beforeAssert, { context: moduleContext.userContext });
|
|
7690
7712
|
}
|
|
7691
7713
|
});
|
|
7692
7714
|
afterAll(async () => {
|
|
@@ -7696,7 +7718,7 @@ function module(moduleName, runtimeOptions, moduleContent) {
|
|
|
7696
7718
|
const lastTest = moduleContext.tests[moduleContext.tests.length - 1];
|
|
7697
7719
|
if (lastTest) {
|
|
7698
7720
|
for (let j = afterHooks.length - 1; j >= 0; j--) {
|
|
7699
|
-
await afterHooks[j].call(lastTest.userContext, lastTest.assert);
|
|
7721
|
+
await afterHooks[j].call(lastTest.userContext, lastTest.assert, { context: lastTest.userContext });
|
|
7700
7722
|
}
|
|
7701
7723
|
}
|
|
7702
7724
|
for (let i = 0, len = moduleContext.tests.length; i < len; i++) {
|
|
@@ -7716,7 +7738,7 @@ function module(moduleName, runtimeOptions, moduleContent) {
|
|
|
7716
7738
|
after(afterFn) {
|
|
7717
7739
|
afterHooks.push(afterFn);
|
|
7718
7740
|
}
|
|
7719
|
-
}, { moduleName, options: runtimeOptions });
|
|
7741
|
+
}, { moduleName, options: runtimeOptions, context: moduleContext.userContext });
|
|
7720
7742
|
ModuleContext.currentModuleChain.pop();
|
|
7721
7743
|
});
|
|
7722
7744
|
}
|
|
@@ -7724,6 +7746,10 @@ module.skip = function skipModule(moduleName, _moduleContent) {
|
|
|
7724
7746
|
describe(moduleName, { ignore: true }, function() {
|
|
7725
7747
|
});
|
|
7726
7748
|
};
|
|
7749
|
+
module.todo = function todoModule(moduleName, _moduleContent) {
|
|
7750
|
+
describe(moduleName, { ignore: true }, function() {
|
|
7751
|
+
});
|
|
7752
|
+
};
|
|
7727
7753
|
|
|
7728
7754
|
// shims/deno/test.ts
|
|
7729
7755
|
function test2(testName, runtimeOptions, testContent) {
|
|
@@ -7742,21 +7768,33 @@ function test2(testName, runtimeOptions, testContent) {
|
|
|
7742
7768
|
const context = new TestContext(testName, moduleContext);
|
|
7743
7769
|
const userContext = Object.create(moduleContext.userContext);
|
|
7744
7770
|
context.userContext = userContext;
|
|
7745
|
-
it(testName, { ...targetRuntimeOptions },
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7771
|
+
it(testName, { ...targetRuntimeOptions }, function() {
|
|
7772
|
+
return new Promise((resolve, reject) => {
|
|
7773
|
+
context.rejectTimeout = reject;
|
|
7774
|
+
(async () => {
|
|
7775
|
+
const hookMeta = { context: userContext };
|
|
7776
|
+
try {
|
|
7777
|
+
for (const module2 of context.module.moduleChain) {
|
|
7778
|
+
for (const hook of module2.beforeEachHooks) {
|
|
7779
|
+
await hook.call(userContext, context.assert, hookMeta);
|
|
7780
|
+
}
|
|
7781
|
+
}
|
|
7782
|
+
const result = await targetTestContent.call(userContext, context.assert, { testName, options: runtimeOptions, context: userContext });
|
|
7783
|
+
await context.assert.waitForAsyncOps();
|
|
7784
|
+
for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
|
|
7785
|
+
const module2 = context.module.moduleChain[i];
|
|
7786
|
+
for (let j = module2.afterEachHooks.length - 1; j >= 0; j--) {
|
|
7787
|
+
await module2.afterEachHooks[j].call(userContext, context.assert, hookMeta);
|
|
7788
|
+
}
|
|
7789
|
+
}
|
|
7790
|
+
resolve(result);
|
|
7791
|
+
} catch (err) {
|
|
7792
|
+
reject(err);
|
|
7793
|
+
} finally {
|
|
7794
|
+
context.clearTimeoutHandle();
|
|
7795
|
+
}
|
|
7796
|
+
})();
|
|
7797
|
+
});
|
|
7760
7798
|
});
|
|
7761
7799
|
}
|
|
7762
7800
|
test2.skip = function skipTest(testName, _testContent) {
|
package/dist/deno/module.d.ts
CHANGED
|
@@ -32,13 +32,16 @@ export type { HookFn, HooksObject, PushResultInfo } from '../types.d.ts';
|
|
|
32
32
|
export default function module(moduleName: string, moduleContent: (hooks: HooksObject<Assert>, meta: {
|
|
33
33
|
moduleName: string;
|
|
34
34
|
options: unknown;
|
|
35
|
+
context: Record<string, unknown>;
|
|
35
36
|
}) => void): void;
|
|
36
37
|
/** Defines a test module (suite) with optional Deno BDD runtime options forwarded to `describe()`. */
|
|
37
38
|
declare function module(moduleName: string, runtimeOptions: object, moduleContent: (hooks: HooksObject<Assert>, meta: {
|
|
38
39
|
moduleName: string;
|
|
39
40
|
options: unknown;
|
|
41
|
+
context: Record<string, unknown>;
|
|
40
42
|
}) => void): void;
|
|
41
43
|
declare namespace module {
|
|
42
44
|
var skip: (moduleName: string, _moduleContent?: unknown) => void;
|
|
45
|
+
var todo: (moduleName: string, _moduleContent?: unknown) => void;
|
|
43
46
|
}
|
|
44
47
|
export default module;
|
package/dist/deno/module.js
CHANGED
|
@@ -17,7 +17,7 @@ function module(moduleName, runtimeOptions, moduleContent) {
|
|
|
17
17
|
const firstTest = moduleContext.tests[0];
|
|
18
18
|
const beforeAssert = firstTest ? firstTest.assert : moduleContext.assert;
|
|
19
19
|
for (const hook of beforeHooks) {
|
|
20
|
-
await hook.call(moduleContext.userContext, beforeAssert);
|
|
20
|
+
await hook.call(moduleContext.userContext, beforeAssert, { context: moduleContext.userContext });
|
|
21
21
|
}
|
|
22
22
|
});
|
|
23
23
|
afterAll(async () => {
|
|
@@ -27,7 +27,7 @@ function module(moduleName, runtimeOptions, moduleContent) {
|
|
|
27
27
|
const lastTest = moduleContext.tests[moduleContext.tests.length - 1];
|
|
28
28
|
if (lastTest) {
|
|
29
29
|
for (let j = afterHooks.length - 1; j >= 0; j--) {
|
|
30
|
-
await afterHooks[j].call(lastTest.userContext, lastTest.assert);
|
|
30
|
+
await afterHooks[j].call(lastTest.userContext, lastTest.assert, { context: lastTest.userContext });
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
for (let i = 0, len = moduleContext.tests.length; i < len; i++) {
|
|
@@ -47,7 +47,7 @@ function module(moduleName, runtimeOptions, moduleContent) {
|
|
|
47
47
|
after(afterFn) {
|
|
48
48
|
afterHooks.push(afterFn);
|
|
49
49
|
}
|
|
50
|
-
}, { moduleName, options: runtimeOptions });
|
|
50
|
+
}, { moduleName, options: runtimeOptions, context: moduleContext.userContext });
|
|
51
51
|
ModuleContext.currentModuleChain.pop();
|
|
52
52
|
});
|
|
53
53
|
}
|
|
@@ -55,6 +55,10 @@ module.skip = function skipModule(moduleName, _moduleContent) {
|
|
|
55
55
|
describe(moduleName, { ignore: true }, function() {
|
|
56
56
|
});
|
|
57
57
|
};
|
|
58
|
+
module.todo = function todoModule(moduleName, _moduleContent) {
|
|
59
|
+
describe(moduleName, { ignore: true }, function() {
|
|
60
|
+
});
|
|
61
|
+
};
|
|
58
62
|
export {
|
|
59
63
|
module as default
|
|
60
64
|
};
|
package/dist/deno/test.d.ts
CHANGED
|
@@ -35,11 +35,13 @@ export type { PushResultInfo } from '../types.d.ts';
|
|
|
35
35
|
export default function test(testName: string, testContent: (assert: Assert, meta: {
|
|
36
36
|
testName: string;
|
|
37
37
|
options: unknown;
|
|
38
|
+
context: Record<string, unknown>;
|
|
38
39
|
}) => void | Promise<void>): void;
|
|
39
40
|
/** Defines an individual test with optional Deno BDD runtime options forwarded to `it()`. */
|
|
40
41
|
declare function test(testName: string, runtimeOptions: object, testContent: (assert: Assert, meta: {
|
|
41
42
|
testName: string;
|
|
42
43
|
options: unknown;
|
|
44
|
+
context: Record<string, unknown>;
|
|
43
45
|
}) => void | Promise<void>): void;
|
|
44
46
|
declare namespace test {
|
|
45
47
|
var skip: (testName: string, _testContent?: unknown) => void;
|
package/dist/deno/test.js
CHANGED
|
@@ -17,21 +17,33 @@ function test(testName, runtimeOptions, testContent) {
|
|
|
17
17
|
const context = new TestContext(testName, moduleContext);
|
|
18
18
|
const userContext = Object.create(moduleContext.userContext);
|
|
19
19
|
context.userContext = userContext;
|
|
20
|
-
it(testName, { ...targetRuntimeOptions },
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
20
|
+
it(testName, { ...targetRuntimeOptions }, function() {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
context.rejectTimeout = reject;
|
|
23
|
+
(async () => {
|
|
24
|
+
const hookMeta = { context: userContext };
|
|
25
|
+
try {
|
|
26
|
+
for (const module of context.module.moduleChain) {
|
|
27
|
+
for (const hook of module.beforeEachHooks) {
|
|
28
|
+
await hook.call(userContext, context.assert, hookMeta);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const result = await targetTestContent.call(userContext, context.assert, { testName, options: runtimeOptions, context: userContext });
|
|
32
|
+
await context.assert.waitForAsyncOps();
|
|
33
|
+
for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
|
|
34
|
+
const module = context.module.moduleChain[i];
|
|
35
|
+
for (let j = module.afterEachHooks.length - 1; j >= 0; j--) {
|
|
36
|
+
await module.afterEachHooks[j].call(userContext, context.assert, hookMeta);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
resolve(result);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
reject(err);
|
|
42
|
+
} finally {
|
|
43
|
+
context.clearTimeoutHandle();
|
|
44
|
+
}
|
|
45
|
+
})();
|
|
46
|
+
});
|
|
35
47
|
});
|
|
36
48
|
}
|
|
37
49
|
test.skip = function skipTest(testName, _testContent) {
|
package/dist/node/module.d.ts
CHANGED
|
@@ -1,14 +1,51 @@
|
|
|
1
1
|
import type Assert from '../shared/assert.d.ts';
|
|
2
2
|
import type { HooksObject } from '../types.d.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Defines a test module (suite) for Node's built-in test runner.
|
|
5
|
+
*
|
|
6
|
+
* Wraps `describe()` from `node:test` and sets up the QUnit lifecycle
|
|
7
|
+
* (before/beforeEach/afterEach/after hooks, assertion counting, steps tracking).
|
|
8
|
+
*
|
|
9
|
+
* @param {string} moduleName - Name of the test suite.
|
|
10
|
+
* @param {object} [runtimeOptions] - Optional Node test runner options forwarded to `describe()`
|
|
11
|
+
* (e.g. `{ concurrency: true }`, `{ timeout: 5000 }`). Use `{ skip: true | string }` to skip
|
|
12
|
+
* the entire module.
|
|
13
|
+
* @param {function} moduleContent - Callback that defines tests and hooks via `hooks.before`,
|
|
14
|
+
* `hooks.beforeEach`, `hooks.afterEach`, `hooks.after`.
|
|
15
|
+
* Receives `(hooks, { moduleName, options, context })`.
|
|
16
|
+
* `context` is the shared module environment — the same object as `this` in
|
|
17
|
+
* regular-function callbacks, useful when using arrow functions.
|
|
18
|
+
* @returns {void}
|
|
19
|
+
* @example
|
|
20
|
+
* ```js
|
|
21
|
+
* import { module, test } from "qunitx";
|
|
22
|
+
*
|
|
23
|
+
* module("Math", (hooks, { context }) => {
|
|
24
|
+
* context.multiplier = 2;
|
|
25
|
+
*
|
|
26
|
+
* hooks.beforeEach((assert, { context }) => {
|
|
27
|
+
* context.value = 21;
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* test("multiplication", (assert, { context }) => {
|
|
31
|
+
* assert.equal(context.value * context.multiplier, 42);
|
|
32
|
+
* });
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
3
36
|
export default function module(moduleName: string, moduleContent: (hooks: HooksObject<Assert>, meta: {
|
|
4
37
|
moduleName: string;
|
|
5
38
|
options: unknown;
|
|
39
|
+
context: Record<string, unknown>;
|
|
6
40
|
}) => void): void;
|
|
41
|
+
/** Defines a test module (suite) with optional Node test runner options forwarded to `describe()`. */
|
|
7
42
|
declare function module(moduleName: string, runtimeOptions: object, moduleContent: (hooks: HooksObject<Assert>, meta: {
|
|
8
43
|
moduleName: string;
|
|
9
44
|
options: unknown;
|
|
45
|
+
context: Record<string, unknown>;
|
|
10
46
|
}) => void): void;
|
|
11
47
|
declare namespace module {
|
|
12
48
|
var skip: (moduleName: string, _moduleContent?: unknown) => void;
|
|
49
|
+
var todo: (moduleName: string, _moduleContent?: unknown) => void;
|
|
13
50
|
}
|
|
14
51
|
export default module;
|
package/dist/node/module.js
CHANGED
|
@@ -17,7 +17,7 @@ function module(moduleName, runtimeOptions, moduleContent) {
|
|
|
17
17
|
const firstTest = moduleContext.tests[0];
|
|
18
18
|
const beforeAssert = firstTest ? firstTest.assert : moduleContext.assert;
|
|
19
19
|
for (const hook of beforeHooks) {
|
|
20
|
-
await hook.call(moduleContext.userContext, beforeAssert);
|
|
20
|
+
await hook.call(moduleContext.userContext, beforeAssert, { context: moduleContext.userContext });
|
|
21
21
|
}
|
|
22
22
|
});
|
|
23
23
|
afterAll(async () => {
|
|
@@ -27,7 +27,7 @@ function module(moduleName, runtimeOptions, moduleContent) {
|
|
|
27
27
|
const lastTest = moduleContext.tests[moduleContext.tests.length - 1];
|
|
28
28
|
if (lastTest) {
|
|
29
29
|
for (let j = afterHooks.length - 1; j >= 0; j--) {
|
|
30
|
-
await afterHooks[j].call(lastTest.userContext, lastTest.assert);
|
|
30
|
+
await afterHooks[j].call(lastTest.userContext, lastTest.assert, { context: lastTest.userContext });
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
for (let i = 0, len = moduleContext.tests.length; i < len; i++) {
|
|
@@ -47,7 +47,7 @@ function module(moduleName, runtimeOptions, moduleContent) {
|
|
|
47
47
|
after(afterFn) {
|
|
48
48
|
afterHooks.push(afterFn);
|
|
49
49
|
}
|
|
50
|
-
}, { moduleName, options: runtimeOptions });
|
|
50
|
+
}, { moduleName, options: runtimeOptions, context: moduleContext.userContext });
|
|
51
51
|
ModuleContext.currentModuleChain.pop();
|
|
52
52
|
});
|
|
53
53
|
}
|
|
@@ -55,6 +55,10 @@ module.skip = function skipModule(moduleName, _moduleContent) {
|
|
|
55
55
|
describe(moduleName, { skip: true }, function() {
|
|
56
56
|
});
|
|
57
57
|
};
|
|
58
|
+
module.todo = function todoModule(moduleName, _moduleContent) {
|
|
59
|
+
describe(moduleName, { skip: true }, function() {
|
|
60
|
+
});
|
|
61
|
+
};
|
|
58
62
|
export {
|
|
59
63
|
module as default
|
|
60
64
|
};
|
package/dist/node/test.d.ts
CHANGED
|
@@ -1,11 +1,46 @@
|
|
|
1
1
|
import type Assert from '../shared/assert.d.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Defines an individual test within a module for Node's built-in test runner.
|
|
4
|
+
*
|
|
5
|
+
* Wraps `it()` from `node:test` and handles the full QUnit lifecycle:
|
|
6
|
+
* beforeEach/afterEach hooks, async assertion waiting, and step verification.
|
|
7
|
+
*
|
|
8
|
+
* Must be called inside a `module()` callback.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} testName - Name of the test.
|
|
11
|
+
* @param {object} [runtimeOptions] - Optional Node test runner options forwarded to `it()`.
|
|
12
|
+
* Use `{ skip: true | string }` to skip the test, `{ todo: true | string }` to mark it as todo.
|
|
13
|
+
* Other Node options like `{ concurrency: true }` or `{ timeout: 5000 }` are forwarded as-is.
|
|
14
|
+
* @param {function} testContent - Test callback receiving `(assert, { testName, options, context })`.
|
|
15
|
+
* `context` is the per-test environment — inherits properties set by `before`/`beforeEach` hooks,
|
|
16
|
+
* and is the same object as `this` in regular-function callbacks. Useful when using arrow functions.
|
|
17
|
+
* @returns {void}
|
|
18
|
+
* @example
|
|
19
|
+
* ```js
|
|
20
|
+
* import { module, test } from "qunitx";
|
|
21
|
+
*
|
|
22
|
+
* module("Math", () => {
|
|
23
|
+
* test("addition", (assert) => {
|
|
24
|
+
* assert.equal(1 + 1, 2);
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* test("async resolves correctly", async (assert) => {
|
|
28
|
+
* const result = await Promise.resolve(42);
|
|
29
|
+
* assert.strictEqual(result, 42);
|
|
30
|
+
* });
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
2
34
|
export default function test(testName: string, testContent: (assert: Assert, meta: {
|
|
3
35
|
testName: string;
|
|
4
36
|
options: unknown;
|
|
37
|
+
context: Record<string, unknown>;
|
|
5
38
|
}) => void | Promise<void>): void;
|
|
39
|
+
/** Defines an individual test with optional Node test runner options forwarded to `it()`. */
|
|
6
40
|
declare function test(testName: string, runtimeOptions: object, testContent: (assert: Assert, meta: {
|
|
7
41
|
testName: string;
|
|
8
42
|
options: unknown;
|
|
43
|
+
context: Record<string, unknown>;
|
|
9
44
|
}) => void | Promise<void>): void;
|
|
10
45
|
declare namespace test {
|
|
11
46
|
var skip: (testName: string, _testContent?: unknown) => void;
|
package/dist/node/test.js
CHANGED
|
@@ -18,21 +18,33 @@ function test(testName, runtimeOptions, testContent) {
|
|
|
18
18
|
const userContext = Object.create(moduleContext.userContext);
|
|
19
19
|
context.userContext = userContext;
|
|
20
20
|
if (todo) moduleContext.tests.pop();
|
|
21
|
-
it(testName, { ...targetRuntimeOptions },
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
21
|
+
it(testName, { ...targetRuntimeOptions }, function() {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
context.rejectTimeout = reject;
|
|
24
|
+
(async () => {
|
|
25
|
+
const hookMeta = { context: userContext };
|
|
26
|
+
try {
|
|
27
|
+
for (const module of context.module.moduleChain) {
|
|
28
|
+
for (const hook of module.beforeEachHooks) {
|
|
29
|
+
await hook.call(userContext, context.assert, hookMeta);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const result = await targetTestContent.call(userContext, context.assert, { testName, options: runtimeOptions, context: userContext });
|
|
33
|
+
await context.assert.waitForAsyncOps();
|
|
34
|
+
for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
|
|
35
|
+
const module = context.module.moduleChain[i];
|
|
36
|
+
for (let j = module.afterEachHooks.length - 1; j >= 0; j--) {
|
|
37
|
+
await module.afterEachHooks[j].call(userContext, context.assert, hookMeta);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
resolve(result);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
reject(err);
|
|
43
|
+
} finally {
|
|
44
|
+
context.clearTimeoutHandle();
|
|
45
|
+
}
|
|
46
|
+
})();
|
|
47
|
+
});
|
|
36
48
|
});
|
|
37
49
|
}
|
|
38
50
|
test.skip = function skipTest(testName, _testContent) {
|
package/dist/shared/assert.js
CHANGED
|
@@ -35,6 +35,7 @@ class Assert {
|
|
|
35
35
|
throw new Error("assert.timeout() expects a positive integer.");
|
|
36
36
|
}
|
|
37
37
|
this.test.timeout = number;
|
|
38
|
+
this.test.setTimeoutDuration(number);
|
|
38
39
|
}
|
|
39
40
|
/**
|
|
40
41
|
* Records a named step. Use with {@linkcode Assert.prototype.verifySteps} to assert that
|
|
@@ -7,7 +7,7 @@ export default class ModuleContext {
|
|
|
7
7
|
static get lastModule(): ModuleContext;
|
|
8
8
|
name: string;
|
|
9
9
|
assert: Assert;
|
|
10
|
-
userContext:
|
|
10
|
+
userContext: Record<string, unknown>;
|
|
11
11
|
context: TestContext;
|
|
12
12
|
moduleChain: ModuleContext[];
|
|
13
13
|
beforeEachHooks: HookFn<Assert>[];
|
|
@@ -13,13 +13,16 @@ export default class TestContext {
|
|
|
13
13
|
set assert(value: Assert | undefined);
|
|
14
14
|
get timeout(): number | undefined;
|
|
15
15
|
set timeout(value: number | undefined);
|
|
16
|
+
rejectTimeout: ((err: Error) => void) | undefined;
|
|
17
|
+
setTimeoutDuration(ms: number): void;
|
|
18
|
+
clearTimeoutHandle(): void;
|
|
16
19
|
get steps(): string[];
|
|
17
20
|
set steps(value: string[]);
|
|
18
21
|
get expectedAssertionCount(): number | undefined;
|
|
19
22
|
set expectedAssertionCount(value: number | undefined);
|
|
20
23
|
get totalExecutedAssertions(): number;
|
|
21
24
|
set totalExecutedAssertions(value: number);
|
|
22
|
-
userContext:
|
|
25
|
+
userContext: Record<string, unknown>;
|
|
23
26
|
constructor(name?: string, moduleContext?: ModuleContext);
|
|
24
27
|
finish(): void;
|
|
25
28
|
}
|
|
@@ -35,6 +35,26 @@ class TestContext {
|
|
|
35
35
|
set timeout(value) {
|
|
36
36
|
this.#timeout = value;
|
|
37
37
|
}
|
|
38
|
+
rejectTimeout;
|
|
39
|
+
#timeoutHandle;
|
|
40
|
+
#timedOut = false;
|
|
41
|
+
setTimeoutDuration(ms) {
|
|
42
|
+
if (this.#timeoutHandle !== void 0) {
|
|
43
|
+
clearTimeout(this.#timeoutHandle);
|
|
44
|
+
this.#timeoutHandle = void 0;
|
|
45
|
+
}
|
|
46
|
+
if (!this.rejectTimeout) return;
|
|
47
|
+
this.#timeoutHandle = setTimeout(() => {
|
|
48
|
+
this.#timedOut = true;
|
|
49
|
+
this.rejectTimeout(new Error(`Test timed out after ${ms}ms`));
|
|
50
|
+
}, ms);
|
|
51
|
+
}
|
|
52
|
+
clearTimeoutHandle() {
|
|
53
|
+
if (this.#timeoutHandle !== void 0) {
|
|
54
|
+
clearTimeout(this.#timeoutHandle);
|
|
55
|
+
this.#timeoutHandle = void 0;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
38
58
|
#steps = [];
|
|
39
59
|
get steps() {
|
|
40
60
|
return this.#steps;
|
|
@@ -66,6 +86,7 @@ class TestContext {
|
|
|
66
86
|
}
|
|
67
87
|
}
|
|
68
88
|
finish() {
|
|
89
|
+
if (this.#timedOut) return;
|
|
69
90
|
if (this.totalExecutedAssertions === 0) {
|
|
70
91
|
this.assert.pushResult({
|
|
71
92
|
result: false,
|
package/dist/types.d.ts
CHANGED
|
@@ -36,20 +36,24 @@ export interface TestState {
|
|
|
36
36
|
asyncOps: Promise<void>[];
|
|
37
37
|
timeout?: number;
|
|
38
38
|
expectedAssertionCount?: number;
|
|
39
|
-
userContext?:
|
|
39
|
+
userContext?: Record<string, unknown>;
|
|
40
40
|
module?: {
|
|
41
41
|
name: string;
|
|
42
42
|
};
|
|
43
|
+
setTimeoutDuration(ms: number): void;
|
|
43
44
|
}
|
|
44
45
|
/** Minimal module shape that Assert needs to resolve a fallback test context. */
|
|
45
46
|
export interface ModuleState {
|
|
46
47
|
context: TestState;
|
|
47
48
|
}
|
|
48
|
-
/** A lifecycle hook callback that receives an {@linkcode Assert} instance. */
|
|
49
|
-
export type HookFn<A = unknown> = (assert: A
|
|
49
|
+
/** A lifecycle hook callback that receives an {@linkcode Assert} instance and a meta object with the shared context. */
|
|
50
|
+
export type HookFn<A = unknown> = (assert: A, meta: {
|
|
51
|
+
context: Record<string, unknown>;
|
|
52
|
+
}) => void | Promise<void>;
|
|
50
53
|
export type TestFn<A = unknown> = (assert: A, meta: {
|
|
51
54
|
testName: string;
|
|
52
55
|
options: unknown;
|
|
56
|
+
context: Record<string, unknown>;
|
|
53
57
|
}) => void | Promise<unknown>;
|
|
54
58
|
/** Lifecycle hooks available inside a `module()` callback. */
|
|
55
59
|
export interface HooksObject<A = unknown> {
|
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.6",
|
|
5
5
|
"description": "A universal test framework for testing any js file on node.js, browser or deno with QUnit API",
|
|
6
6
|
"author": "Izel Nakri",
|
|
7
7
|
"license": "MIT",
|
|
@@ -83,11 +83,11 @@
|
|
|
83
83
|
"format:fix": "prettier --write \"test/**/*.ts\" \"*.ts\" \"package.json\"",
|
|
84
84
|
"lint": "deno lint shims/",
|
|
85
85
|
"lint:docs": "deno doc --lint shims/deno/module.ts shims/deno/test.ts",
|
|
86
|
-
"build": "node
|
|
87
|
-
"build:cold": "rm -rf dist && node
|
|
88
|
-
"pretest": "node
|
|
86
|
+
"build": "node build.ts",
|
|
87
|
+
"build:cold": "rm -rf dist && node build.ts",
|
|
88
|
+
"pretest": "node build.ts && node --input-type=module -e \"import{symlinkSync}from'fs';try{symlinkSync('..','node_modules/qunitx','junction')}catch(_){}\"",
|
|
89
89
|
"run:all": "npm run run:node && npm run run:deno",
|
|
90
|
-
"run:node": "node --
|
|
90
|
+
"run:node": "node --test test/helpers/passing-tests.ts && node --test test/helpers/failing-tests.ts",
|
|
91
91
|
"run:deno": "deno test test/helpers/passing-tests.ts && deno test test/helpers/failing-tests.ts",
|
|
92
92
|
"changelog:unreleased": "git-cliff --unreleased --strip all",
|
|
93
93
|
"changelog:preview": "git-cliff",
|
|
@@ -99,8 +99,8 @@
|
|
|
99
99
|
"test:browser": "qunitx test/index.ts --debug",
|
|
100
100
|
"test:deno": "deno test --allow-read --allow-run test/index.ts",
|
|
101
101
|
"test:doctests": "deno test --doc --allow-read shims/deno/module.ts shims/deno/test.ts",
|
|
102
|
-
"test:node": "node --
|
|
103
|
-
"coverage": "deno test --coverage=tmp/coverage --allow-read --allow-env --allow-run test/index.ts && deno coverage --lcov --output=tmp/coverage/lcov.info --include='shims/' tmp/coverage && node
|
|
102
|
+
"test:node": "node --test test/index.ts",
|
|
103
|
+
"coverage": "deno test --coverage=tmp/coverage --allow-read --allow-env --allow-run test/index.ts && deno coverage --lcov --output=tmp/coverage/lcov.info --include='shims/' tmp/coverage && node scripts/check-coverage.ts",
|
|
104
104
|
"coverage:report": "npm run coverage && deno coverage --html --include='shims/' tmp/coverage",
|
|
105
105
|
"bench": "deno task bench",
|
|
106
106
|
"bench:check": "deno task bench:check",
|
|
@@ -109,6 +109,7 @@
|
|
|
109
109
|
},
|
|
110
110
|
"devDependencies": {
|
|
111
111
|
"@types/node": "^22.0.0",
|
|
112
|
+
"playwright-core": "^1.59.1",
|
|
112
113
|
"prettier": "^3.8.1",
|
|
113
114
|
"qunit": "^2.25.0",
|
|
114
115
|
"qunitx-cli": "^0.9.10",
|