qunitx 0.9.0 → 0.9.1
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 +30 -2
- package/shims/deno/index.js +21 -232
- package/shims/deno/module.js +71 -0
- package/shims/deno/test.js +37 -0
- package/shims/node/index.js +17 -232
- package/shims/node/module.js +71 -0
- package/shims/node/test.js +37 -0
- package/shims/{node → shared}/assert.js +34 -38
- package/shims/shared/module-context.js +47 -0
- package/shims/shared/test-context.js +102 -0
- package/shims/deno/assert.js +0 -333
package/package.json
CHANGED
|
@@ -1,14 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qunitx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.1",
|
|
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",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"test",
|
|
10
|
-
"test framework",
|
|
11
10
|
"testing",
|
|
11
|
+
"automated testing",
|
|
12
|
+
"test framework",
|
|
13
|
+
"ui testing",
|
|
14
|
+
"e2e",
|
|
15
|
+
"e2e testing",
|
|
16
|
+
"0 dependencies",
|
|
17
|
+
"zero dependencies",
|
|
18
|
+
"no dependencies",
|
|
19
|
+
"universal testing",
|
|
20
|
+
"universal test framework",
|
|
21
|
+
"universal test",
|
|
22
|
+
"universal",
|
|
23
|
+
"cross platform",
|
|
24
|
+
"cross platform testing",
|
|
25
|
+
"cross platform test framework",
|
|
26
|
+
"cross platform test",
|
|
27
|
+
"unit testing",
|
|
28
|
+
"unit test",
|
|
29
|
+
"unit",
|
|
30
|
+
"integration testing",
|
|
31
|
+
"integration test",
|
|
32
|
+
"integration",
|
|
33
|
+
"qa",
|
|
34
|
+
"quality assurance",
|
|
35
|
+
"tdd",
|
|
36
|
+
"bdd",
|
|
37
|
+
"assert",
|
|
38
|
+
"frontend",
|
|
39
|
+
"backend",
|
|
12
40
|
"qunit",
|
|
13
41
|
"node",
|
|
14
42
|
"deno",
|
package/shims/deno/index.js
CHANGED
|
@@ -1,238 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
class
|
|
10
|
-
|
|
11
|
-
|
|
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);
|
|
1
|
+
import { AssertionError as DenoAssertionError } from "https://deno.land/std@0.192.0/testing/asserts.ts";
|
|
2
|
+
import '../../vendor/qunit.js';
|
|
3
|
+
import Assert from '../shared/assert.js';
|
|
4
|
+
import ModuleContext from '../shared/module-context.js';
|
|
5
|
+
import TestContext from '../shared/test-context.js';
|
|
6
|
+
import Module from './module.js';
|
|
7
|
+
import Test from './test.js';
|
|
8
|
+
|
|
9
|
+
export class AssertionError extends DenoAssertionError {
|
|
10
|
+
constructor(object) {
|
|
11
|
+
super(object.message);
|
|
135
12
|
}
|
|
136
13
|
}
|
|
137
14
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
}
|
|
15
|
+
Assert.QUnit = QUnit;
|
|
16
|
+
Assert.AssertionError = AssertionError;
|
|
17
|
+
ModuleContext.Assert = Assert;
|
|
18
|
+
TestContext.Assert = Assert;
|
|
162
19
|
|
|
163
|
-
|
|
164
|
-
|
|
20
|
+
Object.freeze(Assert);
|
|
21
|
+
Object.freeze(ModuleContext);
|
|
22
|
+
Object.freeze(TestContext);
|
|
165
23
|
|
|
166
|
-
|
|
167
|
-
|
|
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());
|
|
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();
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
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 : {};
|
|
212
|
-
let targetTestContent = testContent ? testContent : runtimeOptions;
|
|
213
|
-
let context = new TestContext(testName, moduleContext);
|
|
214
|
-
|
|
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
|
-
}
|
|
222
|
-
|
|
223
|
-
result = await targetTestContent.call(context, context.assert, { testName, options: runtimeOptions });
|
|
224
|
-
|
|
225
|
-
await context.assert.waitForAsyncOps();
|
|
226
|
-
|
|
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
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
return result;
|
|
235
|
-
});
|
|
236
|
-
}
|
|
24
|
+
export const module = Module;
|
|
25
|
+
export const test = Test;
|
|
237
26
|
|
|
238
|
-
export default { module, test, config: {} };
|
|
27
|
+
export default { AssertionError: Assert.AssertionError, module, test, config: {} };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, beforeAll, afterAll } from "https://deno.land/std@0.192.0/testing/bdd.ts";
|
|
2
|
+
import ModuleContext from '../shared/module-context.js';
|
|
3
|
+
|
|
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
|
+
export default function module(moduleName, runtimeOptions, moduleContent) {
|
|
9
|
+
let targetRuntimeOptions = moduleContent ? runtimeOptions : {};
|
|
10
|
+
let targetModuleContent = moduleContent ? moduleContent : runtimeOptions;
|
|
11
|
+
let moduleContext = new ModuleContext(moduleName);
|
|
12
|
+
|
|
13
|
+
return describe(moduleName, { concurrency: true, ...targetRuntimeOptions }, async function () {
|
|
14
|
+
let beforeHooks = [];
|
|
15
|
+
let afterHooks = [];
|
|
16
|
+
|
|
17
|
+
beforeAll(async function () {
|
|
18
|
+
Object.assign(moduleContext.context, moduleContext.moduleChain.reduce((result, module) => {
|
|
19
|
+
return Object.assign(result, module.context, {
|
|
20
|
+
steps: result.steps.concat(module.context.steps),
|
|
21
|
+
expectedAssertionCount: module.context.expectedAssertionCount
|
|
22
|
+
? module.context.expectedAssertionCount
|
|
23
|
+
: result.expectedAssertionCount
|
|
24
|
+
});
|
|
25
|
+
}, { steps: [], expectedAssertionCount: undefined }));
|
|
26
|
+
|
|
27
|
+
for (let hook of beforeHooks) {
|
|
28
|
+
await hook.call(moduleContext.context, moduleContext.assert);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
for (let i = 0, len = moduleContext.tests.length; i < len; i++) {
|
|
32
|
+
Object.assign(moduleContext.tests[i], moduleContext.context, {
|
|
33
|
+
steps: moduleContext.context.steps,
|
|
34
|
+
totalExecutedAssertions: moduleContext.context.totalExecutedAssertions,
|
|
35
|
+
expectedAssertionCount: moduleContext.context.expectedAssertionCount,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
afterAll(async () => {
|
|
40
|
+
for (const assert of moduleContext.tests.map(testContext => testContext.assert)) {
|
|
41
|
+
await assert.waitForAsyncOps();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let targetContext = moduleContext.tests[moduleContext.tests.length - 1];
|
|
45
|
+
for (let j = afterHooks.length - 1; j >= 0; j--) {
|
|
46
|
+
await afterHooks[j].call(targetContext, targetContext.assert);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (let i = 0, len = moduleContext.tests.length; i < len; i++) {
|
|
50
|
+
moduleContext.tests[i].finish();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
targetModuleContent.call(moduleContext.context, {
|
|
55
|
+
before(beforeFn) {
|
|
56
|
+
beforeHooks[beforeHooks.length] = beforeFn;
|
|
57
|
+
},
|
|
58
|
+
beforeEach(beforeEachFn) {
|
|
59
|
+
moduleContext.beforeEachHooks[moduleContext.beforeEachHooks.length] = beforeEachFn;
|
|
60
|
+
},
|
|
61
|
+
afterEach(afterEachFn) {
|
|
62
|
+
moduleContext.afterEachHooks[moduleContext.afterEachHooks.length] = afterEachFn;
|
|
63
|
+
},
|
|
64
|
+
after(afterFn) {
|
|
65
|
+
afterHooks[afterHooks.length] = afterFn;
|
|
66
|
+
}
|
|
67
|
+
}, { moduleName, options: runtimeOptions });
|
|
68
|
+
|
|
69
|
+
ModuleContext.currentModuleChain.pop();
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { it } from "https://deno.land/std@0.192.0/testing/bdd.ts";
|
|
2
|
+
import TestContext from '../shared/test-context.js';
|
|
3
|
+
import ModuleContext from '../shared/module-context.js';
|
|
4
|
+
|
|
5
|
+
export default function test(testName, runtimeOptions, testContent) {
|
|
6
|
+
let moduleContext = ModuleContext.lastModule;
|
|
7
|
+
if (!moduleContext) {
|
|
8
|
+
throw new Error(`Test '${testName}' called outside of module context.`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let targetRuntimeOptions = testContent ? runtimeOptions : {};
|
|
12
|
+
let targetTestContent = testContent ? testContent : runtimeOptions;
|
|
13
|
+
let context = new TestContext(testName, moduleContext);
|
|
14
|
+
|
|
15
|
+
return it(testName, { concurrency: true, ...targetRuntimeOptions }, async function () {
|
|
16
|
+
let result;
|
|
17
|
+
for (let module of context.module.moduleChain) {
|
|
18
|
+
for (let hook of module.beforeEachHooks) {
|
|
19
|
+
await hook.call(context, context.assert);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
result = await targetTestContent.call(context, context.assert, { testName, options: runtimeOptions });
|
|
24
|
+
|
|
25
|
+
await context.assert.waitForAsyncOps();
|
|
26
|
+
|
|
27
|
+
for (let i = context.module.moduleChain.length - 1; i >= 0; i--) {
|
|
28
|
+
let module = context.module.moduleChain[i];
|
|
29
|
+
for (let j = module.afterEachHooks.length - 1; j >= 0; j--) {
|
|
30
|
+
await module.afterEachHooks[j].call(context, context.assert);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return result;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
package/shims/node/index.js
CHANGED
|
@@ -1,237 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { AssertionError } from 'node:assert';
|
|
2
|
+
import QUnit from '../../vendor/qunit.js';
|
|
3
|
+
import Assert from '../shared/assert.js';
|
|
4
|
+
import ModuleContext from '../shared/module-context.js';
|
|
5
|
+
import TestContext from '../shared/test-context.js';
|
|
6
|
+
import Module from './module.js';
|
|
7
|
+
import Test from './test.js';
|
|
3
8
|
|
|
4
|
-
|
|
5
|
-
|
|
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)
|
|
9
|
+
Assert.QUnit = QUnit;
|
|
10
|
+
Assert.AssertionError = AssertionError;
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
ModuleContext.Assert = Assert;
|
|
13
|
+
TestContext.Assert = Assert;
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
set module(value) {
|
|
16
|
-
this.#module = value;
|
|
17
|
-
}
|
|
15
|
+
Object.freeze(Assert);
|
|
16
|
+
Object.freeze(ModuleContext);
|
|
17
|
+
Object.freeze(TestContext);
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return this.#assert;
|
|
22
|
-
}
|
|
23
|
-
set assert(value) {
|
|
24
|
-
this.#assert = value;
|
|
25
|
-
}
|
|
19
|
+
export const module = Module;
|
|
20
|
+
export const test = Test;
|
|
26
21
|
|
|
27
|
-
|
|
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) => {
|
|
138
|
-
let targetRuntimeOptions = moduleContent ? runtimeOptions : {};
|
|
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
|
-
}
|
|
161
|
-
|
|
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());
|
|
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();
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
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
|
-
|
|
210
|
-
let targetRuntimeOptions = testContent ? runtimeOptions : {};
|
|
211
|
-
let targetTestContent = testContent ? testContent : runtimeOptions;
|
|
212
|
-
let context = new TestContext(testName, moduleContext);
|
|
213
|
-
|
|
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 });
|
|
223
|
-
|
|
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
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return result;
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
export default { module, test, config: {} };
|
|
22
|
+
export default { AssertionError: Assert.AssertionError, module, test, config: {} };
|