qunitx 0.8.3 → 0.9.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 +2 -2
- package/shims/deno/assert.js +98 -44
- package/shims/deno/index.js +217 -27
- package/shims/node/assert.js +100 -38
- package/shims/node/index.js +220 -58
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qunitx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.0",
|
|
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",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"ts-node": ">=10.7.0"
|
|
62
62
|
},
|
|
63
63
|
"volta": {
|
|
64
|
-
"node": "20.
|
|
64
|
+
"node": "20.5.0"
|
|
65
65
|
},
|
|
66
66
|
"prettier": {
|
|
67
67
|
"printWidth": 100,
|
package/shims/deno/assert.js
CHANGED
|
@@ -9,39 +9,79 @@ export class AssertionError extends DenoAssertionError {
|
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
export default class Assert {
|
|
13
|
+
AssertionError = AssertionError
|
|
14
|
+
|
|
15
|
+
#asyncOps = [];
|
|
16
|
+
|
|
17
|
+
constructor(module, test) {
|
|
18
|
+
this.test = test || module;
|
|
19
|
+
}
|
|
20
|
+
_incrementAssertionCount() {
|
|
21
|
+
this.test.totalExecutedAssertions++;
|
|
22
|
+
}
|
|
23
|
+
timeout(number) {
|
|
24
|
+
if (!Number.isInteger(number) || number < 0) {
|
|
25
|
+
throw new Error('assert.timeout() expects a positive integer.');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.test.timeout = number;
|
|
29
|
+
}
|
|
30
|
+
step(message) {
|
|
31
|
+
let assertionMessage = message;
|
|
32
|
+
let result = !!message;
|
|
33
|
+
|
|
34
|
+
this.test.steps.push(message);
|
|
35
|
+
|
|
36
|
+
if (typeof message === 'undefined' || message === '') {
|
|
37
|
+
assertionMessage = 'You must provide a message to assert.step';
|
|
38
|
+
} else if (typeof message !== 'string') {
|
|
39
|
+
assertionMessage = 'You must provide a string value to assert.step';
|
|
40
|
+
result = false;
|
|
41
|
+
}
|
|
23
42
|
|
|
24
|
-
this.
|
|
43
|
+
this.pushResult({
|
|
44
|
+
result,
|
|
45
|
+
message: assertionMessage
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
verifySteps(steps, message = 'Verify steps failed!') {
|
|
49
|
+
this.deepEqual(this.test.steps, steps, message);
|
|
50
|
+
this.test.steps.length = 0;
|
|
51
|
+
}
|
|
52
|
+
expect(number) {
|
|
53
|
+
if (!Number.isInteger(number) || number < 0) {
|
|
54
|
+
throw new Error('assert.expect() expects a positive integer.');
|
|
55
|
+
}
|
|
25
56
|
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
expect() {
|
|
29
|
-
return () => {}; // NOTE: NOT implemented
|
|
30
|
-
},
|
|
57
|
+
this.test.expectedAssertionCount = number;
|
|
58
|
+
}
|
|
31
59
|
async() {
|
|
32
|
-
|
|
33
|
-
|
|
60
|
+
let resolveFn;
|
|
61
|
+
let done = new Promise(resolve => { resolveFn = resolve; });
|
|
62
|
+
|
|
63
|
+
this.#asyncOps.push(done);
|
|
64
|
+
|
|
65
|
+
return () => { resolveFn(); };
|
|
66
|
+
}
|
|
67
|
+
async waitForAsyncOps() {
|
|
68
|
+
return Promise.all(this.#asyncOps);
|
|
69
|
+
}
|
|
34
70
|
pushResult(resultInfo = {}) {
|
|
35
|
-
|
|
71
|
+
this._incrementAssertionCount();
|
|
72
|
+
if (!resultInfo.result) {
|
|
36
73
|
throw new AssertionError({
|
|
37
74
|
actual: resultInfo.actual,
|
|
38
75
|
expected: resultInfo.expected,
|
|
39
|
-
message:
|
|
76
|
+
message: resultInfo.message || 'Custom assertion failed!',
|
|
40
77
|
stackStartFn: this.pushResult,
|
|
41
78
|
});
|
|
42
79
|
}
|
|
43
|
-
|
|
80
|
+
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
44
83
|
ok(state, message) {
|
|
84
|
+
this._incrementAssertionCount();
|
|
45
85
|
if (!state) {
|
|
46
86
|
throw new AssertionError({
|
|
47
87
|
actual: state,
|
|
@@ -50,8 +90,9 @@ export default {
|
|
|
50
90
|
stackStartFn: this.ok,
|
|
51
91
|
});
|
|
52
92
|
}
|
|
53
|
-
}
|
|
93
|
+
}
|
|
54
94
|
notOk(state, message) {
|
|
95
|
+
this._incrementAssertionCount();
|
|
55
96
|
if (state) {
|
|
56
97
|
throw new AssertionError({
|
|
57
98
|
actual: state,
|
|
@@ -60,8 +101,9 @@ export default {
|
|
|
60
101
|
stackStartFn: this.notOk,
|
|
61
102
|
});
|
|
62
103
|
}
|
|
63
|
-
}
|
|
104
|
+
}
|
|
64
105
|
true(state, message) {
|
|
106
|
+
this._incrementAssertionCount();
|
|
65
107
|
if (state !== true) {
|
|
66
108
|
throw new AssertionError({
|
|
67
109
|
actual: state,
|
|
@@ -70,8 +112,9 @@ export default {
|
|
|
70
112
|
stackStartFn: this.true,
|
|
71
113
|
});
|
|
72
114
|
}
|
|
73
|
-
}
|
|
115
|
+
}
|
|
74
116
|
false(state, message) {
|
|
117
|
+
this._incrementAssertionCount();
|
|
75
118
|
if (state !== false) {
|
|
76
119
|
throw new AssertionError({
|
|
77
120
|
actual: state,
|
|
@@ -80,8 +123,9 @@ export default {
|
|
|
80
123
|
stackStartFn: this.false,
|
|
81
124
|
});
|
|
82
125
|
}
|
|
83
|
-
}
|
|
126
|
+
}
|
|
84
127
|
equal(actual, expected, message) {
|
|
128
|
+
this._incrementAssertionCount();
|
|
85
129
|
if (actual != expected) {
|
|
86
130
|
throw new AssertionError({
|
|
87
131
|
actual,
|
|
@@ -91,8 +135,9 @@ export default {
|
|
|
91
135
|
stackStartFn: this.equal,
|
|
92
136
|
});
|
|
93
137
|
}
|
|
94
|
-
}
|
|
138
|
+
}
|
|
95
139
|
notEqual(actual, expected, message) {
|
|
140
|
+
this._incrementAssertionCount();
|
|
96
141
|
if (actual == expected) {
|
|
97
142
|
throw new AssertionError({
|
|
98
143
|
actual,
|
|
@@ -102,11 +147,12 @@ export default {
|
|
|
102
147
|
stackStartFn: this.notEqual,
|
|
103
148
|
});
|
|
104
149
|
}
|
|
105
|
-
}
|
|
150
|
+
}
|
|
106
151
|
propEqual(actual, expected, message) {
|
|
152
|
+
this._incrementAssertionCount();
|
|
107
153
|
let targetActual = objectValues(actual);
|
|
108
154
|
let targetExpected = objectValues(expected);
|
|
109
|
-
if (!
|
|
155
|
+
if (!QUnit.equiv(targetActual, targetExpected)) {
|
|
110
156
|
throw new AssertionError({
|
|
111
157
|
actual: targetActual,
|
|
112
158
|
expected: targetExpected,
|
|
@@ -114,11 +160,12 @@ export default {
|
|
|
114
160
|
stackStartFn: this.propEqual,
|
|
115
161
|
});
|
|
116
162
|
}
|
|
117
|
-
}
|
|
163
|
+
}
|
|
118
164
|
notPropEqual(actual, expected, message) {
|
|
165
|
+
this._incrementAssertionCount();
|
|
119
166
|
let targetActual = objectValues(actual);
|
|
120
167
|
let targetExpected = objectValues(expected);
|
|
121
|
-
if (
|
|
168
|
+
if (QUnit.equiv(targetActual, targetExpected)) {
|
|
122
169
|
throw new AssertionError({
|
|
123
170
|
actual: targetActual,
|
|
124
171
|
expected: targetExpected,
|
|
@@ -126,11 +173,12 @@ export default {
|
|
|
126
173
|
stackStartFn: this.notPropEqual,
|
|
127
174
|
});
|
|
128
175
|
}
|
|
129
|
-
}
|
|
176
|
+
}
|
|
130
177
|
propContains(actual, expected, message) {
|
|
178
|
+
this._incrementAssertionCount();
|
|
131
179
|
let targetActual = objectValuesSubset(actual, expected);
|
|
132
180
|
let targetExpected = objectValues(expected, false);
|
|
133
|
-
if (!
|
|
181
|
+
if (!QUnit.equiv(targetActual, targetExpected)) {
|
|
134
182
|
throw new AssertionError({
|
|
135
183
|
actual: targetActual,
|
|
136
184
|
expected: targetExpected,
|
|
@@ -138,11 +186,12 @@ export default {
|
|
|
138
186
|
stackStartFn: this.propContains,
|
|
139
187
|
});
|
|
140
188
|
}
|
|
141
|
-
}
|
|
189
|
+
}
|
|
142
190
|
notPropContains(actual, expected, message) {
|
|
191
|
+
this._incrementAssertionCount();
|
|
143
192
|
let targetActual = objectValuesSubset(actual, expected);
|
|
144
193
|
let targetExpected = objectValues(expected);
|
|
145
|
-
if (
|
|
194
|
+
if (QUnit.equiv(targetActual, targetExpected)) {
|
|
146
195
|
throw new AssertionError({
|
|
147
196
|
actual: targetActual,
|
|
148
197
|
expected: targetExpected,
|
|
@@ -150,9 +199,10 @@ export default {
|
|
|
150
199
|
stackStartFn: this.notPropContains,
|
|
151
200
|
});
|
|
152
201
|
}
|
|
153
|
-
}
|
|
202
|
+
}
|
|
154
203
|
deepEqual(actual, expected, message) {
|
|
155
|
-
|
|
204
|
+
this._incrementAssertionCount();
|
|
205
|
+
if (!QUnit.equiv(actual, expected)) {
|
|
156
206
|
throw new AssertionError({
|
|
157
207
|
actual,
|
|
158
208
|
expected,
|
|
@@ -161,9 +211,10 @@ export default {
|
|
|
161
211
|
stackStartFn: this.deepEqual,
|
|
162
212
|
});
|
|
163
213
|
}
|
|
164
|
-
}
|
|
214
|
+
}
|
|
165
215
|
notDeepEqual(actual, expected, message) {
|
|
166
|
-
|
|
216
|
+
this._incrementAssertionCount();
|
|
217
|
+
if (QUnit.equiv(actual, expected)) {
|
|
167
218
|
throw new AssertionError({
|
|
168
219
|
actual,
|
|
169
220
|
expected,
|
|
@@ -172,8 +223,9 @@ export default {
|
|
|
172
223
|
stackStartFn: this.notDeepEqual,
|
|
173
224
|
});
|
|
174
225
|
}
|
|
175
|
-
}
|
|
226
|
+
}
|
|
176
227
|
strictEqual(actual, expected, message) {
|
|
228
|
+
this._incrementAssertionCount();
|
|
177
229
|
if (actual !== expected) {
|
|
178
230
|
throw new AssertionError({
|
|
179
231
|
actual,
|
|
@@ -183,8 +235,9 @@ export default {
|
|
|
183
235
|
stackStartFn: this.strictEqual,
|
|
184
236
|
});
|
|
185
237
|
}
|
|
186
|
-
}
|
|
238
|
+
}
|
|
187
239
|
notStrictEqual(actual, expected, message) {
|
|
240
|
+
this._incrementAssertionCount();
|
|
188
241
|
if (actual === expected) {
|
|
189
242
|
throw new AssertionError({
|
|
190
243
|
actual,
|
|
@@ -194,8 +247,9 @@ export default {
|
|
|
194
247
|
stackStartFn: this.notStrictEqual,
|
|
195
248
|
});
|
|
196
249
|
}
|
|
197
|
-
}
|
|
250
|
+
}
|
|
198
251
|
throws(blockFn, expectedInput, assertionMessage) {
|
|
252
|
+
this?._incrementAssertionCount();
|
|
199
253
|
let [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, 'rejects');
|
|
200
254
|
if (typeof blockFn !== 'function') {
|
|
201
255
|
throw new AssertionError({
|
|
@@ -228,8 +282,9 @@ export default {
|
|
|
228
282
|
message: 'Function passed to `assert.throws` did not throw an exception!',
|
|
229
283
|
stackStartFn: this.throws,
|
|
230
284
|
});
|
|
231
|
-
}
|
|
285
|
+
}
|
|
232
286
|
async rejects(promise, expectedInput, assertionMessage) {
|
|
287
|
+
this._incrementAssertionCount();
|
|
233
288
|
let [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, 'rejects');
|
|
234
289
|
let then = promise && promise.then;
|
|
235
290
|
if (typeof then !== 'function') {
|
|
@@ -276,4 +331,3 @@ ${inspect(expected)}`
|
|
|
276
331
|
function inspect(value) {
|
|
277
332
|
return util.inspect(value, { depth: 10, colors: true, compact: false });
|
|
278
333
|
}
|
|
279
|
-
|
package/shims/deno/index.js
CHANGED
|
@@ -1,48 +1,238 @@
|
|
|
1
1
|
import {
|
|
2
|
-
afterEach,
|
|
3
|
-
beforeEach,
|
|
4
2
|
beforeAll,
|
|
5
3
|
afterAll,
|
|
6
4
|
describe,
|
|
7
5
|
it,
|
|
8
6
|
} from "https://deno.land/std@0.192.0/testing/bdd.ts";
|
|
9
|
-
import
|
|
7
|
+
import Assert from './assert.js';
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
let targetRuntimeOptions = moduleContent ? Object.assign(runtimeOptions, { name: moduleName }) : { name: moduleName };
|
|
14
|
-
let targetModuleContent = moduleContent ? moduleName : runtimeOptions;
|
|
9
|
+
class TestContext {
|
|
10
|
+
name;
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
#module;
|
|
13
|
+
get module() {
|
|
14
|
+
return this.#module;
|
|
15
|
+
}
|
|
16
|
+
set module(value) {
|
|
17
|
+
this.#module = value;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#assert;
|
|
21
|
+
get assert() {
|
|
22
|
+
return this.#assert;
|
|
23
|
+
}
|
|
24
|
+
set assert(value) {
|
|
25
|
+
this.#assert = value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#timeout;
|
|
29
|
+
get timeout() {
|
|
30
|
+
return this.#timeout;
|
|
31
|
+
}
|
|
32
|
+
set timeout(value) {
|
|
33
|
+
this.#timeout = value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#steps = [];
|
|
37
|
+
get steps() {
|
|
38
|
+
return this.#steps;
|
|
39
|
+
}
|
|
40
|
+
set steps(value) {
|
|
41
|
+
this.#steps = value;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#expectedAssertionCount;
|
|
45
|
+
get expectedAssertionCount() {
|
|
46
|
+
return this.#expectedAssertionCount;
|
|
47
|
+
}
|
|
48
|
+
set expectedAssertionCount(value) {
|
|
49
|
+
this.#expectedAssertionCount = value;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
#totalExecutedAssertions = 0;
|
|
53
|
+
get totalExecutedAssertions() {
|
|
54
|
+
return this.#totalExecutedAssertions;
|
|
55
|
+
}
|
|
56
|
+
set totalExecutedAssertions(value) {
|
|
57
|
+
this.#totalExecutedAssertions = value;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
constructor(name, moduleContext) {
|
|
61
|
+
if (moduleContext) {
|
|
62
|
+
this.name = `${moduleContext.name} | ${name}`;
|
|
63
|
+
this.module = moduleContext;
|
|
64
|
+
this.module.tests.push(this);
|
|
65
|
+
this.assert = new Assert(moduleContext, this);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
finish() {
|
|
70
|
+
if (this.totalExecutedAssertions === 0) {
|
|
71
|
+
this.assert.pushResult({
|
|
72
|
+
result: false,
|
|
73
|
+
actual: this.totalExecutedAssertions,
|
|
74
|
+
expected: '> 0',
|
|
75
|
+
message: `Expected at least one assertion to be run for test: ${this.name}`,
|
|
76
|
+
});
|
|
77
|
+
} else if (this.steps.length > 0) {
|
|
78
|
+
this.assert.pushResult({
|
|
79
|
+
result: false,
|
|
80
|
+
actual: this.steps,
|
|
81
|
+
expected: [],
|
|
82
|
+
message: `Expected assert.verifySteps() to be called before end of test after using assert.step(). Unverified steps: ${this.steps.join(', ')}`,
|
|
83
|
+
});
|
|
84
|
+
} else if (this.expectedAssertionCount && this.expectedAssertionCount !== this.totalExecutedAssertions) {
|
|
85
|
+
this.assert.pushResult({
|
|
86
|
+
result: false,
|
|
87
|
+
actual: this.totalExecutedAssertions,
|
|
88
|
+
expected: this.expectedAssertionCount,
|
|
89
|
+
message: `Expected ${this.expectedAssertionCount} assertions, but ${this.totalExecutedAssertions} were run for test: ${this.name}`,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
class ModuleContext extends TestContext {
|
|
96
|
+
static currentModuleChain = [];
|
|
97
|
+
|
|
98
|
+
static get lastModule() {
|
|
99
|
+
return this.currentModuleChain[this.currentModuleChain.length - 1];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
#tests = [];
|
|
103
|
+
get tests() {
|
|
104
|
+
return this.#tests;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
#beforeEachHooks = [];
|
|
108
|
+
get beforeEachHooks() {
|
|
109
|
+
return this.#beforeEachHooks;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
#afterEachHooks = [];
|
|
113
|
+
get afterEachHooks() {
|
|
114
|
+
return this.#afterEachHooks;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
#moduleChain = [];
|
|
118
|
+
get moduleChain() {
|
|
119
|
+
return this.#moduleChain;
|
|
120
|
+
}
|
|
121
|
+
set moduleChain(value) {
|
|
122
|
+
this.#moduleChain = value;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
constructor(name) {
|
|
126
|
+
super(name);
|
|
127
|
+
|
|
128
|
+
let parentModule = ModuleContext.currentModuleChain[ModuleContext.currentModuleChain.length - 1];
|
|
129
|
+
|
|
130
|
+
ModuleContext.currentModuleChain.push(this);
|
|
131
|
+
|
|
132
|
+
this.moduleChain = ModuleContext.currentModuleChain.slice(0);
|
|
133
|
+
this.name = parentModule ? `${parentModule.name} > ${name}` : name;
|
|
134
|
+
this.assert = new Assert(this);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export const module = (moduleName, runtimeOptions, moduleContent) => {
|
|
139
|
+
let targetRuntimeOptions = moduleContent ? runtimeOptions : {};
|
|
140
|
+
let targetModuleContent = moduleContent ? moduleContent : runtimeOptions;
|
|
141
|
+
let moduleContext = new ModuleContext(moduleName);
|
|
142
|
+
|
|
143
|
+
return describe(moduleName, { concurrency: true, ...targetRuntimeOptions }, async function () {
|
|
144
|
+
let beforeHooks = [];
|
|
145
|
+
let afterHooks = [];
|
|
146
|
+
|
|
147
|
+
beforeAll(async function () {
|
|
148
|
+
Object.assign(moduleContext, moduleContext.moduleChain.reduce((result, module) => {
|
|
149
|
+
const { name, ...moduleWithoutName } = module;
|
|
150
|
+
|
|
151
|
+
return Object.assign(result, moduleWithoutName, {
|
|
152
|
+
steps: result.steps.concat(module.steps),
|
|
153
|
+
expectedAssertionCount: module.expectedAssertionCount
|
|
154
|
+
? module.expectedAssertionCount
|
|
155
|
+
: result.expectedAssertionCount
|
|
156
|
+
});
|
|
157
|
+
}, { steps: [], expectedAssertionCount: undefined }));
|
|
158
|
+
|
|
159
|
+
for (let hook of beforeHooks) {
|
|
160
|
+
await hook.call(moduleContext, moduleContext.assert);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
moduleContext.tests.forEach((testContext) => {
|
|
164
|
+
const { name, ...moduleContextWithoutName } = moduleContext;
|
|
165
|
+
|
|
166
|
+
Object.assign(testContext, moduleContextWithoutName, {
|
|
167
|
+
steps: moduleContext.steps,
|
|
168
|
+
totalExecutedAssertions: moduleContext.totalExecutedAssertions,
|
|
169
|
+
expectedAssertionCount: moduleContext.expectedAssertionCount,
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
afterAll(async () => {
|
|
174
|
+
for (const assert of moduleContext.tests.map(testContext => testContext.assert)) {
|
|
175
|
+
await assert.waitForAsyncOps();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
let targetContext = moduleContext.tests[moduleContext.tests.length - 1];
|
|
179
|
+
for (let j = afterHooks.length - 1; j >= 0; j--) {
|
|
180
|
+
await afterHooks[j].call(targetContext, targetContext.assert);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
moduleContext.tests.forEach(testContext => testContext.finish());
|
|
20
184
|
});
|
|
185
|
+
|
|
186
|
+
targetModuleContent.call(moduleContext, {
|
|
187
|
+
before(beforeFn) {
|
|
188
|
+
return beforeHooks.push(beforeFn);
|
|
189
|
+
},
|
|
190
|
+
beforeEach(beforeEachFn) {
|
|
191
|
+
return moduleContext.beforeEachHooks.push(beforeEachFn);
|
|
192
|
+
},
|
|
193
|
+
afterEach(afterEachFn) {
|
|
194
|
+
return moduleContext.afterEachHooks.push(afterEachFn);
|
|
195
|
+
},
|
|
196
|
+
after(afterFn) {
|
|
197
|
+
return afterHooks.push(afterFn);
|
|
198
|
+
}
|
|
199
|
+
}, { moduleName, options: runtimeOptions });
|
|
200
|
+
|
|
201
|
+
ModuleContext.currentModuleChain.pop();
|
|
21
202
|
});
|
|
22
203
|
}
|
|
23
204
|
|
|
24
|
-
export const test =
|
|
25
|
-
let
|
|
205
|
+
export const test = (testName, runtimeOptions, testContent) => {
|
|
206
|
+
let moduleContext = ModuleContext.lastModule;
|
|
207
|
+
if (!moduleContext) {
|
|
208
|
+
throw new Error(`Test '${testName}' called outside of module context.`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let targetRuntimeOptions = testContent ? runtimeOptions : {};
|
|
26
212
|
let targetTestContent = testContent ? testContent : runtimeOptions;
|
|
213
|
+
let context = new TestContext(testName, moduleContext);
|
|
27
214
|
|
|
28
|
-
return it(targetRuntimeOptions, async function() {
|
|
29
|
-
let
|
|
30
|
-
|
|
215
|
+
return it(testName, { concurrency: true, ...targetRuntimeOptions }, async function () {
|
|
216
|
+
let result;
|
|
217
|
+
for (let module of context.module.moduleChain) {
|
|
218
|
+
for (let hook of module.beforeEachHooks) {
|
|
219
|
+
await hook.call(context, context.assert);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
31
222
|
|
|
32
|
-
|
|
223
|
+
result = await targetTestContent.call(context, context.assert, { testName, options: runtimeOptions });
|
|
33
224
|
|
|
34
|
-
|
|
35
|
-
});
|
|
36
|
-
}
|
|
225
|
+
await context.assert.waitForAsyncOps();
|
|
37
226
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
227
|
+
for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
|
|
228
|
+
let module = context.module.moduleChain[i];
|
|
229
|
+
for (let j = module.afterEachHooks.length - 1; j >= 0; j--) {
|
|
230
|
+
await module.afterEachHooks[j].call(context, context.assert);
|
|
231
|
+
}
|
|
42
232
|
}
|
|
43
|
-
}
|
|
44
233
|
|
|
45
|
-
|
|
234
|
+
return result;
|
|
235
|
+
});
|
|
46
236
|
}
|
|
47
237
|
|
|
48
|
-
export default { module, test,
|
|
238
|
+
export default { module, test, config: {} };
|
package/shims/node/assert.js
CHANGED
|
@@ -1,41 +1,88 @@
|
|
|
1
1
|
import QUnit from '../../vendor/qunit.js';
|
|
2
2
|
import { objectValues, objectValuesSubset, validateExpectedExceptionArgs, validateException } from '../shared/index.js';
|
|
3
|
-
import assert, { AssertionError } from 'node:assert';
|
|
3
|
+
import assert, { AssertionError as _AssertionError } from 'node:assert';
|
|
4
4
|
import util from 'node:util';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
export const AssertionError = _AssertionError;
|
|
7
|
+
|
|
8
|
+
// More: contexts needed for timeout
|
|
9
|
+
// NOTE: QUnit API provides assert on hooks, which makes it hard to make it concurrent
|
|
10
|
+
// NOTE: Another approach for a global report Make this._assertions.set(this.currentTest, (this._assertions.get(this.currentTest) || 0) + 1); for pushResult
|
|
11
|
+
// 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.
|
|
12
|
+
|
|
13
|
+
export default class Assert {
|
|
14
|
+
AssertionError = _AssertionError;
|
|
15
|
+
|
|
16
|
+
#asyncOps = [];
|
|
17
|
+
|
|
18
|
+
constructor(module, test) {
|
|
19
|
+
this.test = test || module;
|
|
20
|
+
}
|
|
21
|
+
_incrementAssertionCount() {
|
|
22
|
+
this.test.totalExecutedAssertions++;
|
|
23
|
+
}
|
|
24
|
+
timeout(number) {
|
|
25
|
+
if (!Number.isInteger(number) || number < 0) {
|
|
26
|
+
throw new Error('assert.timeout() expects a positive integer.');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.test.timeout = number;
|
|
30
|
+
}
|
|
31
|
+
step(message) {
|
|
32
|
+
let assertionMessage = message;
|
|
33
|
+
let result = !!message;
|
|
17
34
|
|
|
18
|
-
this.
|
|
35
|
+
this.test.steps.push(message);
|
|
19
36
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
37
|
+
if (typeof message === 'undefined' || message === '') {
|
|
38
|
+
assertionMessage = 'You must provide a message to assert.step';
|
|
39
|
+
} else if (typeof message !== 'string') {
|
|
40
|
+
assertionMessage = 'You must provide a string value to assert.step';
|
|
41
|
+
result = false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.pushResult({
|
|
45
|
+
result,
|
|
46
|
+
message: assertionMessage
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
verifySteps(steps, message = 'Verify steps failed!') {
|
|
50
|
+
this.deepEqual(this.test.steps, steps, message);
|
|
51
|
+
this.test.steps.length = 0;
|
|
52
|
+
}
|
|
53
|
+
expect(number) {
|
|
54
|
+
if (!Number.isInteger(number) || number < 0) {
|
|
55
|
+
throw new Error('assert.expect() expects a positive integer.');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.test.expectedAssertionCount = number;
|
|
59
|
+
}
|
|
25
60
|
async() {
|
|
26
|
-
|
|
27
|
-
|
|
61
|
+
let resolveFn;
|
|
62
|
+
let done = new Promise(resolve => { resolveFn = resolve; });
|
|
63
|
+
|
|
64
|
+
this.#asyncOps.push(done);
|
|
65
|
+
|
|
66
|
+
return () => { resolveFn(); };
|
|
67
|
+
}
|
|
68
|
+
async waitForAsyncOps() {
|
|
69
|
+
return Promise.all(this.#asyncOps);
|
|
70
|
+
}
|
|
28
71
|
pushResult(resultInfo = {}) {
|
|
29
|
-
|
|
72
|
+
this._incrementAssertionCount();
|
|
73
|
+
if (!resultInfo.result) {
|
|
30
74
|
throw new AssertionError({
|
|
31
75
|
actual: resultInfo.actual,
|
|
32
76
|
expected: resultInfo.expected,
|
|
33
|
-
message:
|
|
77
|
+
message: resultInfo.message || 'Custom assertion failed!',
|
|
34
78
|
stackStartFn: this.pushResult,
|
|
35
79
|
});
|
|
36
80
|
}
|
|
37
|
-
|
|
81
|
+
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
38
84
|
ok(state, message) {
|
|
85
|
+
this._incrementAssertionCount();
|
|
39
86
|
if (!state) {
|
|
40
87
|
throw new AssertionError({
|
|
41
88
|
actual: state,
|
|
@@ -44,8 +91,9 @@ export default {
|
|
|
44
91
|
stackStartFn: this.ok,
|
|
45
92
|
});
|
|
46
93
|
}
|
|
47
|
-
}
|
|
94
|
+
}
|
|
48
95
|
notOk(state, message) {
|
|
96
|
+
this._incrementAssertionCount();
|
|
49
97
|
if (state) {
|
|
50
98
|
throw new AssertionError({
|
|
51
99
|
actual: state,
|
|
@@ -54,8 +102,9 @@ export default {
|
|
|
54
102
|
stackStartFn: this.notOk,
|
|
55
103
|
});
|
|
56
104
|
}
|
|
57
|
-
}
|
|
105
|
+
}
|
|
58
106
|
true(state, message) {
|
|
107
|
+
this._incrementAssertionCount();
|
|
59
108
|
if (state !== true) {
|
|
60
109
|
throw new AssertionError({
|
|
61
110
|
actual: state,
|
|
@@ -64,8 +113,9 @@ export default {
|
|
|
64
113
|
stackStartFn: this.true,
|
|
65
114
|
});
|
|
66
115
|
}
|
|
67
|
-
}
|
|
116
|
+
}
|
|
68
117
|
false(state, message) {
|
|
118
|
+
this._incrementAssertionCount();
|
|
69
119
|
if (state !== false) {
|
|
70
120
|
throw new AssertionError({
|
|
71
121
|
actual: state,
|
|
@@ -74,8 +124,9 @@ export default {
|
|
|
74
124
|
stackStartFn: this.false,
|
|
75
125
|
});
|
|
76
126
|
}
|
|
77
|
-
}
|
|
127
|
+
}
|
|
78
128
|
equal(actual, expected, message) {
|
|
129
|
+
this._incrementAssertionCount();
|
|
79
130
|
if (actual != expected) {
|
|
80
131
|
throw new AssertionError({
|
|
81
132
|
actual,
|
|
@@ -85,8 +136,9 @@ export default {
|
|
|
85
136
|
stackStartFn: this.equal,
|
|
86
137
|
});
|
|
87
138
|
}
|
|
88
|
-
}
|
|
139
|
+
}
|
|
89
140
|
notEqual(actual, expected, message) {
|
|
141
|
+
this._incrementAssertionCount();
|
|
90
142
|
if (actual == expected) {
|
|
91
143
|
throw new AssertionError({
|
|
92
144
|
actual,
|
|
@@ -96,8 +148,9 @@ export default {
|
|
|
96
148
|
stackStartFn: this.notEqual,
|
|
97
149
|
});
|
|
98
150
|
}
|
|
99
|
-
}
|
|
151
|
+
}
|
|
100
152
|
propEqual(actual, expected, message) {
|
|
153
|
+
this._incrementAssertionCount();
|
|
101
154
|
let targetActual = objectValues(actual);
|
|
102
155
|
let targetExpected = objectValues(expected);
|
|
103
156
|
if (!QUnit.equiv(targetActual, targetExpected)) {
|
|
@@ -108,8 +161,9 @@ export default {
|
|
|
108
161
|
stackStartFn: this.propEqual,
|
|
109
162
|
});
|
|
110
163
|
}
|
|
111
|
-
}
|
|
164
|
+
}
|
|
112
165
|
notPropEqual(actual, expected, message) {
|
|
166
|
+
this._incrementAssertionCount();
|
|
113
167
|
let targetActual = objectValues(actual);
|
|
114
168
|
let targetExpected = objectValues(expected);
|
|
115
169
|
if (QUnit.equiv(targetActual, targetExpected)) {
|
|
@@ -120,8 +174,9 @@ export default {
|
|
|
120
174
|
stackStartFn: this.notPropEqual,
|
|
121
175
|
});
|
|
122
176
|
}
|
|
123
|
-
}
|
|
177
|
+
}
|
|
124
178
|
propContains(actual, expected, message) {
|
|
179
|
+
this._incrementAssertionCount();
|
|
125
180
|
let targetActual = objectValuesSubset(actual, expected);
|
|
126
181
|
let targetExpected = objectValues(expected, false);
|
|
127
182
|
if (!QUnit.equiv(targetActual, targetExpected)) {
|
|
@@ -132,8 +187,9 @@ export default {
|
|
|
132
187
|
stackStartFn: this.propContains,
|
|
133
188
|
});
|
|
134
189
|
}
|
|
135
|
-
}
|
|
190
|
+
}
|
|
136
191
|
notPropContains(actual, expected, message) {
|
|
192
|
+
this._incrementAssertionCount();
|
|
137
193
|
let targetActual = objectValuesSubset(actual, expected);
|
|
138
194
|
let targetExpected = objectValues(expected);
|
|
139
195
|
if (QUnit.equiv(targetActual, targetExpected)) {
|
|
@@ -144,8 +200,9 @@ export default {
|
|
|
144
200
|
stackStartFn: this.notPropContains,
|
|
145
201
|
});
|
|
146
202
|
}
|
|
147
|
-
}
|
|
203
|
+
}
|
|
148
204
|
deepEqual(actual, expected, message) {
|
|
205
|
+
this._incrementAssertionCount();
|
|
149
206
|
if (!QUnit.equiv(actual, expected)) {
|
|
150
207
|
throw new AssertionError({
|
|
151
208
|
actual,
|
|
@@ -155,8 +212,9 @@ export default {
|
|
|
155
212
|
stackStartFn: this.deepEqual,
|
|
156
213
|
});
|
|
157
214
|
}
|
|
158
|
-
}
|
|
215
|
+
}
|
|
159
216
|
notDeepEqual(actual, expected, message) {
|
|
217
|
+
this._incrementAssertionCount();
|
|
160
218
|
if (QUnit.equiv(actual, expected)) {
|
|
161
219
|
throw new AssertionError({
|
|
162
220
|
actual,
|
|
@@ -166,8 +224,9 @@ export default {
|
|
|
166
224
|
stackStartFn: this.notDeepEqual,
|
|
167
225
|
});
|
|
168
226
|
}
|
|
169
|
-
}
|
|
227
|
+
}
|
|
170
228
|
strictEqual(actual, expected, message) {
|
|
229
|
+
this._incrementAssertionCount();
|
|
171
230
|
if (actual !== expected) {
|
|
172
231
|
throw new AssertionError({
|
|
173
232
|
actual,
|
|
@@ -177,8 +236,9 @@ export default {
|
|
|
177
236
|
stackStartFn: this.strictEqual,
|
|
178
237
|
});
|
|
179
238
|
}
|
|
180
|
-
}
|
|
239
|
+
}
|
|
181
240
|
notStrictEqual(actual, expected, message) {
|
|
241
|
+
this._incrementAssertionCount();
|
|
182
242
|
if (actual === expected) {
|
|
183
243
|
throw new AssertionError({
|
|
184
244
|
actual,
|
|
@@ -188,8 +248,9 @@ export default {
|
|
|
188
248
|
stackStartFn: this.notStrictEqual,
|
|
189
249
|
});
|
|
190
250
|
}
|
|
191
|
-
}
|
|
251
|
+
}
|
|
192
252
|
throws(blockFn, expectedInput, assertionMessage) {
|
|
253
|
+
this?._incrementAssertionCount();
|
|
193
254
|
let [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, 'rejects');
|
|
194
255
|
if (typeof blockFn !== 'function') {
|
|
195
256
|
throw new AssertionError({
|
|
@@ -222,8 +283,9 @@ export default {
|
|
|
222
283
|
message: 'Function passed to `assert.throws` did not throw an exception!',
|
|
223
284
|
stackStartFn: this.throws,
|
|
224
285
|
});
|
|
225
|
-
}
|
|
286
|
+
}
|
|
226
287
|
async rejects(promise, expectedInput, assertionMessage) {
|
|
288
|
+
this._incrementAssertionCount();
|
|
227
289
|
let [expected, message] = validateExpectedExceptionArgs(expectedInput, assertionMessage, 'rejects');
|
|
228
290
|
let then = promise && promise.then;
|
|
229
291
|
if (typeof then !== 'function') {
|
package/shims/node/index.js
CHANGED
|
@@ -1,75 +1,237 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { describe, it, before as beforeAll, after as afterAll } from 'node:test';
|
|
2
|
+
import Assert from './assert.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// NOTE: node.js beforeEach & afterEach is buggy because the TestContext it has is NOT correct reference when called, it gets the last context
|
|
5
|
+
// NOTE: QUnit expect() logic is buggy in nested modules
|
|
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
|
+
|
|
8
|
+
class TestContext {
|
|
9
|
+
name;
|
|
10
|
+
|
|
11
|
+
#module;
|
|
12
|
+
get module() {
|
|
13
|
+
return this.#module;
|
|
14
|
+
}
|
|
15
|
+
set module(value) {
|
|
16
|
+
this.#module = value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#assert;
|
|
20
|
+
get assert() {
|
|
21
|
+
return this.#assert;
|
|
22
|
+
}
|
|
23
|
+
set assert(value) {
|
|
24
|
+
this.#assert = value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#timeout;
|
|
28
|
+
get timeout() {
|
|
29
|
+
return this.#timeout;
|
|
30
|
+
}
|
|
31
|
+
set timeout(value) {
|
|
32
|
+
this.#timeout = value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#steps = [];
|
|
36
|
+
get steps() {
|
|
37
|
+
return this.#steps;
|
|
38
|
+
}
|
|
39
|
+
set steps(value) {
|
|
40
|
+
this.#steps = value;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#expectedAssertionCount;
|
|
44
|
+
get expectedAssertionCount() {
|
|
45
|
+
return this.#expectedAssertionCount;
|
|
46
|
+
}
|
|
47
|
+
set expectedAssertionCount(value) {
|
|
48
|
+
this.#expectedAssertionCount = value;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
#totalExecutedAssertions = 0;
|
|
52
|
+
get totalExecutedAssertions() {
|
|
53
|
+
return this.#totalExecutedAssertions;
|
|
54
|
+
}
|
|
55
|
+
set totalExecutedAssertions(value) {
|
|
56
|
+
this.#totalExecutedAssertions = value;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
constructor(name, moduleContext) {
|
|
60
|
+
if (moduleContext) {
|
|
61
|
+
this.name = `${moduleContext.name} | ${name}`;
|
|
62
|
+
this.module = moduleContext;
|
|
63
|
+
this.module.tests.push(this);
|
|
64
|
+
this.assert = new Assert(moduleContext, this);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
finish() {
|
|
69
|
+
if (this.totalExecutedAssertions === 0) {
|
|
70
|
+
this.assert.pushResult({
|
|
71
|
+
result: false,
|
|
72
|
+
actual: this.totalExecutedAssertions,
|
|
73
|
+
expected: '> 0',
|
|
74
|
+
message: `Expected at least one assertion to be run for test: ${this.name}`,
|
|
75
|
+
});
|
|
76
|
+
} else if (this.steps.length > 0) {
|
|
77
|
+
this.assert.pushResult({
|
|
78
|
+
result: false,
|
|
79
|
+
actual: this.steps,
|
|
80
|
+
expected: [],
|
|
81
|
+
message: `Expected assert.verifySteps() to be called before end of test after using assert.step(). Unverified steps: ${this.steps.join(', ')}`,
|
|
82
|
+
});
|
|
83
|
+
} else if (this.expectedAssertionCount && this.expectedAssertionCount !== this.totalExecutedAssertions) {
|
|
84
|
+
this.assert.pushResult({
|
|
85
|
+
result: false,
|
|
86
|
+
actual: this.totalExecutedAssertions,
|
|
87
|
+
expected: this.expectedAssertionCount,
|
|
88
|
+
message: `Expected ${this.expectedAssertionCount} assertions, but ${this.totalExecutedAssertions} were run for test: ${this.name}`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
class ModuleContext extends TestContext {
|
|
95
|
+
static currentModuleChain = [];
|
|
96
|
+
|
|
97
|
+
static get lastModule() {
|
|
98
|
+
return this.currentModuleChain[this.currentModuleChain.length - 1];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
#tests = [];
|
|
102
|
+
get tests() {
|
|
103
|
+
return this.#tests;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
#beforeEachHooks = [];
|
|
107
|
+
get beforeEachHooks() {
|
|
108
|
+
return this.#beforeEachHooks;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
#afterEachHooks = [];
|
|
112
|
+
get afterEachHooks() {
|
|
113
|
+
return this.#afterEachHooks;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
#moduleChain = [];
|
|
117
|
+
get moduleChain() {
|
|
118
|
+
return this.#moduleChain;
|
|
119
|
+
}
|
|
120
|
+
set moduleChain(value) {
|
|
121
|
+
this.#moduleChain = value;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
constructor(name) {
|
|
125
|
+
super(name);
|
|
126
|
+
|
|
127
|
+
let parentModule = ModuleContext.currentModuleChain[ModuleContext.currentModuleChain.length - 1];
|
|
128
|
+
|
|
129
|
+
ModuleContext.currentModuleChain.push(this);
|
|
130
|
+
|
|
131
|
+
this.moduleChain = ModuleContext.currentModuleChain.slice(0);
|
|
132
|
+
this.name = parentModule ? `${parentModule.name} > ${name}` : name;
|
|
133
|
+
this.assert = new Assert(this);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const module = (moduleName, runtimeOptions, moduleContent) => {
|
|
5
138
|
let targetRuntimeOptions = moduleContent ? runtimeOptions : {};
|
|
6
139
|
let targetModuleContent = moduleContent ? moduleContent : runtimeOptions;
|
|
140
|
+
let moduleContext = new ModuleContext(moduleName);
|
|
141
|
+
|
|
142
|
+
return describe(moduleName, { concurrency: true, ...targetRuntimeOptions }, async function () {
|
|
143
|
+
let beforeHooks = [];
|
|
144
|
+
let afterHooks = [];
|
|
145
|
+
|
|
146
|
+
beforeAll(async function () {
|
|
147
|
+
Object.assign(moduleContext, moduleContext.moduleChain.reduce((result, module) => {
|
|
148
|
+
const { name, ...moduleWithoutName } = module;
|
|
149
|
+
|
|
150
|
+
return Object.assign(result, moduleWithoutName, {
|
|
151
|
+
steps: result.steps.concat(module.steps),
|
|
152
|
+
expectedAssertionCount: module.expectedAssertionCount
|
|
153
|
+
? module.expectedAssertionCount
|
|
154
|
+
: result.expectedAssertionCount
|
|
155
|
+
});
|
|
156
|
+
}, { steps: [], expectedAssertionCount: undefined }));
|
|
157
|
+
|
|
158
|
+
for (let hook of beforeHooks) {
|
|
159
|
+
await hook.call(moduleContext, moduleContext.assert);
|
|
160
|
+
}
|
|
7
161
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
162
|
+
moduleContext.tests.forEach((testContext) => {
|
|
163
|
+
const { name, ...moduleContextWithoutName } = moduleContext;
|
|
164
|
+
|
|
165
|
+
Object.assign(testContext, moduleContextWithoutName, {
|
|
166
|
+
steps: moduleContext.steps,
|
|
167
|
+
totalExecutedAssertions: moduleContext.totalExecutedAssertions,
|
|
168
|
+
expectedAssertionCount: moduleContext.expectedAssertionCount,
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
afterAll(async () => {
|
|
173
|
+
for (const assert of moduleContext.tests.map(testContext => testContext.assert)) {
|
|
174
|
+
await assert.waitForAsyncOps();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
let targetContext = moduleContext.tests[moduleContext.tests.length - 1];
|
|
178
|
+
for (let j = afterHooks.length - 1; j >= 0; j--) {
|
|
179
|
+
await afterHooks[j].call(targetContext, targetContext.assert);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
moduleContext.tests.forEach(testContext => testContext.finish());
|
|
12
183
|
});
|
|
184
|
+
|
|
185
|
+
targetModuleContent.call(moduleContext, {
|
|
186
|
+
before(beforeFn) {
|
|
187
|
+
return beforeHooks.push(beforeFn);
|
|
188
|
+
},
|
|
189
|
+
beforeEach(beforeEachFn) {
|
|
190
|
+
return moduleContext.beforeEachHooks.push(beforeEachFn);
|
|
191
|
+
},
|
|
192
|
+
afterEach(afterEachFn) {
|
|
193
|
+
return moduleContext.afterEachHooks.push(afterEachFn);
|
|
194
|
+
},
|
|
195
|
+
after(afterFn) {
|
|
196
|
+
return afterHooks.push(afterFn);
|
|
197
|
+
}
|
|
198
|
+
}, { moduleName, options: runtimeOptions });
|
|
199
|
+
|
|
200
|
+
ModuleContext.currentModuleChain.pop();
|
|
13
201
|
});
|
|
14
202
|
}
|
|
15
203
|
|
|
16
|
-
export const test =
|
|
204
|
+
export const test = (testName, runtimeOptions, testContent) => {
|
|
205
|
+
let moduleContext = ModuleContext.lastModule;
|
|
206
|
+
if (!moduleContext) {
|
|
207
|
+
throw new Error(`Test '${testName}' called outside of module context.`);
|
|
208
|
+
}
|
|
209
|
+
|
|
17
210
|
let targetRuntimeOptions = testContent ? runtimeOptions : {};
|
|
18
211
|
let targetTestContent = testContent ? testContent : runtimeOptions;
|
|
212
|
+
let context = new TestContext(testName, moduleContext);
|
|
19
213
|
|
|
20
|
-
return it(testName,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
214
|
+
return it(testName, { concurrency: true, ...targetRuntimeOptions }, async function () {
|
|
215
|
+
let result;
|
|
216
|
+
for (let module of context.module.moduleChain) {
|
|
217
|
+
for (let hook of module.beforeEachHooks) {
|
|
218
|
+
await hook.call(context, context.assert);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
result = await targetTestContent.call(context, context.assert, { testName, options: runtimeOptions });
|
|
24
223
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
224
|
+
await context.assert.waitForAsyncOps();
|
|
225
|
+
|
|
226
|
+
for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
|
|
227
|
+
let module = context.module.moduleChain[i];
|
|
228
|
+
for (let j = module.afterEachHooks.length - 1; j >= 0; j--) {
|
|
229
|
+
await module.afterEachHooks[j].call(context, context.assert);
|
|
230
|
+
}
|
|
29
231
|
}
|
|
30
|
-
}
|
|
31
232
|
|
|
32
|
-
|
|
233
|
+
return result;
|
|
234
|
+
});
|
|
33
235
|
}
|
|
34
236
|
|
|
35
237
|
export default { module, test, config: {} };
|
|
36
|
-
|
|
37
|
-
// NOTE: later maybe expose these as well:
|
|
38
|
-
|
|
39
|
-
// import QUnit from './vendor/qunit.js';
|
|
40
|
-
|
|
41
|
-
// QUnit.config.autostart = false;
|
|
42
|
-
|
|
43
|
-
// export const isLocal = QUnit.isLocal;
|
|
44
|
-
// export const on = QUnit.on;
|
|
45
|
-
// export const test = QUnit.test;
|
|
46
|
-
// export const skip = QUnit.skip;
|
|
47
|
-
// export const start = QUnit.start;
|
|
48
|
-
// export const is = QUnit.is;
|
|
49
|
-
// export const extend = QUnit.extend;
|
|
50
|
-
// export const stack = QUnit.stack;
|
|
51
|
-
// export const onUnhandledRejection = QUnit.onUnhandledRejection;
|
|
52
|
-
// export const assert = QUnit.assert;
|
|
53
|
-
// export const dump = QUnit.dump;
|
|
54
|
-
// export const done = QUnit.done;
|
|
55
|
-
// export const testStart = QUnit.testStart;
|
|
56
|
-
// export const moduleStart = QUnit.moduleStart;
|
|
57
|
-
// export const version = QUnit.version;
|
|
58
|
-
// export const module = QUnit.module;
|
|
59
|
-
// export const todo = QUnit.todo;
|
|
60
|
-
// export const only = QUnit.only;
|
|
61
|
-
// export const config = QUnit.config;
|
|
62
|
-
// export const objectType = QUnit.objectType;
|
|
63
|
-
// export const load = QUnit.load;
|
|
64
|
-
// export const onError = QUnit.onError;
|
|
65
|
-
// export const pushFailure = QUnit.pushFailure;
|
|
66
|
-
// export const equiv = QUnit.equiv;
|
|
67
|
-
// export const begin = QUnit.begin;
|
|
68
|
-
// export const log = QUnit.log;
|
|
69
|
-
// export const testDone = QUnit.testDone;
|
|
70
|
-
// export const moduleDone = QUnit.moduleDone;
|
|
71
|
-
// export const diff = QUnit.diff;
|
|
72
|
-
|
|
73
|
-
// export default Object.assign(QUnit, {
|
|
74
|
-
// QUnitxVersion: '0.0.1'
|
|
75
|
-
// });
|