qunitx 0.12.2 → 0.12.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.
package/README.md CHANGED
@@ -1,11 +1,16 @@
1
+ <div align="center">
2
+
3
+ # QUnitX
4
+
1
5
  [![CI](https://github.com/izelnakri/qunitx/actions/workflows/ci.yml/badge.svg)](https://github.com/izelnakri/qunitx/actions/workflows/ci.yml)
6
+ [![codecov](https://codecov.io/gh/izelnakri/qunitx/branch/main/graph/badge.svg)](https://codecov.io/gh/izelnakri/qunitx)
2
7
  [![npm](https://img.shields.io/npm/v/qunitx)](https://www.npmjs.com/package/qunitx)
3
8
  [![npm downloads](https://img.shields.io/npm/dm/qunitx)](https://www.npmjs.com/package/qunitx)
4
9
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
5
10
  [![Ask me anything](https://img.shields.io/badge/ask%20me-anything-1abc9c.svg)](https://github.com/izelnakri/qunitx/issues)
6
11
  [![Sponsor](https://img.shields.io/badge/sponsor-%E2%99%A5-pink)](https://github.com/sponsors/izelnakri)
7
12
 
8
- # QUnitX
13
+ </div>
9
14
 
10
15
  **The oldest, most battle-tested JavaScript test API — now universal.**
11
16
 
@@ -36,6 +41,10 @@ ecosystem:
36
41
  QUnitX wraps this API to work with **Node.js's built-in `node:test` runner** and
37
42
  **Deno's native test runner** — no Jest, Vitest, or other framework needed.
38
43
 
44
+ QUnit includes the fastest assertion and test runtime in JS world. I've previously contributed to some [speed optimizations](https://qunitjs.com/blog/2022/02/15/qunit-2-18-0/) to QUnit, we benchmark every possible thing to make it the fastest test
45
+ runtime, faster than node.js and deno default assertions in most cases. Therefore I consider myself very objective
46
+ when I say QUnit(X) is the best JS/TS testing tool out there.
47
+
39
48
  ---
40
49
 
41
50
  ## Demo
@@ -51,14 +60,12 @@ Live browser UI example (click to see filterable QUnit test suite):
51
60
 
52
61
  [objectmodel.js.org/test/?moduleId=6e15ed5f](https://objectmodel.js.org/test/?moduleId=6e15ed5f&moduleId=950ec9c5)
53
62
 
54
- ![QUnitX CLI help](https://raw.githubusercontent.com/izelnakri/qunitx/main/docs/qunitx-help-stdout.png)
55
-
56
63
  ---
57
64
 
58
65
  ## Installation
59
66
 
60
67
  ```sh
61
- npm install qunitx
68
+ npm install qunitx --save-dev
62
69
  ```
63
70
 
64
71
  Requires **Node.js >= 22** (LTS) or **Deno >= 2**.
@@ -204,6 +211,8 @@ familiar browser UI with zero extra layers.
204
211
 
205
212
  ## Code coverage
206
213
 
214
+ Probably c8 isn't even needed since qunitx runs as a dependency(rather than runtime) on node.js and deno.
215
+
207
216
  ```sh
208
217
  # Node (any c8-compatible reporter)
209
218
  npx c8 node --test test/
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "qunitx",
3
3
  "type": "module",
4
- "version": "0.12.2",
4
+ "version": "0.12.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",
@@ -63,8 +63,10 @@
63
63
  "url": "git+https://github.com/izelnakri/qunitx.git"
64
64
  },
65
65
  "scripts": {
66
- "lint": "prettier --check \"test/**/*.js\" \"*.js\" \"package.json\"",
67
- "lint:fix": "prettier --write \"test/**/*.js\" \"*.js\" \"package.json\"",
66
+ "format": "prettier --check \"test/**/*.js\" \"*.js\" \"package.json\"",
67
+ "format:fix": "prettier --write \"test/**/*.js\" \"*.js\" \"package.json\"",
68
+ "lint": "deno lint shims/",
69
+ "lint:docs": "deno doc --lint shims/deno/module.js shims/deno/test.js",
68
70
  "build": "node build.js",
69
71
  "run:all": "npm run run:node && npm run run:deno",
70
72
  "run:node": "node --test test/helpers/passing-tests.js && node --test test/helpers/failing-tests.js",
@@ -77,7 +79,11 @@
77
79
  "test:dev": "npm run test | tee test-output.log",
78
80
  "test:browser": "qunitx test/index.js --debug",
79
81
  "test:deno": "deno test --allow-read --allow-env --allow-run test/index.js",
80
- "test:node": "node --test test/index.js"
82
+ "test:doctests": "deno test --doc --allow-env --allow-read shims/deno/module.js shims/deno/test.js",
83
+ "test:node": "node --test test/index.js",
84
+ "coverage": "deno test --coverage=tmp/coverage --allow-read --allow-env --allow-run test/index.js && deno coverage --lcov --output=tmp/coverage/lcov.info --include='shims/' tmp/coverage && node scripts/check-coverage.js",
85
+ "coverage:report": "npm run coverage && deno coverage --html --include='shims/' tmp/coverage",
86
+ "docs": "deno doc --html --name=\"QUnitX\" --output=docs/src shims/deno/index.js"
81
87
  },
82
88
  "devDependencies": {
83
89
  "prettier": "^3.8.1",
@@ -0,0 +1,15 @@
1
+ import { readFile } from 'node:fs/promises';
2
+
3
+ const THRESHOLD = 85;
4
+ const lcov = await readFile('tmp/coverage/lcov.info', 'utf8');
5
+
6
+ const lh = [...lcov.matchAll(/^LH:(\d+)/gm)].reduce((s, m) => s + parseInt(m[1]), 0);
7
+ const lf = [...lcov.matchAll(/^LF:(\d+)/gm)].reduce((s, m) => s + parseInt(m[1]), 0);
8
+ const pct = lf > 0 ? (lh / lf) * 100 : 0;
9
+
10
+ console.log(`Coverage: ${pct.toFixed(1)}% (${lh}/${lf} lines)`);
11
+
12
+ if (pct < THRESHOLD) {
13
+ console.error(`Error: coverage ${pct.toFixed(1)}% is below the ${THRESHOLD}% threshold.`);
14
+ process.exit(1);
15
+ }
@@ -1,3 +1,29 @@
1
+ /**
2
+ * QUnitX — universal test library that runs the same test file in Node.js, Deno, and browser.
3
+ *
4
+ * Wraps QUnit's assertion API over each runtime's native BDD test runner so you only
5
+ * write your tests once.
6
+ *
7
+ * @example
8
+ * ```js
9
+ * import { module, test } from "qunitx";
10
+ *
11
+ * module("Math", (hooks) => {
12
+ * hooks.before((assert) => assert.step("setup"));
13
+ *
14
+ * test("addition", (assert) => {
15
+ * assert.equal(1 + 1, 2);
16
+ * });
17
+ *
18
+ * test("async", async (assert) => {
19
+ * const n = await Promise.resolve(42);
20
+ * assert.strictEqual(n, 42);
21
+ * });
22
+ * });
23
+ * ```
24
+ *
25
+ * @module
26
+ */
1
27
  import { AssertionError as DenoAssertionError } from "jsr:@std/assert";
2
28
  import '../../vendor/qunit.js';
3
29
  import Assert from '../shared/assert.js';
@@ -6,6 +32,24 @@ import TestContext from '../shared/test-context.js';
6
32
  import Module from './module.js';
7
33
  import Test from './test.js';
8
34
 
35
+ /**
36
+ * Thrown when an assertion fails. Extends Deno's built-in `AssertionError`
37
+ * so it integrates cleanly with Deno's test runner output.
38
+ *
39
+ * You rarely construct this directly — assertion methods on {@linkcode Assert}
40
+ * throw it automatically on failure.
41
+ *
42
+ * @example
43
+ * ```js
44
+ * import { AssertionError } from "qunitx";
45
+ *
46
+ * try {
47
+ * throw new AssertionError({ message: "something went wrong" });
48
+ * } catch (e) {
49
+ * console.log(e instanceof AssertionError); // true
50
+ * }
51
+ * ```
52
+ */
9
53
  export class AssertionError extends DenoAssertionError {
10
54
  constructor(object) {
11
55
  super(object.message);
@@ -21,7 +65,103 @@ Object.freeze(Assert);
21
65
  Object.freeze(ModuleContext);
22
66
  Object.freeze(TestContext);
23
67
 
68
+ export { Assert };
69
+
70
+ /**
71
+ * Defines a test module (suite). Wraps Deno's `describe()` and sets up the
72
+ * QUnit lifecycle — `before`, `beforeEach`, `afterEach`, and `after` hooks,
73
+ * assertion counting, and step tracking.
74
+ *
75
+ * Each {@linkcode test} inside the callback receives an {@linkcode Assert} instance.
76
+ * Modules can be nested by calling `module()` inside another module's callback.
77
+ *
78
+ * @param {string} moduleName - Name of the test suite.
79
+ * @param {object} [runtimeOptions] - Optional Deno BDD options forwarded to `describe()`
80
+ * (e.g. `{ concurrency: false }`, `{ permissions: { read: true } }`).
81
+ * @param {function} moduleContent - Callback that defines tests and hooks.
82
+ * Receives `(hooks, { moduleName, options })` where `hooks` exposes
83
+ * `before`, `beforeEach`, `afterEach`, and `after`.
84
+ * @example
85
+ * ```js
86
+ * import { module, test } from "qunitx";
87
+ *
88
+ * module("Math", (hooks) => {
89
+ * hooks.before((assert) => {
90
+ * assert.step("before hook ran");
91
+ * });
92
+ *
93
+ * test("addition", (assert) => {
94
+ * assert.equal(2 + 2, 4);
95
+ * });
96
+ * });
97
+ * ```
98
+ * @example
99
+ * ```js
100
+ * // Nested modules
101
+ * module("Outer", () => {
102
+ * module("Inner", () => {
103
+ * test("nested test", (assert) => {
104
+ * assert.ok(true);
105
+ * });
106
+ * });
107
+ * });
108
+ * ```
109
+ */
24
110
  export const module = Module;
111
+
112
+ /**
113
+ * Defines an individual test. Wraps Deno's `it()` and handles the full QUnit
114
+ * lifecycle: `beforeEach`/`afterEach` hooks, async assertion waiting, and step
115
+ * verification. Must be called inside a {@linkcode module} callback.
116
+ *
117
+ * The test callback receives `(assert, { testName, options })` where `assert`
118
+ * is an {@linkcode Assert} instance.
119
+ *
120
+ * @param {string} testName - Name of the test.
121
+ * @param {object} [runtimeOptions] - Optional Deno BDD options forwarded to `it()`
122
+ * (e.g. `{ concurrency: false }`, `{ sanitizeExit: false }`).
123
+ * @param {function} testContent - Test callback receiving `(assert, { testName, options })`.
124
+ * @example
125
+ * ```js
126
+ * import { module, test } from "qunitx";
127
+ *
128
+ * module("Math", () => {
129
+ * test("addition", (assert) => {
130
+ * assert.equal(1 + 1, 2);
131
+ * });
132
+ *
133
+ * test("async resolves correctly", async (assert) => {
134
+ * const result = await Promise.resolve(42);
135
+ * assert.strictEqual(result, 42);
136
+ * });
137
+ * });
138
+ * ```
139
+ */
25
140
  export const test = Test;
26
141
 
142
+ /**
143
+ * The default export provides the full QUnitX API as a single object.
144
+ *
145
+ * @example
146
+ * ```js
147
+ * import qunitx from "qunitx";
148
+ *
149
+ * qunitx.module("Math", () => {
150
+ * qunitx.test("addition", (assert) => {
151
+ * assert.equal(1 + 1, 2);
152
+ * });
153
+ * });
154
+ * ```
155
+ *
156
+ * @property {Function} module - Defines a test suite. Wraps Deno's `describe()` with
157
+ * QUnit lifecycle hooks (`before`, `beforeEach`, `afterEach`, `after`).
158
+ * See the named {@linkcode module} export for full parameter documentation.
159
+ * @property {Function} test - Defines an individual test inside a `module()` callback.
160
+ * Receives an {@linkcode Assert} instance as its first argument.
161
+ * See the named {@linkcode test} export for full parameter documentation.
162
+ * @property {typeof AssertionError} AssertionError - The error class thrown when an
163
+ * assertion fails. Extends Deno's built-in `AssertionError`.
164
+ * @property {object} config - Runtime configuration object (currently unused; reserved
165
+ * for future QUnit config compatibility).
166
+ */
27
167
  export default { AssertionError: Assert.AssertionError, module, test, config: {} };
@@ -5,14 +5,41 @@ import ModuleContext from '../shared/module-context.js';
5
5
  // NOTE: QUnit expect() logic is buggy in nested modules
6
6
  // NOTE: after gets the last direct children test of the module, not last defined context of a module(last defined context is a module)
7
7
 
8
+ /**
9
+ * Defines a test module (suite) for Deno's BDD test runner.
10
+ *
11
+ * Wraps `describe()` from `@std/testing/bdd` and sets up the QUnit lifecycle
12
+ * (before/beforeEach/afterEach/after hooks, assertion counting, steps tracking).
13
+ *
14
+ * @param {string} moduleName - Name of the test suite
15
+ * @param {object} [runtimeOptions] - Optional Deno BDD options forwarded to `describe()`
16
+ * (e.g. `{ concurrency: false }`, `{ permissions: { read: true } }`)
17
+ * @param {function} moduleContent - Callback that defines tests and hooks via `hooks.before`,
18
+ * `hooks.beforeEach`, `hooks.afterEach`, `hooks.after`
19
+ * @returns {void}
20
+ * @example
21
+ * ```js ignore
22
+ * import { module, test } from "qunitx";
23
+ *
24
+ * module("Math", (hooks) => {
25
+ * hooks.before((assert) => {
26
+ * assert.step("before hook ran");
27
+ * });
28
+ *
29
+ * test("addition", (assert) => {
30
+ * assert.equal(2 + 2, 4);
31
+ * });
32
+ * });
33
+ * ```
34
+ */
8
35
  export default function module(moduleName, runtimeOptions, moduleContent) {
9
- let targetRuntimeOptions = moduleContent ? runtimeOptions : {};
10
- let targetModuleContent = moduleContent ? moduleContent : runtimeOptions;
11
- let moduleContext = new ModuleContext(moduleName);
36
+ const targetRuntimeOptions = moduleContent ? runtimeOptions : {};
37
+ const targetModuleContent = moduleContent ? moduleContent : runtimeOptions;
38
+ const moduleContext = new ModuleContext(moduleName);
12
39
 
13
- return describe(moduleName, { concurrency: true, ...targetRuntimeOptions }, function () {
14
- let beforeHooks = [];
15
- let afterHooks = [];
40
+ describe(moduleName, { concurrency: true, ...targetRuntimeOptions }, function () {
41
+ const beforeHooks = [];
42
+ const afterHooks = [];
16
43
 
17
44
  beforeAll(async function () {
18
45
  Object.assign(moduleContext.context, moduleContext.moduleChain.reduce((result, module) => {
@@ -24,7 +51,7 @@ export default function module(moduleName, runtimeOptions, moduleContent) {
24
51
  });
25
52
  }, { steps: [], expectedAssertionCount: undefined }));
26
53
 
27
- for (let hook of beforeHooks) {
54
+ for (const hook of beforeHooks) {
28
55
  await hook.call(moduleContext.context, moduleContext.assert);
29
56
  }
30
57
 
@@ -41,7 +68,7 @@ export default function module(moduleName, runtimeOptions, moduleContent) {
41
68
  await assert.waitForAsyncOps();
42
69
  }
43
70
 
44
- let targetContext = moduleContext.tests[moduleContext.tests.length - 1];
71
+ const targetContext = moduleContext.tests[moduleContext.tests.length - 1];
45
72
  for (let j = afterHooks.length - 1; j >= 0; j--) {
46
73
  await afterHooks[j].call(targetContext, targetContext.assert);
47
74
  }
@@ -2,29 +2,58 @@ import { it } from "jsr:@std/testing/bdd";
2
2
  import TestContext from '../shared/test-context.js';
3
3
  import ModuleContext from '../shared/module-context.js';
4
4
 
5
+ /**
6
+ * Defines an individual test within a module for Deno's BDD test runner.
7
+ *
8
+ * Wraps `it()` from `@std/testing/bdd` and handles the full QUnit lifecycle:
9
+ * beforeEach/afterEach hooks, async assertion waiting, and step verification.
10
+ *
11
+ * Must be called inside a `module()` callback.
12
+ *
13
+ * @param {string} testName - Name of the test
14
+ * @param {object} [runtimeOptions] - Optional Deno BDD options forwarded to `it()`
15
+ * (e.g. `{ concurrency: false }`, `{ sanitizeExit: false }`)
16
+ * @param {function} testContent - Test callback receiving `(assert, { testName, options })`
17
+ * @returns {void}
18
+ * @example
19
+ * ```js ignore
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
+ */
5
34
  export default function test(testName, runtimeOptions, testContent) {
6
- let moduleContext = ModuleContext.lastModule;
35
+ const moduleContext = ModuleContext.lastModule;
7
36
  if (!moduleContext) {
8
37
  throw new Error(`Test '${testName}' called outside of module context.`);
9
38
  }
10
39
 
11
- let targetRuntimeOptions = testContent ? runtimeOptions : {};
12
- let targetTestContent = testContent ? testContent : runtimeOptions;
13
- let context = new TestContext(testName, moduleContext);
40
+ const targetRuntimeOptions = testContent ? runtimeOptions : {};
41
+ const targetTestContent = testContent ? testContent : runtimeOptions;
42
+ const context = new TestContext(testName, moduleContext);
14
43
 
15
- return it(testName, { concurrency: true, ...targetRuntimeOptions }, async function () {
16
- for (let module of context.module.moduleChain) {
17
- for (let hook of module.beforeEachHooks) {
44
+ it(testName, { concurrency: true, ...targetRuntimeOptions }, async function () {
45
+ for (const module of context.module.moduleChain) {
46
+ for (const hook of module.beforeEachHooks) {
18
47
  await hook.call(context, context.assert);
19
48
  }
20
49
  }
21
50
 
22
- let result = await targetTestContent.call(context, context.assert, { testName, options: runtimeOptions });
51
+ const result = await targetTestContent.call(context, context.assert, { testName, options: runtimeOptions });
23
52
 
24
53
  await context.assert.waitForAsyncOps();
25
54
 
26
55
  for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
27
- let module = context.module.moduleChain[i];
56
+ const module = context.module.moduleChain[i];
28
57
  for (let j = module.afterEachHooks.length - 1; j >= 0; j--) {
29
58
  await module.afterEachHooks[j].call(context, context.assert);
30
59
  }
@@ -6,13 +6,13 @@ import ModuleContext from '../shared/module-context.js';
6
6
  // NOTE: after gets the last direct children test of the module, not last defined context of a module(last defined context is a module)
7
7
 
8
8
  export default function module(moduleName, runtimeOptions, moduleContent) {
9
- let targetRuntimeOptions = moduleContent ? runtimeOptions : {};
10
- let targetModuleContent = moduleContent ? moduleContent : runtimeOptions;
11
- let moduleContext = new ModuleContext(moduleName);
9
+ const targetRuntimeOptions = moduleContent ? runtimeOptions : {};
10
+ const targetModuleContent = moduleContent ? moduleContent : runtimeOptions;
11
+ const moduleContext = new ModuleContext(moduleName);
12
12
 
13
- return describe(moduleName, { concurrency: true, ...targetRuntimeOptions }, async function () {
14
- let beforeHooks = [];
15
- let afterHooks = [];
13
+ return describe(moduleName, { concurrency: true, ...targetRuntimeOptions }, function () {
14
+ const beforeHooks = [];
15
+ const afterHooks = [];
16
16
 
17
17
  beforeAll(async function () {
18
18
  Object.assign(moduleContext.context, moduleContext.moduleChain.reduce((result, module) => {
@@ -24,7 +24,7 @@ export default function module(moduleName, runtimeOptions, moduleContent) {
24
24
  });
25
25
  }, { steps: [], expectedAssertionCount: undefined }));
26
26
 
27
- for (let hook of beforeHooks) {
27
+ for (const hook of beforeHooks) {
28
28
  await hook.call(moduleContext.context, moduleContext.assert);
29
29
  }
30
30
 
@@ -41,7 +41,7 @@ export default function module(moduleName, runtimeOptions, moduleContent) {
41
41
  await assert.waitForAsyncOps();
42
42
  }
43
43
 
44
- let targetContext = moduleContext.tests[moduleContext.tests.length - 1];
44
+ const targetContext = moduleContext.tests[moduleContext.tests.length - 1];
45
45
  for (let j = afterHooks.length - 1; j >= 0; j--) {
46
46
  await afterHooks[j].call(targetContext, targetContext.assert);
47
47
  }
@@ -3,28 +3,28 @@ import TestContext from '../shared/test-context.js';
3
3
  import ModuleContext from '../shared/module-context.js';
4
4
 
5
5
  export default function test(testName, runtimeOptions, testContent) {
6
- let moduleContext = ModuleContext.lastModule;
6
+ const moduleContext = ModuleContext.lastModule;
7
7
  if (!moduleContext) {
8
8
  throw new Error(`Test '${testName}' called outside of module context.`);
9
9
  }
10
10
 
11
- let targetRuntimeOptions = testContent ? runtimeOptions : {};
12
- let targetTestContent = testContent ? testContent : runtimeOptions;
13
- let context = new TestContext(testName, moduleContext);
11
+ const targetRuntimeOptions = testContent ? runtimeOptions : {};
12
+ const targetTestContent = testContent ? testContent : runtimeOptions;
13
+ const context = new TestContext(testName, moduleContext);
14
14
 
15
15
  return it(testName, { concurrency: true, ...targetRuntimeOptions }, async function () {
16
- for (let module of context.module.moduleChain) {
17
- for (let hook of module.beforeEachHooks) {
16
+ for (const module of context.module.moduleChain) {
17
+ for (const hook of module.beforeEachHooks) {
18
18
  await hook.call(context, context.assert);
19
19
  }
20
20
  }
21
21
 
22
- let result = await targetTestContent.call(context, context.assert, { testName, options: runtimeOptions });
22
+ const result = await targetTestContent.call(context, context.assert, { testName, options: runtimeOptions });
23
23
 
24
24
  await context.assert.waitForAsyncOps();
25
25
 
26
26
  for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
27
- let module = context.module.moduleChain[i];
27
+ const module = context.module.moduleChain[i];
28
28
  for (let j = module.afterEachHooks.length - 1; j >= 0; j--) {
29
29
  await module.afterEachHooks[j].call(context, context.assert);
30
30
  }
@@ -6,6 +6,25 @@ import util from 'node:util';
6
6
  // NOTE: Another approach for a global report Make this._assertions.set(this.currentTest, (this._assertions.get(this.currentTest) || 0) + 1); for pushResult
7
7
  // NOTE: This should *always* be a singleton(?), passed around as an argument for hooks. Seems difficult with concurrency. Singleton needs to be a concurrent data structure.
8
8
 
9
+ /**
10
+ * The assertion object passed to every test callback and lifecycle hook.
11
+ *
12
+ * Every {@linkcode test} callback receives an instance of `Assert` as its first argument.
13
+ * All assertion methods throw an {@linkcode AssertionError} on failure, which the test
14
+ * runner catches and reports.
15
+ *
16
+ * @example
17
+ * ```js
18
+ * import { module, test } from "qunitx";
19
+ *
20
+ * module("Math", () => {
21
+ * test("addition", (assert) => {
22
+ * assert.equal(1 + 1, 2);
23
+ * assert.strictEqual(typeof 42, "number");
24
+ * });
25
+ * });
26
+ * ```
27
+ */
9
28
  export default class Assert {
10
29
  static QUnit;
11
30
  static AssertionError;
@@ -17,6 +36,20 @@ export default class Assert {
17
36
  _incrementAssertionCount() {
18
37
  this.test.totalExecutedAssertions++;
19
38
  }
39
+
40
+ /**
41
+ * Sets the number of milliseconds after which the current test will fail if not yet complete.
42
+ *
43
+ * @param {number} number - Timeout in milliseconds (positive integer).
44
+ * @example
45
+ * ```js
46
+ * test("slow async operation", async (assert) => {
47
+ * assert.timeout(500);
48
+ * await somethingAsync();
49
+ * assert.ok(true);
50
+ * });
51
+ * ```
52
+ */
20
53
  timeout(number) {
21
54
  if (!Number.isInteger(number) || number < 0) {
22
55
  throw new Error('assert.timeout() expects a positive integer.');
@@ -24,6 +57,22 @@ export default class Assert {
24
57
 
25
58
  this.test.timeout = number;
26
59
  }
60
+
61
+ /**
62
+ * Records a named step. Use with {@linkcode Assert.prototype.verifySteps} to assert that
63
+ * a sequence of steps occurred in the right order.
64
+ *
65
+ * @param {string} message - The step label to record.
66
+ * @example
67
+ * ```js
68
+ * test("event order", (assert) => {
69
+ * assert.expect(3);
70
+ * assert.step("step one");
71
+ * assert.step("step two");
72
+ * assert.verifySteps(["step one", "step two"]);
73
+ * });
74
+ * ```
75
+ */
27
76
  step(message) {
28
77
  let assertionMessage = message;
29
78
  let result = !!message;
@@ -42,10 +91,41 @@ export default class Assert {
42
91
  message: assertionMessage
43
92
  });
44
93
  }
94
+
95
+ /**
96
+ * Asserts that the steps recorded via {@linkcode Assert.prototype.step} match the given array,
97
+ * then clears the recorded steps.
98
+ *
99
+ * @param {string[]} steps - Expected array of step labels in order.
100
+ * @param {string} [message] - Optional failure message.
101
+ * @example
102
+ * ```js
103
+ * test("lifecycle order", (assert) => {
104
+ * assert.step("init");
105
+ * assert.step("run");
106
+ * assert.verifySteps(["init", "run"]);
107
+ * });
108
+ * ```
109
+ */
45
110
  verifySteps(steps, message = 'Verify steps failed!') {
46
111
  this.deepEqual(this.test.steps, steps, message);
47
112
  this.test.steps.length = 0;
48
113
  }
114
+
115
+ /**
116
+ * Sets the number of assertions expected to run in the current test.
117
+ * The test fails if a different number of assertions actually ran.
118
+ *
119
+ * @param {number} number - Expected assertion count (non-negative integer).
120
+ * @example
121
+ * ```js
122
+ * test("exactly two assertions", (assert) => {
123
+ * assert.expect(2);
124
+ * assert.ok(true);
125
+ * assert.ok(true);
126
+ * });
127
+ * ```
128
+ */
49
129
  expect(number) {
50
130
  if (!Number.isInteger(number) || number < 0) {
51
131
  throw new Error('assert.expect() expects a positive integer.');
@@ -53,17 +133,57 @@ export default class Assert {
53
133
 
54
134
  this.test.expectedAssertionCount = number;
55
135
  }
136
+
137
+ /**
138
+ * Returns a `done` callback for callback-style async tests. The test will not
139
+ * finish until every `done` callback returned by `async()` has been called.
140
+ *
141
+ * For `async/await` tests prefer `async (assert) => { ... }` directly.
142
+ *
143
+ * @returns {function} A callback to invoke when the async work finishes.
144
+ * @example
145
+ * ```js
146
+ * test("async callback style", (assert) => {
147
+ * const done = assert.async();
148
+ * setTimeout(() => {
149
+ * assert.ok(true, "async callback ran");
150
+ * done();
151
+ * }, 10);
152
+ * });
153
+ * ```
154
+ */
56
155
  async() {
57
156
  let resolveFn;
58
- let done = new Promise(resolve => { resolveFn = resolve; });
157
+ const done = new Promise(resolve => { resolveFn = resolve; });
59
158
 
60
159
  this.test.asyncOps.push(done);
61
160
 
62
161
  return () => { resolveFn(); };
63
162
  }
64
- async waitForAsyncOps() {
163
+
164
+ waitForAsyncOps() {
65
165
  return Promise.all(this.test.asyncOps);
66
166
  }
167
+
168
+ /**
169
+ * Pushes a custom assertion result. Fails the test if `resultInfo.result` is falsy.
170
+ * Throws an {@linkcode AssertionError} on failure.
171
+ *
172
+ * Useful for building custom assertion helpers.
173
+ *
174
+ * @param {{ result: boolean, actual?: unknown, expected?: unknown, message?: string }} resultInfo
175
+ * @example
176
+ * ```js
177
+ * test("custom assertion", (assert) => {
178
+ * assert.pushResult({
179
+ * result: 1 + 1 === 2,
180
+ * actual: 2,
181
+ * expected: 2,
182
+ * message: "custom math check",
183
+ * });
184
+ * });
185
+ * ```
186
+ */
67
187
  pushResult(resultInfo = {}) {
68
188
  this._incrementAssertionCount();
69
189
  if (!resultInfo.result) {
@@ -77,6 +197,19 @@ export default class Assert {
77
197
 
78
198
  return this;
79
199
  }
200
+
201
+ /**
202
+ * Asserts that `state` is truthy.
203
+ *
204
+ * @param {unknown} state - The value to test.
205
+ * @param {string} [message] - Optional failure message.
206
+ * @example
207
+ * ```js
208
+ * assert.ok(true);
209
+ * assert.ok(1, "non-zero is truthy");
210
+ * assert.ok("hello");
211
+ * ```
212
+ */
80
213
  ok(state, message) {
81
214
  this._incrementAssertionCount();
82
215
  if (!state) {
@@ -88,6 +221,19 @@ export default class Assert {
88
221
  });
89
222
  }
90
223
  }
224
+
225
+ /**
226
+ * Asserts that `state` is falsy.
227
+ *
228
+ * @param {unknown} state - The value to test.
229
+ * @param {string} [message] - Optional failure message.
230
+ * @example
231
+ * ```js
232
+ * assert.notOk(false);
233
+ * assert.notOk(0, "zero is falsy");
234
+ * assert.notOk(null);
235
+ * ```
236
+ */
91
237
  notOk(state, message) {
92
238
  this._incrementAssertionCount();
93
239
  if (state) {
@@ -99,6 +245,18 @@ export default class Assert {
99
245
  });
100
246
  }
101
247
  }
248
+
249
+ /**
250
+ * Asserts that `state === true` (strict boolean true).
251
+ *
252
+ * @param {unknown} state - The value to test.
253
+ * @param {string} [message] - Optional failure message.
254
+ * @example
255
+ * ```js
256
+ * assert.true(1 === 1);
257
+ * assert.true(Array.isArray([]), "arrays are arrays");
258
+ * ```
259
+ */
102
260
  true(state, message) {
103
261
  this._incrementAssertionCount();
104
262
  if (state !== true) {
@@ -110,6 +268,18 @@ export default class Assert {
110
268
  });
111
269
  }
112
270
  }
271
+
272
+ /**
273
+ * Asserts that `state === false` (strict boolean false).
274
+ *
275
+ * @param {unknown} state - The value to test.
276
+ * @param {string} [message] - Optional failure message.
277
+ * @example
278
+ * ```js
279
+ * assert.false(1 === 2);
280
+ * assert.false(Number.isNaN(42), "42 is not NaN");
281
+ * ```
282
+ */
113
283
  false(state, message) {
114
284
  this._incrementAssertionCount();
115
285
  if (state !== false) {
@@ -121,6 +291,22 @@ export default class Assert {
121
291
  });
122
292
  }
123
293
  }
294
+
295
+ /**
296
+ * Asserts that `actual == expected` (loose equality, allows type coercion).
297
+ *
298
+ * Prefer {@linkcode Assert.prototype.strictEqual} for most comparisons. Use {@linkcode Assert.prototype.notEqual}
299
+ * for the inverse.
300
+ *
301
+ * @param {unknown} actual - The value produced by the code under test.
302
+ * @param {unknown} expected - The expected value.
303
+ * @param {string} [message] - Optional failure message.
304
+ * @example
305
+ * ```js
306
+ * assert.equal(1, 1);
307
+ * assert.equal("1", 1, "loose equality allows coercion");
308
+ * ```
309
+ */
124
310
  equal(actual, expected, message) {
125
311
  this._incrementAssertionCount();
126
312
  if (actual != expected) {
@@ -133,6 +319,19 @@ export default class Assert {
133
319
  });
134
320
  }
135
321
  }
322
+
323
+ /**
324
+ * Asserts that `actual != expected` (loose inequality). Inverse of {@linkcode Assert.prototype.equal}.
325
+ *
326
+ * @param {unknown} actual - The actual value.
327
+ * @param {unknown} expected - The value it should not loosely equal.
328
+ * @param {string} [message] - Optional failure message.
329
+ * @example
330
+ * ```js
331
+ * assert.notEqual(1, 2);
332
+ * assert.notEqual("hello", "world");
333
+ * ```
334
+ */
136
335
  notEqual(actual, expected, message) {
137
336
  this._incrementAssertionCount();
138
337
  if (actual == expected) {
@@ -145,10 +344,27 @@ export default class Assert {
145
344
  });
146
345
  }
147
346
  }
347
+
348
+ /**
349
+ * Asserts that `actual` and `expected` have the same own enumerable properties
350
+ * and values. Prototype methods are ignored; only own properties are compared.
351
+ *
352
+ * @param {object} actual - The actual object.
353
+ * @param {object} expected - The expected object.
354
+ * @param {string} [message] - Optional failure message.
355
+ * @example
356
+ * ```js
357
+ * assert.propEqual({ a: 1, b: 2 }, { a: 1, b: 2 });
358
+ *
359
+ * // Ignores prototype methods — only own properties matter:
360
+ * function Point(x, y) { this.x = x; this.y = y; }
361
+ * assert.propEqual(new Point(1, 2), { x: 1, y: 2 });
362
+ * ```
363
+ */
148
364
  propEqual(actual, expected, message) {
149
365
  this._incrementAssertionCount();
150
- let targetActual = objectValues(actual);
151
- let targetExpected = objectValues(expected);
366
+ const targetActual = objectValues(actual);
367
+ const targetExpected = objectValues(expected);
152
368
  if (!Assert.QUnit.equiv(targetActual, targetExpected)) {
153
369
  throw new Assert.AssertionError({
154
370
  actual: targetActual,
@@ -158,10 +374,24 @@ export default class Assert {
158
374
  });
159
375
  }
160
376
  }
377
+
378
+ /**
379
+ * Asserts that `actual` and `expected` do NOT have the same own enumerable
380
+ * properties and values. Inverse of {@linkcode Assert.prototype.propEqual}.
381
+ *
382
+ * @param {object} actual - The actual object.
383
+ * @param {object} expected - The value it should not propEqual.
384
+ * @param {string} [message] - Optional failure message.
385
+ * @example
386
+ * ```js
387
+ * assert.notPropEqual({ a: 1 }, { a: 2 });
388
+ * assert.notPropEqual({ a: 1, b: 2 }, { a: 1 }); // extra key makes them unequal
389
+ * ```
390
+ */
161
391
  notPropEqual(actual, expected, message) {
162
392
  this._incrementAssertionCount();
163
- let targetActual = objectValues(actual);
164
- let targetExpected = objectValues(expected);
393
+ const targetActual = objectValues(actual);
394
+ const targetExpected = objectValues(expected);
165
395
  if (Assert.QUnit.equiv(targetActual, targetExpected)) {
166
396
  throw new Assert.AssertionError({
167
397
  actual: targetActual,
@@ -171,10 +401,24 @@ export default class Assert {
171
401
  });
172
402
  }
173
403
  }
404
+
405
+ /**
406
+ * Asserts that `actual` contains all own enumerable properties from `expected`
407
+ * with matching values. Extra properties on `actual` are allowed and ignored.
408
+ *
409
+ * @param {object} actual - The actual object (may have extra keys).
410
+ * @param {object} expected - The subset of key/value pairs that must be present.
411
+ * @param {string} [message] - Optional failure message.
412
+ * @example
413
+ * ```js
414
+ * assert.propContains({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 });
415
+ * assert.propContains(user, { role: "admin" });
416
+ * ```
417
+ */
174
418
  propContains(actual, expected, message) {
175
419
  this._incrementAssertionCount();
176
- let targetActual = objectValuesSubset(actual, expected);
177
- let targetExpected = objectValues(expected, false);
420
+ const targetActual = objectValuesSubset(actual, expected);
421
+ const targetExpected = objectValues(expected, false);
178
422
  if (!Assert.QUnit.equiv(targetActual, targetExpected)) {
179
423
  throw new Assert.AssertionError({
180
424
  actual: targetActual,
@@ -184,10 +428,24 @@ export default class Assert {
184
428
  });
185
429
  }
186
430
  }
431
+
432
+ /**
433
+ * Asserts that `actual` does NOT contain all own enumerable properties
434
+ * from `expected` with matching values. Inverse of {@linkcode Assert.prototype.propContains}.
435
+ *
436
+ * @param {object} actual - The actual object.
437
+ * @param {object} expected - The subset of properties that must NOT all match.
438
+ * @param {string} [message] - Optional failure message.
439
+ * @example
440
+ * ```js
441
+ * assert.notPropContains({ a: 1, b: 2 }, { a: 9 });
442
+ * assert.notPropContains(user, { role: "banned" });
443
+ * ```
444
+ */
187
445
  notPropContains(actual, expected, message) {
188
446
  this._incrementAssertionCount();
189
- let targetActual = objectValuesSubset(actual, expected);
190
- let targetExpected = objectValues(expected);
447
+ const targetActual = objectValuesSubset(actual, expected);
448
+ const targetExpected = objectValues(expected);
191
449
  if (Assert.QUnit.equiv(targetActual, targetExpected)) {
192
450
  throw new Assert.AssertionError({
193
451
  actual: targetActual,
@@ -197,6 +455,20 @@ export default class Assert {
197
455
  });
198
456
  }
199
457
  }
458
+
459
+ /**
460
+ * Asserts deep equality between `actual` and `expected` using recursive structural
461
+ * comparison. Handles nested objects, arrays, `Date`, `RegExp`, and more.
462
+ *
463
+ * @param {unknown} actual - The actual value.
464
+ * @param {unknown} expected - The expected value.
465
+ * @param {string} [message] - Optional failure message.
466
+ * @example
467
+ * ```js
468
+ * assert.deepEqual([1, { a: 2 }], [1, { a: 2 }]);
469
+ * assert.deepEqual(new Date("2024-01-01"), new Date("2024-01-01"));
470
+ * ```
471
+ */
200
472
  deepEqual(actual, expected, message) {
201
473
  this._incrementAssertionCount();
202
474
  if (!Assert.QUnit.equiv(actual, expected)) {
@@ -209,6 +481,19 @@ export default class Assert {
209
481
  });
210
482
  }
211
483
  }
484
+
485
+ /**
486
+ * Asserts that `actual` and `expected` are NOT deeply equal. Inverse of {@linkcode Assert.prototype.deepEqual}.
487
+ *
488
+ * @param {unknown} actual - The actual value.
489
+ * @param {unknown} expected - The value it should not deepEqual.
490
+ * @param {string} [message] - Optional failure message.
491
+ * @example
492
+ * ```js
493
+ * assert.notDeepEqual([1, 2], [1, 3]);
494
+ * assert.notDeepEqual({ a: 1 }, { a: 2 });
495
+ * ```
496
+ */
212
497
  notDeepEqual(actual, expected, message) {
213
498
  this._incrementAssertionCount();
214
499
  if (Assert.QUnit.equiv(actual, expected)) {
@@ -221,6 +506,19 @@ export default class Assert {
221
506
  });
222
507
  }
223
508
  }
509
+
510
+ /**
511
+ * Asserts that `actual === expected` (strict equality, no type coercion).
512
+ *
513
+ * @param {unknown} actual - The actual value.
514
+ * @param {unknown} expected - The expected value.
515
+ * @param {string} [message] - Optional failure message.
516
+ * @example
517
+ * ```js
518
+ * assert.strictEqual(1 + 1, 2);
519
+ * assert.strictEqual(typeof "hello", "string");
520
+ * ```
521
+ */
224
522
  strictEqual(actual, expected, message) {
225
523
  this._incrementAssertionCount();
226
524
  if (actual !== expected) {
@@ -233,6 +531,19 @@ export default class Assert {
233
531
  });
234
532
  }
235
533
  }
534
+
535
+ /**
536
+ * Asserts that `actual !== expected` (strict inequality). Inverse of {@linkcode Assert.prototype.strictEqual}.
537
+ *
538
+ * @param {unknown} actual - The actual value.
539
+ * @param {unknown} expected - The value it should not strictly equal.
540
+ * @param {string} [message] - Optional failure message.
541
+ * @example
542
+ * ```js
543
+ * assert.notStrictEqual(1, "1", "different types");
544
+ * assert.notStrictEqual({}, {}, "different object references");
545
+ * ```
546
+ */
236
547
  notStrictEqual(actual, expected, message) {
237
548
  this._incrementAssertionCount();
238
549
  if (actual === expected) {
@@ -245,9 +556,25 @@ export default class Assert {
245
556
  });
246
557
  }
247
558
  }
559
+
560
+ /**
561
+ * Asserts that `blockFn` throws an exception. Optionally validates the thrown
562
+ * error against a string (message substring), RegExp (message pattern),
563
+ * or constructor (`instanceof` check). For async functions use {@linkcode Assert.prototype.rejects}.
564
+ *
565
+ * @param {function} blockFn - A synchronous function expected to throw.
566
+ * @param {string|RegExp|function} [expected] - Optional matcher for the thrown error.
567
+ * @param {string} [message] - Optional failure message.
568
+ * @example
569
+ * ```js
570
+ * assert.throws(() => { throw new Error("boom"); });
571
+ * assert.throws(() => JSON.parse("{bad}"), SyntaxError);
572
+ * assert.throws(() => { throw new Error("bad input"); }, /bad input/);
573
+ * ```
574
+ */
248
575
  throws(blockFn, expectedInput, assertionMessage) {
249
576
  this?._incrementAssertionCount();
250
- let [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, 'rejects');
577
+ const [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, 'rejects');
251
578
  if (typeof blockFn !== 'function') {
252
579
  throw new Assert.AssertionError({
253
580
  actual: blockFn,
@@ -260,7 +587,7 @@ export default class Assert {
260
587
  try {
261
588
  blockFn();
262
589
  } catch (error) {
263
- let validation = validateException(error, expected, message);
590
+ const validation = validateException(error, expected, message);
264
591
  if (validation.result === false) {
265
592
  throw new Assert.AssertionError({
266
593
  actual: validation.result,
@@ -280,10 +607,26 @@ export default class Assert {
280
607
  stackStartFn: this.throws,
281
608
  });
282
609
  }
610
+
611
+ /**
612
+ * Asserts that a promise rejects. Optionally validates the rejection reason
613
+ * against a string (message substring), RegExp (message pattern),
614
+ * or constructor (`instanceof` check). For synchronous throws use {@linkcode Assert.prototype.throws}.
615
+ *
616
+ * @param {Promise<unknown>} promise - A promise expected to reject.
617
+ * @param {string|RegExp|function} [expected] - Optional matcher for the rejection reason.
618
+ * @param {string} [message] - Optional failure message.
619
+ * @example
620
+ * ```js
621
+ * await assert.rejects(Promise.reject(new Error("oops")));
622
+ * await assert.rejects(fetch("/bad-url"), TypeError);
623
+ * await assert.rejects(Promise.reject(new Error("timeout")), /timeout/);
624
+ * ```
625
+ */
283
626
  async rejects(promise, expectedInput, assertionMessage) {
284
627
  this._incrementAssertionCount();
285
- let [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, 'rejects');
286
- let then = promise && promise.then;
628
+ const [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, 'rejects');
629
+ const then = promise && promise.then;
287
630
  if (typeof then !== 'function') {
288
631
  throw new Assert.AssertionError({
289
632
  actual: promise,
@@ -302,7 +645,7 @@ export default class Assert {
302
645
  stackStartFn: this.rejects,
303
646
  });
304
647
  } catch (error) {
305
- let validation = validateException(error, expected, message);
648
+ const validation = validateException(error, expected, message);
306
649
  if (validation.result === false) {
307
650
  throw new Assert.AssertionError({
308
651
  actual: validation.result,
@@ -1,14 +1,8 @@
1
1
  const hasOwn = Object.prototype.hasOwnProperty
2
2
 
3
- function _typeof(obj) {
4
- "@babel/helpers - typeof";
5
-
6
- return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
7
- return typeof obj;
8
- } : function (obj) {
9
- return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
10
- }, _typeof(obj);
11
- }
3
+ const _typeof = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol'
4
+ ? (obj) => typeof obj
5
+ : (obj) => obj && typeof Symbol === 'function' && obj.constructor === Symbol && obj !== Symbol.prototype ? 'symbol' : typeof obj;
12
6
 
13
7
  export function objectType(obj) {
14
8
  if (typeof obj === 'undefined') {
@@ -19,8 +13,8 @@ export function objectType(obj) {
19
13
  if (obj === null) {
20
14
  return 'null';
21
15
  }
22
- var match = toString.call(obj).match(/^\[object\s(.*)\]$/);
23
- var type = match && match[1];
16
+ const match = toString.call(obj).match(/^\[object\s(.*)\]$/);
17
+ const type = match && match[1];
24
18
  switch (type) {
25
19
  case 'Number':
26
20
  if (isNaN(obj)) {
@@ -47,12 +41,12 @@ function is(type, obj) {
47
41
  }
48
42
 
49
43
  export function objectValues(obj) {
50
- let allowArray = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
51
- let vals = allowArray && is('array', obj) ? [] : {};
44
+ const allowArray = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
45
+ const vals = allowArray && is('array', obj) ? [] : {};
52
46
 
53
- for (var key in obj) {
47
+ for (const key in obj) {
54
48
  if (hasOwn.call(obj, key)) {
55
- let val = obj[key];
49
+ const val = obj[key];
56
50
  vals[key] = val === Object(val) ? objectValues(val, allowArray) : val;
57
51
  }
58
52
  }
@@ -80,8 +74,8 @@ export function objectValuesSubset(obj, model) {
80
74
 
81
75
  // Unlike objectValues(), subset arrays to a plain objects as well.
82
76
  // This enables subsetting [20, 30] with {1: 30}.
83
- var subset = {};
84
- for (var key in model) {
77
+ const subset = {};
78
+ for (const key in model) {
85
79
  if (hasOwn.call(model, key) && hasOwn.call(obj, key)) {
86
80
  subset[key] = objectValuesSubset(obj[key], model[key]);
87
81
  }
@@ -90,7 +84,7 @@ export function objectValuesSubset(obj, model) {
90
84
  }
91
85
 
92
86
  export function validateExpectedExceptionArgs(expected, message, assertionMethod) {
93
- var expectedType = objectType(expected);
87
+ const expectedType = objectType(expected);
94
88
 
95
89
  // 'expected' is optional unless doing string comparison
96
90
  if (expectedType === 'string') {
@@ -102,7 +96,7 @@ export function validateExpectedExceptionArgs(expected, message, assertionMethod
102
96
  throw new Error('assert.' + assertionMethod + ' does not accept a string value for the expected argument.\n' + 'Use a non-string object value (e.g. RegExp or validator function) ' + 'instead if necessary.');
103
97
  }
104
98
  }
105
- var valid = !expected ||
99
+ const valid = !expected ||
106
100
  // TODO: be more explicit here
107
101
  expectedType === 'regexp' || expectedType === 'function' || expectedType === 'object';
108
102
  if (!valid) {
@@ -112,8 +106,8 @@ export function validateExpectedExceptionArgs(expected, message, assertionMethod
112
106
  }
113
107
 
114
108
  export function validateException(actual, expected, message) {
115
- var result = false;
116
- var expectedType = objectType(expected);
109
+ let result = false;
110
+ const expectedType = objectType(expected);
117
111
 
118
112
  // These branches should be exhaustive, based on validation done in validateExpectedException
119
113
 
@@ -157,7 +151,7 @@ export function validateException(actual, expected, message) {
157
151
 
158
152
  function errorString(error) {
159
153
  // Use String() instead of toString() to handle non-object values like undefined or null.
160
- var resultErrorString = String(error);
154
+ const resultErrorString = String(error);
161
155
 
162
156
  // If the error wasn't a subclass of Error but something like
163
157
  // an object literal with name and message properties...
@@ -16,7 +16,7 @@ export default class ModuleContext {
16
16
  tests = [];
17
17
 
18
18
  constructor(name) {
19
- let parentModule = ModuleContext.currentModuleChain[ModuleContext.currentModuleChain.length - 1];
19
+ const parentModule = ModuleContext.currentModuleChain[ModuleContext.currentModuleChain.length - 1];
20
20
 
21
21
  ModuleContext.currentModuleChain.push(this);
22
22
 
package/Makefile DELETED
@@ -1,28 +0,0 @@
1
- .PHONY: check test lint build release
2
-
3
- check: lint test
4
-
5
- lint:
6
- npm run lint
7
-
8
- test:
9
- npm test
10
-
11
- build:
12
- npm run build
13
-
14
- # Lint, bump version, update changelog, commit, tag, push, publish to npm.
15
- # CI then creates the GitHub release.
16
- # Usage: make release (defaults to patch)
17
- # make release LEVEL=minor|major
18
- LEVEL ?= patch
19
- release:
20
- @npm whoami 2>/dev/null || npm login
21
- npm run lint
22
- npm version $(LEVEL) --no-git-tag-version
23
- npm run changelog:update
24
- git add package.json package-lock.json CHANGELOG.md
25
- git commit -m "Release $$(node -p 'require("./package.json").version')"
26
- git tag "v$$(node -p 'require("./package.json").version')"
27
- git push && git push --tags
28
- npm publish --access public