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.
@@ -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 clearTimeout = g.clearTimeout;
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
- clearTimeout(config.timeout);
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
- clearTimeout(this.timeout);
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
- clearTimeout(config.timeout);
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
- clearTimeout(config.timeout);
2665
+ clearTimeout2(config.timeout);
2666
2666
  config.timeout = setTimeout$1(config.timeoutHandler(timeoutDuration), timeoutDuration);
2667
2667
  } else {
2668
- clearTimeout(config.timeout);
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
- clearTimeout(config.timeout);
2963
+ clearTimeout2(config.timeout);
2964
2964
  config.timeout = setTimeout$1(function() {
2965
2965
  if (test4.pauses.size > 0) {
2966
2966
  return;
2967
2967
  }
2968
- clearTimeout(config.timeout);
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 }, async function() {
7746
- for (const module2 of context.module.moduleChain) {
7747
- for (const hook of module2.beforeEachHooks) {
7748
- await hook.call(userContext, context.assert);
7749
- }
7750
- }
7751
- const result = await targetTestContent.call(userContext, context.assert, { testName, options: runtimeOptions });
7752
- await context.assert.waitForAsyncOps();
7753
- for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
7754
- const module2 = context.module.moduleChain[i];
7755
- for (let j = module2.afterEachHooks.length - 1; j >= 0; j--) {
7756
- await module2.afterEachHooks[j].call(userContext, context.assert);
7757
- }
7758
- }
7759
- return result;
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) {
@@ -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;
@@ -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
  };
@@ -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 }, async function() {
21
- for (const module of context.module.moduleChain) {
22
- for (const hook of module.beforeEachHooks) {
23
- await hook.call(userContext, context.assert);
24
- }
25
- }
26
- const result = await targetTestContent.call(userContext, context.assert, { testName, options: runtimeOptions });
27
- await context.assert.waitForAsyncOps();
28
- for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
29
- const module = context.module.moduleChain[i];
30
- for (let j = module.afterEachHooks.length - 1; j >= 0; j--) {
31
- await module.afterEachHooks[j].call(userContext, context.assert);
32
- }
33
- }
34
- return result;
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) {
@@ -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;
@@ -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
  };
@@ -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 }, async function() {
22
- for (const module of context.module.moduleChain) {
23
- for (const hook of module.beforeEachHooks) {
24
- await hook.call(userContext, context.assert);
25
- }
26
- }
27
- const result = await targetTestContent.call(userContext, context.assert, { testName, options: runtimeOptions });
28
- await context.assert.waitForAsyncOps();
29
- for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
30
- const module = context.module.moduleChain[i];
31
- for (let j = module.afterEachHooks.length - 1; j >= 0; j--) {
32
- await module.afterEachHooks[j].call(userContext, context.assert);
33
- }
34
- }
35
- return result;
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) {
@@ -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: object;
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: object;
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?: object;
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) => void | Promise<void>;
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",
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 --experimental-strip-types build.ts",
87
- "build:cold": "rm -rf dist && node --experimental-strip-types build.ts",
88
- "pretest": "node --experimental-strip-types build.ts && node --input-type=module -e \"import{symlinkSync}from'fs';try{symlinkSync('..','node_modules/qunitx','junction')}catch(_){}\"",
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 --experimental-strip-types --test test/helpers/passing-tests.ts && node --experimental-strip-types --test test/helpers/failing-tests.ts",
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 --experimental-strip-types --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 --experimental-strip-types scripts/check-coverage.ts",
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",