nole 2.2.2 → 3.1.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/.github/workflows/ci.yaml +34 -0
- package/LICENSE.md +21 -0
- package/README.md +474 -388
- package/bin/nole.js +145 -111
- package/dist/const.d.ts +8 -0
- package/dist/const.d.ts.map +1 -0
- package/dist/const.js +9 -0
- package/dist/core.d.ts +22 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +56 -0
- package/dist/dynamic.d.ts +5 -1
- package/dist/dynamic.d.ts.map +1 -1
- package/dist/dynamic.js +35 -1
- package/dist/handle/after-each-hooks.d.ts +3 -0
- package/dist/handle/after-each-hooks.d.ts.map +1 -0
- package/dist/handle/after-each-hooks.js +26 -0
- package/dist/handle/after-hooks.d.ts +3 -0
- package/dist/handle/after-hooks.d.ts.map +1 -0
- package/dist/handle/after-hooks.js +24 -0
- package/dist/handle/before-each-hooks.d.ts +3 -0
- package/dist/handle/before-each-hooks.d.ts.map +1 -0
- package/dist/handle/before-each-hooks.js +26 -0
- package/dist/handle/before-hooks.d.ts +3 -0
- package/dist/handle/before-hooks.d.ts.map +1 -0
- package/dist/handle/before-hooks.js +34 -0
- package/dist/handle/cleanup-hooks.d.ts +3 -0
- package/dist/handle/cleanup-hooks.d.ts.map +1 -0
- package/dist/handle/cleanup-hooks.js +34 -0
- package/dist/handle/specs.d.ts +3 -0
- package/dist/handle/specs.d.ts.map +1 -0
- package/dist/handle/specs.js +50 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/pipeline.test.d.ts +7 -0
- package/dist/pipeline.test.d.ts.map +1 -0
- package/dist/pipeline.test.js +124 -0
- package/dist/run.d.ts +7 -6
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +166 -196
- package/dist/symbol.d.ts +2 -0
- package/dist/symbol.d.ts.map +1 -0
- package/dist/symbol.js +2 -0
- package/dist/test-wrap.d.ts +38 -0
- package/dist/test-wrap.d.ts.map +1 -0
- package/dist/test-wrap.js +30 -0
- package/dist/utils/executor.js +1 -1
- package/dist/utils/executor.test.d.ts +3 -1
- package/dist/utils/executor.test.d.ts.map +1 -1
- package/dist/utils/executor.test.js +3 -30
- package/dist/utils/time_difference.d.ts +9 -0
- package/dist/utils/time_difference.d.ts.map +1 -1
- package/dist/utils/time_difference.js +10 -1
- package/dist/utils/time_difference.test.d.ts +3 -1
- package/dist/utils/time_difference.test.d.ts.map +1 -1
- package/dist/utils/time_difference.test.js +5 -18
- package/dist/utils/time_factor.d.ts.map +1 -1
- package/dist/utils/time_factor.js +2 -3
- package/dist/utils/time_factor.test.d.ts +3 -1
- package/dist/utils/time_factor.test.d.ts.map +1 -1
- package/dist/utils/time_factor.test.js +3 -18
- package/package.json +58 -58
- package/tsconfig.json +18 -18
- package/dist/data.d.ts +0 -3
- package/dist/data.d.ts.map +0 -1
- package/dist/data.js +0 -9
- package/dist/data.js.map +0 -1
- package/dist/decorators.d.ts +0 -9
- package/dist/decorators.d.ts.map +0 -1
- package/dist/decorators.js +0 -118
- package/dist/decorators.js.map +0 -1
- package/dist/dynamic.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/run.js.map +0 -1
- package/dist/test.d.ts +0 -39
- package/dist/test.d.ts.map +0 -1
- package/dist/test.js +0 -25
- package/dist/test.js.map +0 -1
- package/dist/utils/executor.js.map +0 -1
- package/dist/utils/executor.test.js.map +0 -1
- package/dist/utils/time_difference.js.map +0 -1
- package/dist/utils/time_difference.test.js.map +0 -1
- package/dist/utils/time_factor.js.map +0 -1
- package/dist/utils/time_factor.test.js.map +0 -1
- package/src/data.ts +0 -13
- package/src/decorators.ts +0 -208
- package/src/dynamic.ts +0 -11
- package/src/index.ts +0 -13
- package/src/run.ts +0 -331
- package/src/test.ts +0 -47
- package/src/utils/executor.test.ts +0 -27
- package/src/utils/executor.ts +0 -22
- package/src/utils/time_difference.test.ts +0 -12
- package/src/utils/time_difference.ts +0 -26
- package/src/utils/time_factor.test.ts +0 -29
- package/src/utils/time_factor.ts +0 -35
- package/test/basic.test.ts +0 -24
- package/test/before.test.ts +0 -54
- package/test/clean-up.test.ts +0 -52
- package/test/dynamic-skip.test.ts +0 -8
- package/test/dynamic.test.ts +0 -13
- package/test/hook.test.ts +0 -27
- package/test/multi-dependency.test.ts +0 -45
- package/test/multiple-uppercased-chars.test.ts +0 -19
- package/test/skip-all.test.ts +0 -19
- package/test/tsconfig.json +0 -24
- package/test/turkish-chars.test.ts +0 -19
package/src/decorators.ts
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { HashMap } from "./data.js";
|
|
2
|
-
import { Test, HookType, ClassDefition } from "./test.js";
|
|
3
|
-
import camelcase from "camelcase";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Assignes method as test case
|
|
7
|
-
* @param timeout Timeout of case in milliseconds
|
|
8
|
-
*/
|
|
9
|
-
export function Spec(timeout: number = 5000): MethodDecorator {
|
|
10
|
-
return function (target, propertyKey) {
|
|
11
|
-
DeclareSpecForTestClass(target, <string>propertyKey, timeout);
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Assignes dependency for test class
|
|
17
|
-
* @param dependency a Test class that needed
|
|
18
|
-
*/
|
|
19
|
-
export function Dependency<T>(dependency: ClassDefition<T>): PropertyDecorator {
|
|
20
|
-
return function (target, propertyKey) {
|
|
21
|
-
DeclareDependencyForTestClass(target, <string>propertyKey, dependency);
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Assignes dependencies for test class
|
|
27
|
-
* @param dependencies a Test class array that needed
|
|
28
|
-
*/
|
|
29
|
-
export function Dependencies(
|
|
30
|
-
dependencies: (() => ClassDefition<any>[]) | ClassDefition<any>[]
|
|
31
|
-
): ClassDecorator {
|
|
32
|
-
return function (target) {
|
|
33
|
-
setImmediate(() => {
|
|
34
|
-
const value = isFunction(dependencies) ? dependencies() : dependencies;
|
|
35
|
-
|
|
36
|
-
for (const dependency of value) {
|
|
37
|
-
const propertyKey = validPropertyName(dependency.name);
|
|
38
|
-
|
|
39
|
-
DeclareDependencyForTestClass(
|
|
40
|
-
{ constructor: target },
|
|
41
|
-
propertyKey,
|
|
42
|
-
dependency
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Reverse dependencies for assuring execution order
|
|
51
|
-
* @param dependents a function that returns a Test class array
|
|
52
|
-
*/
|
|
53
|
-
export function Dependents(
|
|
54
|
-
dependents: (() => ClassDefition<any>[]) | ClassDefition<any>[]
|
|
55
|
-
): ClassDecorator {
|
|
56
|
-
return function (target) {
|
|
57
|
-
setImmediate(() => {
|
|
58
|
-
const value = isFunction(dependents) ? dependents() : dependents;
|
|
59
|
-
|
|
60
|
-
for (const dependent of value) {
|
|
61
|
-
const propertyKey = validPropertyName(target.name);
|
|
62
|
-
|
|
63
|
-
DeclareDependencyForTestClass(
|
|
64
|
-
{ constructor: dependent },
|
|
65
|
-
propertyKey,
|
|
66
|
-
target
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Creates hook for test case
|
|
75
|
-
* @param type Hook type
|
|
76
|
-
* @param timeout Timeout of case in milliseconds
|
|
77
|
-
*/
|
|
78
|
-
export function Hook(type: HookType, timeout: number = 5000): MethodDecorator {
|
|
79
|
-
return function (target, propertyKey) {
|
|
80
|
-
DeclareHookForTestClass(target, <string>propertyKey, type, timeout);
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Assigns test spec as skipped
|
|
86
|
-
* @param reason Why skipped
|
|
87
|
-
*/
|
|
88
|
-
export function Skip(reason?: string): MethodDecorator {
|
|
89
|
-
return function (target, propertyKey) {
|
|
90
|
-
DeclareAsSkipped(target, <string>propertyKey, reason ? reason : "");
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Assigns test spec as skipped
|
|
96
|
-
* @param reason Why skipped
|
|
97
|
-
*/
|
|
98
|
-
export function SkipClass(reason?: string): ClassDecorator {
|
|
99
|
-
return function (target) {
|
|
100
|
-
DeclareAsSkippedClass(target, reason ? reason : "");
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function GetTestInstanceOfTarget(target: any) {
|
|
105
|
-
let instance = HashMap().get(target);
|
|
106
|
-
if (!instance) {
|
|
107
|
-
HashMap().set(target, (instance = new Test(target)));
|
|
108
|
-
}
|
|
109
|
-
return instance;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function DeclareDependencyForTestClass(
|
|
113
|
-
protoOfTarget: any,
|
|
114
|
-
propertyKey: string,
|
|
115
|
-
dependency: any
|
|
116
|
-
) {
|
|
117
|
-
const target = protoOfTarget.constructor;
|
|
118
|
-
|
|
119
|
-
const test = GetTestInstanceOfTarget(target);
|
|
120
|
-
const depTest = GetTestInstanceOfTarget(dependency);
|
|
121
|
-
|
|
122
|
-
test.dependencies.push({ propertyKey, dependency: depTest });
|
|
123
|
-
depTest.dependents.push(test);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function DeclareSpecForTestClass(
|
|
127
|
-
protoOfTarget: any,
|
|
128
|
-
propertyKey: string,
|
|
129
|
-
timeout: number
|
|
130
|
-
) {
|
|
131
|
-
const target = protoOfTarget.constructor;
|
|
132
|
-
const test = GetTestInstanceOfTarget(target);
|
|
133
|
-
|
|
134
|
-
if (test.hooks.has(propertyKey)) {
|
|
135
|
-
throw new Error("@Hook cannot be used with @Spec! Test: ");
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (test.specs.has(propertyKey)) {
|
|
139
|
-
throw new Error("Multiple @Spec for a single method is prohibited");
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
test.specs.set(propertyKey, { timeout });
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function DeclareHookForTestClass(
|
|
146
|
-
protoOfTarget: any,
|
|
147
|
-
propertyKey: string,
|
|
148
|
-
hookType: HookType,
|
|
149
|
-
timeout: number
|
|
150
|
-
) {
|
|
151
|
-
const target = protoOfTarget.constructor;
|
|
152
|
-
const test = GetTestInstanceOfTarget(target);
|
|
153
|
-
|
|
154
|
-
if (test.specs.has(propertyKey)) {
|
|
155
|
-
throw new Error("@Hook cannot be used with @Spec");
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (test.hooks.has(propertyKey)) {
|
|
159
|
-
throw new Error("Multiple @Hook for a single method is prohibited");
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
test.hooks.set(propertyKey, { type: hookType, timeout });
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function DeclareAsSkipped(
|
|
166
|
-
protoOfTarget: any,
|
|
167
|
-
propertyKey: string,
|
|
168
|
-
reason: string
|
|
169
|
-
) {
|
|
170
|
-
const target = protoOfTarget.constructor;
|
|
171
|
-
const test = GetTestInstanceOfTarget(target);
|
|
172
|
-
|
|
173
|
-
if (test.skip.has(propertyKey)) {
|
|
174
|
-
const obj = test.skip.get(propertyKey)!;
|
|
175
|
-
|
|
176
|
-
if (reason) {
|
|
177
|
-
obj.reason = (obj.reason ? obj.reason + ", " : "") + reason;
|
|
178
|
-
}
|
|
179
|
-
} else {
|
|
180
|
-
test.skip.set(propertyKey, { reason });
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function DeclareAsSkippedClass(target: any, reason: string) {
|
|
185
|
-
const test = GetTestInstanceOfTarget(target);
|
|
186
|
-
|
|
187
|
-
test.skipClass = { reason };
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function validPropertyName(name: string) {
|
|
191
|
-
return camelcase(name, {
|
|
192
|
-
preserveConsecutiveUppercase:
|
|
193
|
-
process.env.NOLE_PRESERVE_CONSECUTIVE_UPPERCASE == undefined
|
|
194
|
-
? true
|
|
195
|
-
: process.env.NOLE_PRESERVE_CONSECUTIVE_UPPERCASE === "true",
|
|
196
|
-
|
|
197
|
-
pascalCase:
|
|
198
|
-
process.env.NOLE_PASCALCASE == undefined
|
|
199
|
-
? false
|
|
200
|
-
: process.env.NOLE_PASCALCASE === "true",
|
|
201
|
-
|
|
202
|
-
locale: "en-US",
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function isFunction(thing: any): thing is (...args: any[]) => void {
|
|
207
|
-
return typeof thing !== "object" && typeof thing === "function";
|
|
208
|
-
}
|
package/src/dynamic.ts
DELETED
package/src/index.ts
DELETED
package/src/run.ts
DELETED
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
import { HashMap } from "./data.js";
|
|
2
|
-
import { TimeDifference } from "./utils/time_difference.js";
|
|
3
|
-
import { TimeFactor } from "./utils/time_factor.js";
|
|
4
|
-
import * as clrs from "colors/safe.js";
|
|
5
|
-
import { Executor } from "./utils/executor.js";
|
|
6
|
-
import { HookType, Test } from "./test.js";
|
|
7
|
-
|
|
8
|
-
const colors = (clrs as any).default;
|
|
9
|
-
|
|
10
|
-
const OK_TEXT = colors.bold(colors.green(" (ok) "));
|
|
11
|
-
const SKIP_TEXT = colors.bold(colors.yellow(" (skip) "));
|
|
12
|
-
const DYNAMIC_SKIP_TEXT = colors.bold(colors.blue(" (dskip) "));
|
|
13
|
-
const FAILED_TEXT = colors.bold(colors.red(" (failed) "));
|
|
14
|
-
const HOOK_FAILED_TEXT = colors.bold(colors.red(" (hook failed) "));
|
|
15
|
-
|
|
16
|
-
interface Options {
|
|
17
|
-
log: Function;
|
|
18
|
-
orderDebug: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function ManualRun(options: Options) {
|
|
22
|
-
if (!options.log) {
|
|
23
|
-
options.log = console.log.bind(console);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const log = options.log;
|
|
27
|
-
|
|
28
|
-
return new Promise<void>(async (resolve, reject) => {
|
|
29
|
-
try {
|
|
30
|
-
let hashMap = new Map(HashMap());
|
|
31
|
-
|
|
32
|
-
if (!hashMap.size) {
|
|
33
|
-
log(`${FAILED_TEXT} no specs found`);
|
|
34
|
-
throw new Error("No specs found");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
while (hashMap.size) {
|
|
38
|
-
let test = PickNextTestFromHashMap(hashMap);
|
|
39
|
-
|
|
40
|
-
if (test) {
|
|
41
|
-
hashMap.delete(test.target);
|
|
42
|
-
CreateInstanceIfNotExists(test);
|
|
43
|
-
HandleDependencies(test);
|
|
44
|
-
|
|
45
|
-
await HandleBeforeHooks(test, options);
|
|
46
|
-
await HandleSpecs(test, options);
|
|
47
|
-
await HandleAfterHooks(test, options);
|
|
48
|
-
|
|
49
|
-
test.isFinished = true;
|
|
50
|
-
|
|
51
|
-
if (test.dependents.length == 0) {
|
|
52
|
-
await HandleCleanUp(test, options);
|
|
53
|
-
}
|
|
54
|
-
} else {
|
|
55
|
-
DependencyLock(hashMap);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
resolve();
|
|
60
|
-
} catch (e) {
|
|
61
|
-
reject(e);
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function PickNextTestFromHashMap(hashMap: Map<any, Test>) {
|
|
67
|
-
for (let test of hashMap.values()) {
|
|
68
|
-
if (test.isFinished) continue;
|
|
69
|
-
if (!test.dependencies.every((x) => x.dependency.isFinished)) continue;
|
|
70
|
-
|
|
71
|
-
return test;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function CreateInstanceIfNotExists(test: Test) {
|
|
76
|
-
if (!test.testInstance) {
|
|
77
|
-
test.testInstance = new test.target();
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function HandleDependencies(test: Test) {
|
|
82
|
-
for (let dependency of test.dependencies) {
|
|
83
|
-
test.testInstance[dependency.propertyKey] =
|
|
84
|
-
dependency.dependency.testInstance;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async function HandleBeforeHooks(test: Test, options: Options) {
|
|
89
|
-
for (let [propertyKey, hook] of test.hooks.entries()) {
|
|
90
|
-
if (hook.type != HookType.Before) continue;
|
|
91
|
-
|
|
92
|
-
let hookName = colors.bold(
|
|
93
|
-
colors.yellow(
|
|
94
|
-
test.name +
|
|
95
|
-
(propertyKey != "before" ? `.${propertyKey}:before` : ":before")
|
|
96
|
-
)
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
try {
|
|
100
|
-
if (!options.orderDebug) {
|
|
101
|
-
await Executor(
|
|
102
|
-
test.testInstance[propertyKey].bind(test.testInstance),
|
|
103
|
-
hook.timeout
|
|
104
|
-
);
|
|
105
|
-
} else {
|
|
106
|
-
let timeText = TimeFactor(0, hook.timeout);
|
|
107
|
-
|
|
108
|
-
options.log(`${OK_TEXT} ${timeText} ${hookName}()`);
|
|
109
|
-
}
|
|
110
|
-
} catch (e) {
|
|
111
|
-
console.error(`${HOOK_FAILED_TEXT} ${hookName}()`);
|
|
112
|
-
console.error((e as any)?.stack ?? e);
|
|
113
|
-
throw e;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async function HandleBeforeEachHooks(test: Test, options: Options) {
|
|
119
|
-
for (let [propertyKey, hook] of test.hooks.entries()) {
|
|
120
|
-
if (hook.type != HookType.BeforeEach) continue;
|
|
121
|
-
let hookName = colors.bold(
|
|
122
|
-
colors.yellow(
|
|
123
|
-
test.name +
|
|
124
|
-
(propertyKey != "beforeEach"
|
|
125
|
-
? `.${propertyKey}:beforeEach`
|
|
126
|
-
: ":beforeEach")
|
|
127
|
-
)
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
if (!options.orderDebug) {
|
|
132
|
-
await Executor(
|
|
133
|
-
test.testInstance[propertyKey].bind(test.testInstance),
|
|
134
|
-
hook.timeout
|
|
135
|
-
);
|
|
136
|
-
} else {
|
|
137
|
-
let timeText = TimeFactor(0, hook.timeout);
|
|
138
|
-
|
|
139
|
-
options.log(`${OK_TEXT} ${timeText} ${hookName}()`);
|
|
140
|
-
}
|
|
141
|
-
} catch (e) {
|
|
142
|
-
console.error(`${HOOK_FAILED_TEXT} ${hookName}()`);
|
|
143
|
-
console.error((e as any)?.stack ?? e);
|
|
144
|
-
throw e;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async function HandleAfterEachHooks(test: Test, options: Options) {
|
|
150
|
-
for (let [propertyKey, hook] of test.hooks.entries()) {
|
|
151
|
-
if (hook.type != HookType.AfterEach) continue;
|
|
152
|
-
|
|
153
|
-
let hookName = colors.bold(
|
|
154
|
-
colors.yellow(
|
|
155
|
-
test.name +
|
|
156
|
-
(propertyKey != "afterEach"
|
|
157
|
-
? `.${propertyKey}:afterEach`
|
|
158
|
-
: ":afterEach")
|
|
159
|
-
)
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
try {
|
|
163
|
-
if (!options.orderDebug) {
|
|
164
|
-
await Executor(
|
|
165
|
-
test.testInstance[propertyKey].bind(test.testInstance),
|
|
166
|
-
hook.timeout
|
|
167
|
-
);
|
|
168
|
-
} else {
|
|
169
|
-
let timeText = TimeFactor(0, hook.timeout);
|
|
170
|
-
|
|
171
|
-
options.log(`${OK_TEXT} ${timeText} ${hookName}()`);
|
|
172
|
-
}
|
|
173
|
-
} catch (e) {
|
|
174
|
-
console.error(`${HOOK_FAILED_TEXT} ${hookName}()`);
|
|
175
|
-
console.error((e as any)?.stack ?? e);
|
|
176
|
-
throw e;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
async function HandleSpecs(test: Test, options: Options) {
|
|
182
|
-
const log = options.log;
|
|
183
|
-
|
|
184
|
-
for (let [propertyKey, spec] of test.specs.entries()) {
|
|
185
|
-
let testName = colors.bold(colors.yellow(test.name + "." + propertyKey));
|
|
186
|
-
|
|
187
|
-
const shouldPropertySkip = test.skip.has(propertyKey);
|
|
188
|
-
if (shouldPropertySkip || test.skipClass) {
|
|
189
|
-
let reason = shouldPropertySkip
|
|
190
|
-
? test.skip.get(propertyKey)!.reason
|
|
191
|
-
: test.skipClass!.reason;
|
|
192
|
-
log(
|
|
193
|
-
`${SKIP_TEXT} ${" ".repeat(9)} ${testName}() ${
|
|
194
|
-
reason ? "{" + reason + "}" : ""
|
|
195
|
-
}`
|
|
196
|
-
);
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
await HandleBeforeEachHooks(test, options);
|
|
201
|
-
|
|
202
|
-
let start = TimeDifference.begin();
|
|
203
|
-
|
|
204
|
-
try {
|
|
205
|
-
if (!options.orderDebug) {
|
|
206
|
-
await Executor(
|
|
207
|
-
test.testInstance[propertyKey].bind(test.testInstance),
|
|
208
|
-
spec.timeout
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
let timeText = TimeFactor(start.end(), spec.timeout);
|
|
213
|
-
|
|
214
|
-
log(`${OK_TEXT} ${timeText} ${testName}()`);
|
|
215
|
-
} catch (e) {
|
|
216
|
-
if ((e as any)?._nole_anchor) {
|
|
217
|
-
let reason = (e as any).reason;
|
|
218
|
-
log(
|
|
219
|
-
`${DYNAMIC_SKIP_TEXT} ${" ".repeat(8)} ${testName}() ${
|
|
220
|
-
reason ? "{" + reason + "}" : ""
|
|
221
|
-
}`
|
|
222
|
-
);
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
let timeText = TimeFactor(start.end(), spec.timeout);
|
|
227
|
-
|
|
228
|
-
console.error(`${FAILED_TEXT} ${timeText} ${testName}()`);
|
|
229
|
-
console.error((e as any)?.stack ?? e);
|
|
230
|
-
throw e;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
await HandleAfterEachHooks(test, options);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
async function HandleAfterHooks(test: Test, options: Options) {
|
|
238
|
-
for (let [propertyKey, hook] of test.hooks.entries()) {
|
|
239
|
-
if (hook.type != HookType.After) continue;
|
|
240
|
-
|
|
241
|
-
let hookName = colors.bold(
|
|
242
|
-
colors.yellow(
|
|
243
|
-
test.name +
|
|
244
|
-
(propertyKey != "after" ? `.${propertyKey}:after` : ":after")
|
|
245
|
-
)
|
|
246
|
-
);
|
|
247
|
-
|
|
248
|
-
try {
|
|
249
|
-
if (!options.orderDebug) {
|
|
250
|
-
await Executor(
|
|
251
|
-
test.testInstance[propertyKey].bind(test.testInstance),
|
|
252
|
-
hook.timeout
|
|
253
|
-
);
|
|
254
|
-
} else {
|
|
255
|
-
let timeText = TimeFactor(0, hook.timeout);
|
|
256
|
-
|
|
257
|
-
options.log(`${OK_TEXT} ${timeText} ${hookName}()`);
|
|
258
|
-
}
|
|
259
|
-
} catch (e) {
|
|
260
|
-
console.error(`${HOOK_FAILED_TEXT} ${hookName}()`);
|
|
261
|
-
console.error((e as any)?.stack ?? e);
|
|
262
|
-
throw e;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
async function HandleCleanUp(test: Test, options: Options) {
|
|
268
|
-
if (test.cleanUpCalled) return;
|
|
269
|
-
if (
|
|
270
|
-
!test.dependents.every(
|
|
271
|
-
(dependent) => dependent.isFinished && dependent.cleanUpCalled
|
|
272
|
-
)
|
|
273
|
-
)
|
|
274
|
-
return;
|
|
275
|
-
|
|
276
|
-
test.cleanUpCalled = true;
|
|
277
|
-
|
|
278
|
-
const log = options.log;
|
|
279
|
-
|
|
280
|
-
for (let [propertyKey, hook] of test.hooks.entries()) {
|
|
281
|
-
if (hook.type != HookType.CleanUp) continue;
|
|
282
|
-
|
|
283
|
-
let hookName = colors.bold(
|
|
284
|
-
colors.yellow(
|
|
285
|
-
test.name +
|
|
286
|
-
(propertyKey != "cleanUp" ? `.${propertyKey}:cleanUp` : ":cleanUp")
|
|
287
|
-
)
|
|
288
|
-
);
|
|
289
|
-
let start = TimeDifference.begin();
|
|
290
|
-
|
|
291
|
-
try {
|
|
292
|
-
if (!options.orderDebug) {
|
|
293
|
-
await Executor(
|
|
294
|
-
test.testInstance[propertyKey].bind(test.testInstance),
|
|
295
|
-
hook.timeout
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
let timeText = TimeFactor(start.end(), hook.timeout);
|
|
300
|
-
|
|
301
|
-
log(`${OK_TEXT} ${timeText} ${hookName}()`);
|
|
302
|
-
} catch (e) {
|
|
303
|
-
console.error(`${HOOK_FAILED_TEXT} ${hookName}()`);
|
|
304
|
-
console.error((e as any)?.stack ?? e);
|
|
305
|
-
throw e;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
for (let tree of test.dependencies) {
|
|
310
|
-
await HandleCleanUp(tree.dependency, options);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
function DependencyLock(hashMap: Map<any, Test>) {
|
|
315
|
-
console.error(
|
|
316
|
-
FAILED_TEXT +
|
|
317
|
-
colors.red("Looks like there is confict issue for dependency resolving!")
|
|
318
|
-
);
|
|
319
|
-
|
|
320
|
-
console.error("Possible conflicts;");
|
|
321
|
-
for (let test of hashMap.values()) {
|
|
322
|
-
console.error(
|
|
323
|
-
`- class ${test.name} { ${test.dependencies
|
|
324
|
-
.filter((x) => !x.dependency.isFinished)
|
|
325
|
-
.map((x) => `@Dependency(${x.dependency.name}) ${x.propertyKey}`)
|
|
326
|
-
.join(", ")} }`
|
|
327
|
-
);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
throw new Error("Dependency lock occurred!");
|
|
331
|
-
}
|
package/src/test.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
export interface IDependency {
|
|
2
|
-
propertyKey: string;
|
|
3
|
-
dependency: Test;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export interface ISpec {
|
|
7
|
-
timeout: number;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface IHook {
|
|
11
|
-
type: HookType;
|
|
12
|
-
timeout: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ISkip {
|
|
16
|
-
reason: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export class Test {
|
|
20
|
-
dependencies: IDependency[] = [];
|
|
21
|
-
dependents: Test[] = [];
|
|
22
|
-
skip = new Map<string, ISkip>();
|
|
23
|
-
skipClass: ISkip | null = null;
|
|
24
|
-
specs = new Map<string, ISpec>();
|
|
25
|
-
hooks = new Map<string, IHook>();
|
|
26
|
-
isFinished: boolean = false; // cleanup ignored
|
|
27
|
-
cleanUpCalled: boolean = false;
|
|
28
|
-
testInstance: any;
|
|
29
|
-
|
|
30
|
-
constructor(public target: any) {}
|
|
31
|
-
|
|
32
|
-
get name() {
|
|
33
|
-
return this.target.name;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export enum HookType {
|
|
38
|
-
Before, // Trigger when test case is ready to handle
|
|
39
|
-
After, // Trigger when test case did all the specs
|
|
40
|
-
BeforeEach, // Trigger before each spec
|
|
41
|
-
AfterEach, // Trigger after each spec
|
|
42
|
-
CleanUp, // Trigger after all dependents tested (You can safely remove connections etc.)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface ClassDefition<T> {
|
|
46
|
-
new (): T;
|
|
47
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import * as assert from "assert";
|
|
2
|
-
import { Spec } from "../index.js";
|
|
3
|
-
import { Executor } from "./executor.js";
|
|
4
|
-
|
|
5
|
-
export class ExecutorTest {
|
|
6
|
-
@Spec()
|
|
7
|
-
async evaluate() {
|
|
8
|
-
await Executor(() => 1, 1);
|
|
9
|
-
await Executor(async () => 1, 1);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
@Spec()
|
|
13
|
-
async throws() {
|
|
14
|
-
await assert.rejects(() => {
|
|
15
|
-
return Executor(() => {
|
|
16
|
-
throw new Error("throws");
|
|
17
|
-
}, 1);
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
@Spec()
|
|
22
|
-
async timeout() {
|
|
23
|
-
await assert.rejects(() => {
|
|
24
|
-
return Executor(() => new Promise(() => {}), 10);
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
}
|
package/src/utils/executor.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export function Executor(fn: Function, timeout: number): Promise<void> {
|
|
2
|
-
return new Promise(async (resolve, reject) => {
|
|
3
|
-
let _timeout = null;
|
|
4
|
-
|
|
5
|
-
try {
|
|
6
|
-
let expectPromise = fn();
|
|
7
|
-
if (expectPromise && expectPromise.then) {
|
|
8
|
-
_timeout = setTimeout(function () {
|
|
9
|
-
reject(new Error("Timeout occurred! value: " + timeout));
|
|
10
|
-
}, timeout);
|
|
11
|
-
|
|
12
|
-
await expectPromise;
|
|
13
|
-
}
|
|
14
|
-
} catch (e) {
|
|
15
|
-
reject(e);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
clearTimeout(_timeout!);
|
|
19
|
-
|
|
20
|
-
resolve();
|
|
21
|
-
});
|
|
22
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import * as assert from "assert";
|
|
2
|
-
import { Spec } from "../index.js";
|
|
3
|
-
import { Executor } from "./executor.js";
|
|
4
|
-
import { TimeDifference } from "./time_difference.js";
|
|
5
|
-
|
|
6
|
-
export class TimeDifferenceTest {
|
|
7
|
-
@Spec()
|
|
8
|
-
async evaluate() {
|
|
9
|
-
const td = TimeDifference.begin();
|
|
10
|
-
td.end();
|
|
11
|
-
}
|
|
12
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Calculates the time difference in nanoseconds
|
|
3
|
-
*/
|
|
4
|
-
export class TimeDifference {
|
|
5
|
-
private startAt: [number, number];
|
|
6
|
-
|
|
7
|
-
private constructor() {
|
|
8
|
-
this.startAt = process.hrtime();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Creates the instance at the begining
|
|
13
|
-
*/
|
|
14
|
-
public static begin() {
|
|
15
|
-
return new TimeDifference();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Finishes the time, returns data in milliseconds
|
|
20
|
-
*/
|
|
21
|
-
end(): number {
|
|
22
|
-
let diff = process.hrtime(this.startAt);
|
|
23
|
-
|
|
24
|
-
return diff[0] * 1000 + diff[1] / 1e6;
|
|
25
|
-
}
|
|
26
|
-
}
|