qunitx 1.2.2 → 1.2.5

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.
@@ -1049,13 +1049,13 @@ var require_qunit = __commonJS({
1049
1049
  }, {
1050
1050
  key: "getStatus",
1051
1051
  value: function getStatus() {
1052
- var _this$getTestCounts = this.getTestCounts(), total = _this$getTestCounts.total, failed = _this$getTestCounts.failed, skipped = _this$getTestCounts.skipped, todo = _this$getTestCounts.todo;
1052
+ var _this$getTestCounts = this.getTestCounts(), total = _this$getTestCounts.total, failed = _this$getTestCounts.failed, skipped = _this$getTestCounts.skipped, todo2 = _this$getTestCounts.todo;
1053
1053
  if (failed) {
1054
1054
  return "failed";
1055
1055
  } else {
1056
1056
  if (skipped === total) {
1057
1057
  return "skipped";
1058
- } else if (todo === total) {
1058
+ } else if (todo2 === total) {
1059
1059
  return "todo";
1060
1060
  } else {
1061
1061
  return "passed";
@@ -1081,7 +1081,7 @@ var require_qunit = __commonJS({
1081
1081
  var moduleName = parentModule !== null ? [parentModule.name, name].join(" > ") : name;
1082
1082
  var parentSuite = parentModule ? parentModule.suiteReport : runSuite;
1083
1083
  var skip2 = parentModule !== null && parentModule.skip || modifiers.skip;
1084
- var todo = parentModule !== null && parentModule.todo || modifiers.todo;
1084
+ var todo2 = parentModule !== null && parentModule.todo || modifiers.todo;
1085
1085
  var env = {};
1086
1086
  if (parentModule) {
1087
1087
  extend(env, parentModule.testEnvironment);
@@ -1111,7 +1111,7 @@ var require_qunit = __commonJS({
1111
1111
  // This property will be used to mark own tests and tests of child suites
1112
1112
  // as either `skipped` or `todo`.
1113
1113
  skip: skip2,
1114
- todo: skip2 ? false : todo,
1114
+ todo: skip2 ? false : todo2,
1115
1115
  ignored: modifiers.ignored || false
1116
1116
  };
1117
1117
  if (parentModule) {
@@ -2373,7 +2373,7 @@ var require_qunit = __commonJS({
2373
2373
  var moduleName = module3.name;
2374
2374
  var testName = this.testName;
2375
2375
  var skipped = !!this.skip;
2376
- var todo = !!this.todo;
2376
+ var todo2 = !!this.todo;
2377
2377
  var bad = 0;
2378
2378
  var storage = config.storage;
2379
2379
  this.runtime = Math.round(performance.now() - this.started);
@@ -2406,7 +2406,7 @@ var require_qunit = __commonJS({
2406
2406
  name: testName,
2407
2407
  module: moduleName,
2408
2408
  skipped,
2409
- todo,
2409
+ todo: todo2,
2410
2410
  failed: bad,
2411
2411
  passed: this.assertions.length - bad,
2412
2412
  total: this.assertions.length,
@@ -2866,7 +2866,7 @@ var require_qunit = __commonJS({
2866
2866
  }
2867
2867
  }
2868
2868
  extend(test3, {
2869
- todo: function todo(testName, callback) {
2869
+ todo: function todo2(testName, callback) {
2870
2870
  addTest({
2871
2871
  testName,
2872
2872
  callback,
@@ -7686,7 +7686,7 @@ function module(moduleName, runtimeOptions, moduleContent) {
7686
7686
  const firstTest = moduleContext.tests[0];
7687
7687
  const beforeAssert = firstTest ? firstTest.assert : moduleContext.assert;
7688
7688
  for (const hook of beforeHooks) {
7689
- await hook.call(moduleContext.userContext, beforeAssert);
7689
+ await hook.call(moduleContext.userContext, beforeAssert, { context: moduleContext.userContext });
7690
7690
  }
7691
7691
  });
7692
7692
  afterAll(async () => {
@@ -7696,7 +7696,7 @@ function module(moduleName, runtimeOptions, moduleContent) {
7696
7696
  const lastTest = moduleContext.tests[moduleContext.tests.length - 1];
7697
7697
  if (lastTest) {
7698
7698
  for (let j = afterHooks.length - 1; j >= 0; j--) {
7699
- await afterHooks[j].call(lastTest.userContext, lastTest.assert);
7699
+ await afterHooks[j].call(lastTest.userContext, lastTest.assert, { context: lastTest.userContext });
7700
7700
  }
7701
7701
  }
7702
7702
  for (let i = 0, len = moduleContext.tests.length; i < len; i++) {
@@ -7716,7 +7716,7 @@ function module(moduleName, runtimeOptions, moduleContent) {
7716
7716
  after(afterFn) {
7717
7717
  afterHooks.push(afterFn);
7718
7718
  }
7719
- }, { moduleName, options: runtimeOptions });
7719
+ }, { moduleName, options: runtimeOptions, context: moduleContext.userContext });
7720
7720
  ModuleContext.currentModuleChain.pop();
7721
7721
  });
7722
7722
  }
@@ -7732,8 +7732,8 @@ function test2(testName, runtimeOptions, testContent) {
7732
7732
  throw new Error(`Test '${testName}' called outside of module context.`);
7733
7733
  }
7734
7734
  const targetRuntimeOptions = testContent ? runtimeOptions : {};
7735
- const { skip: skip2 } = targetRuntimeOptions;
7736
- if (skip2) {
7735
+ const { skip: skip2, todo: todo2 } = targetRuntimeOptions;
7736
+ if (skip2 || todo2) {
7737
7737
  it(testName, { ignore: true }, async function() {
7738
7738
  });
7739
7739
  return;
@@ -7743,17 +7743,18 @@ function test2(testName, runtimeOptions, testContent) {
7743
7743
  const userContext = Object.create(moduleContext.userContext);
7744
7744
  context.userContext = userContext;
7745
7745
  it(testName, { ...targetRuntimeOptions }, async function() {
7746
+ const hookMeta = { context: userContext };
7746
7747
  for (const module2 of context.module.moduleChain) {
7747
7748
  for (const hook of module2.beforeEachHooks) {
7748
- await hook.call(userContext, context.assert);
7749
+ await hook.call(userContext, context.assert, hookMeta);
7749
7750
  }
7750
7751
  }
7751
- const result = await targetTestContent.call(userContext, context.assert, { testName, options: runtimeOptions });
7752
+ const result = await targetTestContent.call(userContext, context.assert, { testName, options: runtimeOptions, context: userContext });
7752
7753
  await context.assert.waitForAsyncOps();
7753
7754
  for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
7754
7755
  const module2 = context.module.moduleChain[i];
7755
7756
  for (let j = module2.afterEachHooks.length - 1; j >= 0; j--) {
7756
- await module2.afterEachHooks[j].call(userContext, context.assert);
7757
+ await module2.afterEachHooks[j].call(userContext, context.assert, hookMeta);
7757
7758
  }
7758
7759
  }
7759
7760
  return result;
@@ -7763,6 +7764,10 @@ test2.skip = function skipTest(testName, _testContent) {
7763
7764
  it(testName, { ignore: true }, async function() {
7764
7765
  });
7765
7766
  };
7767
+ test2.todo = function todoTest(testName, _testContent) {
7768
+ it(testName, { ignore: true }, async function() {
7769
+ });
7770
+ };
7766
7771
 
7767
7772
  // shims/deno/index.ts
7768
7773
  var AssertionError2 = class extends AssertionError {
@@ -7779,6 +7784,7 @@ Object.freeze(Assert);
7779
7784
  Object.freeze(ModuleContext);
7780
7785
  Object.freeze(TestContext);
7781
7786
  var skip = test2.skip;
7787
+ var todo = test2.todo;
7782
7788
  var index_default = { AssertionError: Assert.AssertionError, module, test: test2, config: {} };
7783
7789
  export {
7784
7790
  Assert,
@@ -7786,7 +7792,8 @@ export {
7786
7792
  index_default as default,
7787
7793
  module,
7788
7794
  skip,
7789
- test2 as test
7795
+ test2 as test,
7796
+ todo
7790
7797
  };
7791
7798
  /*!
7792
7799
  * QUnit 2.25.0
@@ -32,11 +32,13 @@ 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;
@@ -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
  }
@@ -10,8 +10,10 @@ export type { PushResultInfo } from '../types.d.ts';
10
10
  * Must be called inside a `module()` callback.
11
11
  *
12
12
  * @param {string} testName - Name of the test
13
- * @param {object} [runtimeOptions] - Optional Deno BDD options forwarded to `it()`
14
- * (e.g. `{ concurrency: false }`, `{ sanitizeExit: false }`)
13
+ * @param {object} [runtimeOptions] - Optional options forwarded to `it()`.
14
+ * Use `{ skip: true | string }` to skip the test, `{ todo: true | string }` to mark it as todo
15
+ * (both map to Deno's `{ ignore: true }`). Other Deno BDD options like
16
+ * `{ concurrency: false }` or `{ sanitizeExit: false }` are forwarded as-is.
15
17
  * @param {function} testContent - Test callback receiving `(assert, { testName, options })`
16
18
  * @returns {void}
17
19
  * @example
@@ -33,13 +35,16 @@ export type { PushResultInfo } from '../types.d.ts';
33
35
  export default function test(testName: string, testContent: (assert: Assert, meta: {
34
36
  testName: string;
35
37
  options: unknown;
38
+ context: Record<string, unknown>;
36
39
  }) => void | Promise<void>): void;
37
40
  /** Defines an individual test with optional Deno BDD runtime options forwarded to `it()`. */
38
41
  declare function test(testName: string, runtimeOptions: object, testContent: (assert: Assert, meta: {
39
42
  testName: string;
40
43
  options: unknown;
44
+ context: Record<string, unknown>;
41
45
  }) => void | Promise<void>): void;
42
46
  declare namespace test {
43
47
  var skip: (testName: string, _testContent?: unknown) => void;
48
+ var todo: (testName: string, _testContent?: unknown) => void;
44
49
  }
45
50
  export default test;
package/dist/deno/test.js CHANGED
@@ -7,8 +7,8 @@ function test(testName, runtimeOptions, testContent) {
7
7
  throw new Error(`Test '${testName}' called outside of module context.`);
8
8
  }
9
9
  const targetRuntimeOptions = testContent ? runtimeOptions : {};
10
- const { skip } = targetRuntimeOptions;
11
- if (skip) {
10
+ const { skip, todo } = targetRuntimeOptions;
11
+ if (skip || todo) {
12
12
  it(testName, { ignore: true }, async function() {
13
13
  });
14
14
  return;
@@ -18,17 +18,18 @@ function test(testName, runtimeOptions, testContent) {
18
18
  const userContext = Object.create(moduleContext.userContext);
19
19
  context.userContext = userContext;
20
20
  it(testName, { ...targetRuntimeOptions }, async function() {
21
+ const hookMeta = { context: userContext };
21
22
  for (const module of context.module.moduleChain) {
22
23
  for (const hook of module.beforeEachHooks) {
23
- await hook.call(userContext, context.assert);
24
+ await hook.call(userContext, context.assert, hookMeta);
24
25
  }
25
26
  }
26
- const result = await targetTestContent.call(userContext, context.assert, { testName, options: runtimeOptions });
27
+ const result = await targetTestContent.call(userContext, context.assert, { testName, options: runtimeOptions, context: userContext });
27
28
  await context.assert.waitForAsyncOps();
28
29
  for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
29
30
  const module = context.module.moduleChain[i];
30
31
  for (let j = module.afterEachHooks.length - 1; j >= 0; j--) {
31
- await module.afterEachHooks[j].call(userContext, context.assert);
32
+ await module.afterEachHooks[j].call(userContext, context.assert, hookMeta);
32
33
  }
33
34
  }
34
35
  return result;
@@ -38,6 +39,10 @@ test.skip = function skipTest(testName, _testContent) {
38
39
  it(testName, { ignore: true }, async function() {
39
40
  });
40
41
  };
42
+ test.todo = function todoTest(testName, _testContent) {
43
+ it(testName, { ignore: true }, async function() {
44
+ });
45
+ };
41
46
  export {
42
47
  test as default
43
48
  };
@@ -5,6 +5,10 @@ export { default as module } from './module.d.ts';
5
5
  export { default as test } from './test.d.ts';
6
6
  export { Assert };
7
7
  export declare const skip: (testName: string, _testContent?: unknown) => void;
8
+ export declare const todo: (testName: string, testContent?: (assert: Assert, meta: {
9
+ testName: string;
10
+ options: unknown;
11
+ }) => void | Promise<void>) => void;
8
12
  declare const _default: {
9
13
  AssertionError: import("../types.d.ts").AssertionErrorConstructor;
10
14
  module: typeof Module;
@@ -17,11 +17,13 @@ Object.freeze(TestContext);
17
17
  import { default as default2 } from "./module.js";
18
18
  import { default as default3 } from "./test.js";
19
19
  const skip = Test.skip;
20
+ const todo = Test.todo;
20
21
  var node_default = { AssertionError: Assert.AssertionError, module: Module, test: Test, config: {} };
21
22
  export {
22
23
  Assert,
23
24
  node_default as default,
24
25
  default2 as module,
25
26
  skip,
26
- default3 as test
27
+ default3 as test,
28
+ todo
27
29
  };
@@ -1,12 +1,48 @@
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;
@@ -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
  }
@@ -1,13 +1,52 @@
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;
47
+ var todo: (testName: string, testContent?: (assert: Assert, meta: {
48
+ testName: string;
49
+ options: unknown;
50
+ }) => void | Promise<void>) => void;
12
51
  }
13
52
  export default test;
package/dist/node/test.js CHANGED
@@ -7,28 +7,30 @@ function test(testName, runtimeOptions, testContent) {
7
7
  throw new Error(`Test '${testName}' called outside of module context.`);
8
8
  }
9
9
  const targetRuntimeOptions = testContent ? runtimeOptions : {};
10
- const { skip } = targetRuntimeOptions;
10
+ const { skip, todo } = targetRuntimeOptions;
11
11
  if (skip) {
12
12
  it(testName, { skip }, async function() {
13
13
  });
14
14
  return;
15
15
  }
16
- const targetTestContent = testContent ? testContent : runtimeOptions;
16
+ const targetTestContent = testContent ?? runtimeOptions;
17
17
  const context = new TestContext(testName, moduleContext);
18
18
  const userContext = Object.create(moduleContext.userContext);
19
19
  context.userContext = userContext;
20
+ if (todo) moduleContext.tests.pop();
20
21
  it(testName, { ...targetRuntimeOptions }, async function() {
22
+ const hookMeta = { context: userContext };
21
23
  for (const module of context.module.moduleChain) {
22
24
  for (const hook of module.beforeEachHooks) {
23
- await hook.call(userContext, context.assert);
25
+ await hook.call(userContext, context.assert, hookMeta);
24
26
  }
25
27
  }
26
- const result = await targetTestContent.call(userContext, context.assert, { testName, options: runtimeOptions });
28
+ const result = await targetTestContent.call(userContext, context.assert, { testName, options: runtimeOptions, context: userContext });
27
29
  await context.assert.waitForAsyncOps();
28
30
  for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
29
31
  const module = context.module.moduleChain[i];
30
32
  for (let j = module.afterEachHooks.length - 1; j >= 0; j--) {
31
- await module.afterEachHooks[j].call(userContext, context.assert);
33
+ await module.afterEachHooks[j].call(userContext, context.assert, hookMeta);
32
34
  }
33
35
  }
34
36
  return result;
@@ -38,6 +40,14 @@ test.skip = function skipTest(testName, _testContent) {
38
40
  it(testName, { skip: true }, async function() {
39
41
  });
40
42
  };
43
+ test.todo = function todoTest(testName, testContent) {
44
+ if (!testContent) {
45
+ it(testName, { todo: true }, async function() {
46
+ });
47
+ return;
48
+ }
49
+ test(testName, { todo: true }, testContent);
50
+ };
41
51
  export {
42
52
  test as default
43
53
  };
@@ -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>[];
@@ -19,7 +19,7 @@ export default class TestContext {
19
19
  set expectedAssertionCount(value: number | undefined);
20
20
  get totalExecutedAssertions(): number;
21
21
  set totalExecutedAssertions(value: number);
22
- userContext: object;
22
+ userContext: Record<string, unknown>;
23
23
  constructor(name?: string, moduleContext?: ModuleContext);
24
24
  finish(): void;
25
25
  }
package/dist/types.d.ts CHANGED
@@ -36,7 +36,7 @@ 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
  };
@@ -45,11 +45,14 @@ export interface TestState {
45
45
  export interface ModuleState {
46
46
  context: TestState;
47
47
  }
48
- /** A lifecycle hook callback that receives an {@linkcode Assert} instance. */
49
- export type HookFn<A = unknown> = (assert: A) => void | Promise<void>;
48
+ /** A lifecycle hook callback that receives an {@linkcode Assert} instance and a meta object with the shared context. */
49
+ export type HookFn<A = unknown> = (assert: A, meta: {
50
+ context: Record<string, unknown>;
51
+ }) => void | Promise<void>;
50
52
  export type TestFn<A = unknown> = (assert: A, meta: {
51
53
  testName: string;
52
54
  options: unknown;
55
+ context: Record<string, unknown>;
53
56
  }) => void | Promise<unknown>;
54
57
  /** Lifecycle hooks available inside a `module()` callback. */
55
58
  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.2",
4
+ "version": "1.2.5",
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",
@@ -120,8 +120,10 @@ export { default as module } from './module.ts';
120
120
  * is an {@linkcode Assert} instance.
121
121
  *
122
122
  * @param {string} testName - Name of the test.
123
- * @param {object} [runtimeOptions] - Optional Deno BDD options forwarded to `it()`
124
- * (e.g. `{ concurrency: false }`, `{ sanitizeExit: false }`).
123
+ * @param {object} [runtimeOptions] - Optional options forwarded to `it()`.
124
+ * Use `{ skip: true | string }` to skip the test, `{ todo: true | string }` to mark it as todo
125
+ * (both map to Deno's `{ ignore: true }`). Other Deno BDD options like
126
+ * `{ concurrency: false }` or `{ sanitizeExit: false }` are forwarded as-is.
125
127
  * @param {function} testContent - Test callback receiving `(assert, { testName, options })`.
126
128
  * @example
127
129
  * ```js
@@ -159,6 +161,7 @@ export { default as test } from './test.ts';
159
161
  * ```
160
162
  */
161
163
  export const skip = Test.skip;
164
+ export const todo = Test.todo;
162
165
 
163
166
  /**
164
167
  * The default export provides the full QUnitX API as a single object.
@@ -1,6 +1,6 @@
1
1
  import { describe, beforeAll, afterAll } from "jsr:@std/testing/bdd";
2
2
  import type Assert from '../shared/assert.ts';
3
- import type { HooksObject } from '../types.ts';
3
+ import type { HookFn, HooksObject } from '../types.ts';
4
4
  import ModuleContext from '../shared/module-context.ts';
5
5
  export type { Assert };
6
6
  export type { HookFn, HooksObject, PushResultInfo } from '../types.ts';
@@ -32,13 +32,13 @@ export type { HookFn, HooksObject, PushResultInfo } from '../types.ts';
32
32
  * });
33
33
  * ```
34
34
  */
35
- export default function module(moduleName: string, moduleContent: (hooks: HooksObject<Assert>, meta: { moduleName: string; options: unknown }) => void): void;
35
+ export default function module(moduleName: string, moduleContent: (hooks: HooksObject<Assert>, meta: { moduleName: string; options: unknown; context: Record<string, unknown> }) => void): void;
36
36
  /** Defines a test module (suite) with optional Deno BDD runtime options forwarded to `describe()`. */
37
- export default function module(moduleName: string, runtimeOptions: object, moduleContent: (hooks: HooksObject<Assert>, meta: { moduleName: string; options: unknown }) => void): void;
37
+ export default function module(moduleName: string, runtimeOptions: object, moduleContent: (hooks: HooksObject<Assert>, meta: { moduleName: string; options: unknown; context: Record<string, unknown> }) => void): void;
38
38
  export default function module(
39
39
  moduleName: string,
40
40
  runtimeOptions: object | ((hooks: HooksObject<Assert>) => void),
41
- moduleContent?: (hooks: HooksObject<Assert>, meta: { moduleName: string; options: unknown }) => void,
41
+ moduleContent?: (hooks: HooksObject<Assert>, meta: { moduleName: string; options: unknown; context: Record<string, unknown> }) => void,
42
42
  ): void {
43
43
  const targetRuntimeOptions = moduleContent ? runtimeOptions as object : {};
44
44
  const { skip } = targetRuntimeOptions as { skip?: boolean | string };
@@ -57,8 +57,8 @@ export default function module(
57
57
  const moduleContext = new ModuleContext(moduleName);
58
58
 
59
59
  describe(moduleName, { ...targetRuntimeOptions }, function () {
60
- const beforeHooks: ((assert: Assert) => void | Promise<void>)[] = [];
61
- const afterHooks: ((assert: Assert) => void | Promise<void>)[] = [];
60
+ const beforeHooks: HookFn<Assert>[] = [];
61
+ const afterHooks: HookFn<Assert>[] = [];
62
62
 
63
63
  beforeAll(async function () {
64
64
  // before() assertions are attributed to the first direct test only (matching QUnit's model).
@@ -67,7 +67,7 @@ export default function module(
67
67
  const beforeAssert = firstTest ? firstTest.assert! : moduleContext.assert!;
68
68
 
69
69
  for (const hook of beforeHooks) {
70
- await hook.call(moduleContext.userContext, beforeAssert);
70
+ await hook.call(moduleContext.userContext, beforeAssert, { context: moduleContext.userContext });
71
71
  }
72
72
  });
73
73
 
@@ -79,7 +79,7 @@ export default function module(
79
79
  const lastTest = moduleContext.tests[moduleContext.tests.length - 1];
80
80
  if (lastTest) {
81
81
  for (let j = afterHooks.length - 1; j >= 0; j--) {
82
- await afterHooks[j]!.call(lastTest.userContext, lastTest.assert!);
82
+ await afterHooks[j]!.call(lastTest.userContext, lastTest.assert!, { context: lastTest.userContext });
83
83
  }
84
84
  }
85
85
 
@@ -101,7 +101,7 @@ export default function module(
101
101
  after(afterFn) {
102
102
  afterHooks.push(afterFn);
103
103
  }
104
- }, { moduleName, options: runtimeOptions });
104
+ }, { moduleName, options: runtimeOptions, context: moduleContext.userContext });
105
105
 
106
106
  ModuleContext.currentModuleChain.pop();
107
107
  });