qunitx 0.12.4 → 1.0.0
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/package.json +1 -1
- package/shims/deno/index.js +140 -0
- package/shims/shared/assert.js +343 -0
package/package.json
CHANGED
package/shims/deno/index.js
CHANGED
|
@@ -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: {} };
|
package/shims/shared/assert.js
CHANGED
|
@@ -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,6 +133,25 @@ 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
157
|
const done = new Promise(resolve => { resolveFn = resolve; });
|
|
@@ -61,9 +160,30 @@ export default class Assert {
|
|
|
61
160
|
|
|
62
161
|
return () => { resolveFn(); };
|
|
63
162
|
}
|
|
163
|
+
|
|
64
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,6 +344,23 @@ 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
366
|
const targetActual = objectValues(actual);
|
|
@@ -158,6 +374,20 @@ 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
393
|
const targetActual = objectValues(actual);
|
|
@@ -171,6 +401,20 @@ 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
420
|
const targetActual = objectValuesSubset(actual, expected);
|
|
@@ -184,6 +428,20 @@ 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
447
|
const targetActual = objectValuesSubset(actual, expected);
|
|
@@ -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,6 +556,22 @@ 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
577
|
const [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, 'rejects');
|
|
@@ -280,6 +607,22 @@ 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
628
|
const [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, 'rejects');
|