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.
@@ -14,8 +14,10 @@ export type { PushResultInfo } from '../types.ts';
14
14
  * Must be called inside a `module()` callback.
15
15
  *
16
16
  * @param {string} testName - Name of the test
17
- * @param {object} [runtimeOptions] - Optional Deno BDD options forwarded to `it()`
18
- * (e.g. `{ concurrency: false }`, `{ sanitizeExit: false }`)
17
+ * @param {object} [runtimeOptions] - Optional options forwarded to `it()`.
18
+ * Use `{ skip: true | string }` to skip the test, `{ todo: true | string }` to mark it as todo
19
+ * (both map to Deno's `{ ignore: true }`). Other Deno BDD options like
20
+ * `{ concurrency: false }` or `{ sanitizeExit: false }` are forwarded as-is.
19
21
  * @param {function} testContent - Test callback receiving `(assert, { testName, options })`
20
22
  * @returns {void}
21
23
  * @example
@@ -34,13 +36,13 @@ export type { PushResultInfo } from '../types.ts';
34
36
  * });
35
37
  * ```
36
38
  */
37
- export default function test(testName: string, testContent: (assert: Assert, meta: { testName: string; options: unknown }) => void | Promise<void>): void;
39
+ export default function test(testName: string, testContent: (assert: Assert, meta: { testName: string; options: unknown; context: Record<string, unknown> }) => void | Promise<void>): void;
38
40
  /** Defines an individual test with optional Deno BDD runtime options forwarded to `it()`. */
39
- export default function test(testName: string, runtimeOptions: object, testContent: (assert: Assert, meta: { testName: string; options: unknown }) => void | Promise<void>): void;
41
+ export default function test(testName: string, runtimeOptions: object, testContent: (assert: Assert, meta: { testName: string; options: unknown; context: Record<string, unknown> }) => void | Promise<void>): void;
40
42
  export default function test(
41
43
  testName: string,
42
- runtimeOptions: object | ((assert: Assert, meta: { testName: string; options: unknown }) => void | Promise<void>),
43
- testContent?: (assert: Assert, meta: { testName: string; options: unknown }) => void | Promise<void>,
44
+ runtimeOptions: object | ((assert: Assert, meta: { testName: string; options: unknown; context: Record<string, unknown> }) => void | Promise<void>),
45
+ testContent?: (assert: Assert, meta: { testName: string; options: unknown; context: Record<string, unknown> }) => void | Promise<void>,
44
46
  ): void {
45
47
  const moduleContext = ModuleContext.lastModule;
46
48
  if (!moduleContext) {
@@ -48,12 +50,11 @@ export default function test(
48
50
  }
49
51
 
50
52
  const targetRuntimeOptions = testContent ? runtimeOptions as object : {};
51
- const { skip } = targetRuntimeOptions as { skip?: boolean | string };
53
+ const { skip, todo } = targetRuntimeOptions as { skip?: boolean | string; todo?: boolean | string };
52
54
 
53
- // If skip is set, register a skipped it() without creating a TestContext (whose
54
- // finish() would otherwise fire a "0 assertions" failure from afterAll).
55
- // Deno uses `ignore` instead of `skip`.
56
- if (skip) {
55
+ // skip/todo: no TestContext finish() would fire "0 assertions" from afterAll otherwise.
56
+ // Deno uses `ignore` for both (no native todo concept).
57
+ if (skip || todo) {
57
58
  it(testName, { ignore: true }, async function () {});
58
59
  return;
59
60
  }
@@ -68,20 +69,22 @@ export default function test(
68
69
  context.userContext = userContext;
69
70
 
70
71
  it(testName, { ...targetRuntimeOptions }, async function () {
72
+ const hookMeta = { context: userContext };
73
+
71
74
  for (const module of context.module!.moduleChain) {
72
75
  for (const hook of module.beforeEachHooks) {
73
- await hook.call(userContext, context.assert!);
76
+ await hook.call(userContext, context.assert!, hookMeta);
74
77
  }
75
78
  }
76
79
 
77
- const result = await targetTestContent.call(userContext, context.assert!, { testName, options: runtimeOptions });
80
+ const result = await targetTestContent.call(userContext, context.assert!, { testName, options: runtimeOptions, context: userContext });
78
81
 
79
82
  await context.assert!.waitForAsyncOps();
80
83
 
81
84
  for (let i = context.module!.moduleChain.length - 1; i >= 0; i--) {
82
85
  const module = context.module!.moduleChain[i];
83
86
  for (let j = module.afterEachHooks.length - 1; j >= 0; j--) {
84
- await module.afterEachHooks[j]!.call(userContext, context.assert!);
87
+ await module.afterEachHooks[j]!.call(userContext, context.assert!, hookMeta);
85
88
  }
86
89
  }
87
90
 
@@ -109,3 +112,25 @@ export default function test(
109
112
  test.skip = function skipTest(testName: string, _testContent?: unknown): void {
110
113
  it(testName, { ignore: true }, async function () {});
111
114
  };
115
+
116
+ /**
117
+ * Registers a todo test. Equivalent to `QUnit.test.todo`.
118
+ * The test body is never executed; the test is reported as ignored by Deno's runner
119
+ * (Deno has no native todo concept).
120
+ *
121
+ * @param {string} testName - Name of the test to mark as todo.
122
+ * @param {function} [_testContent] - Optional body (ignored — the test will not run).
123
+ * @example
124
+ * ```js ignore
125
+ * import { module, test } from "qunitx";
126
+ *
127
+ * module("Math", () => {
128
+ * test.todo("addition is not yet implemented", (assert) => {
129
+ * assert.equal(1 + 1, 2);
130
+ * });
131
+ * });
132
+ * ```
133
+ */
134
+ test.todo = function todoTest(testName: string, _testContent?: unknown): void {
135
+ it(testName, { ignore: true }, async function () {});
136
+ };
@@ -12,7 +12,7 @@ export default class ModuleContext {
12
12
 
13
13
  name!: string;
14
14
  assert!: Assert;
15
- userContext!: object;
15
+ userContext!: Record<string, unknown>;
16
16
 
17
17
  // Internal fallback assert for modules with no direct tests
18
18
  context = new TestContext();
@@ -68,7 +68,7 @@ export default class TestContext {
68
68
  this.#totalExecutedAssertions = value;
69
69
  }
70
70
 
71
- userContext: object = {};
71
+ userContext: Record<string, unknown> = {};
72
72
 
73
73
  constructor(name?: string, moduleContext?: ModuleContext) {
74
74
  if (moduleContext) {
package/shims/types.ts CHANGED
@@ -37,7 +37,7 @@ export interface TestState {
37
37
  asyncOps: Promise<void>[];
38
38
  timeout?: number;
39
39
  expectedAssertionCount?: number;
40
- userContext?: object;
40
+ userContext?: Record<string, unknown>;
41
41
  module?: { name: string };
42
42
  }
43
43
 
@@ -46,11 +46,11 @@ export interface ModuleState {
46
46
  context: TestState;
47
47
  }
48
48
 
49
- /** A lifecycle hook callback that receives an {@linkcode Assert} instance. */
50
- 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: { context: Record<string, unknown> }) => void | Promise<void>;
51
51
  export type TestFn<A = unknown> = (
52
52
  assert: A,
53
- meta: { testName: string; options: unknown },
53
+ meta: { testName: string; options: unknown; context: Record<string, unknown> },
54
54
  ) => void | Promise<unknown>;
55
55
 
56
56
  /** Lifecycle hooks available inside a `module()` callback. */