@nestia/e2e 11.0.0-dev.20260312 → 11.0.0-dev.20260313-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/DynamicExecutor.ts +274 -274
- package/src/index.ts +4 -4
- package/src/internal/json_equal_to.ts +35 -35
package/package.json
CHANGED
package/src/DynamicExecutor.ts
CHANGED
|
@@ -1,274 +1,274 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import NodePath from "path";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Dynamic Executor running prefixed functions.
|
|
6
|
-
*
|
|
7
|
-
* `DynamicExecutor` runs every (or some filtered) prefixed functions in a
|
|
8
|
-
* specific directory.
|
|
9
|
-
*
|
|
10
|
-
* For reference, it's useful for test program development of a backend server.
|
|
11
|
-
* Just write test functions under a directory, and just specify it.
|
|
12
|
-
* Furthermore, if you compose e2e test programs to utilize the `@nestia/sdk`
|
|
13
|
-
* generated API functions, you can take advantage of {@link DynamicBenchmarker}
|
|
14
|
-
* at the same time.
|
|
15
|
-
*
|
|
16
|
-
* When you want to see some utilization cases, see the below example links.
|
|
17
|
-
*
|
|
18
|
-
* @author Jeongho Nam - https://github.com/samchon
|
|
19
|
-
* @example
|
|
20
|
-
* https://github.com/samchon/nestia-start/blob/master/test/index.ts
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* https://github.com/samchon/backend/blob/master/test/index.ts
|
|
24
|
-
*/
|
|
25
|
-
export namespace DynamicExecutor {
|
|
26
|
-
/**
|
|
27
|
-
* Function type of a prefixed.
|
|
28
|
-
*
|
|
29
|
-
* @template Arguments Type of parameters
|
|
30
|
-
* @template Ret Type of return value
|
|
31
|
-
*/
|
|
32
|
-
export interface Closure<Arguments extends any[], Ret = any> {
|
|
33
|
-
(...args: Arguments): Promise<Ret>;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Options for dynamic executor. */
|
|
37
|
-
export interface IProps<Parameters extends any[], Ret = any> {
|
|
38
|
-
/**
|
|
39
|
-
* Prefix of function name.
|
|
40
|
-
*
|
|
41
|
-
* Every prefixed function will be executed.
|
|
42
|
-
*
|
|
43
|
-
* In other words, if a function name doesn't start with the prefix, then it
|
|
44
|
-
* would never be executed.
|
|
45
|
-
*/
|
|
46
|
-
prefix: string;
|
|
47
|
-
|
|
48
|
-
/** Location of the test functions. */
|
|
49
|
-
location: string;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Get parameters of a function.
|
|
53
|
-
*
|
|
54
|
-
* @param name Function name
|
|
55
|
-
* @returns Parameters
|
|
56
|
-
*/
|
|
57
|
-
parameters: (name: string) => Parameters;
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* On complete function.
|
|
61
|
-
*
|
|
62
|
-
* Listener of completion of a test function.
|
|
63
|
-
*
|
|
64
|
-
* @param exec Execution result of a test function
|
|
65
|
-
*/
|
|
66
|
-
onComplete?: (exec: IExecution) => void;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Filter function whether to run or not.
|
|
70
|
-
*
|
|
71
|
-
* @param name Function name
|
|
72
|
-
* @returns Whether to run or not
|
|
73
|
-
*/
|
|
74
|
-
filter?: (name: string) => boolean;
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Wrapper of test function.
|
|
78
|
-
*
|
|
79
|
-
* If you specify this `wrapper` property, every dynamic functions loaded
|
|
80
|
-
* and called by this `DynamicExecutor` would be wrapped by the `wrapper`
|
|
81
|
-
* function.
|
|
82
|
-
*
|
|
83
|
-
* @param name Function name
|
|
84
|
-
* @param closure Function to be executed
|
|
85
|
-
* @param parameters Parameters, result of options.parameters function.
|
|
86
|
-
* @returns Wrapper function
|
|
87
|
-
*/
|
|
88
|
-
wrapper?: (
|
|
89
|
-
name: string,
|
|
90
|
-
closure: Closure<Parameters, Ret>,
|
|
91
|
-
parameters: Parameters,
|
|
92
|
-
) => Promise<any>;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Number of simultaneous requests.
|
|
96
|
-
*
|
|
97
|
-
* The number of requests to be executed simultaneously.
|
|
98
|
-
*
|
|
99
|
-
* If you configure a value greater than one, the dynamic executor will
|
|
100
|
-
* process the functions concurrently with the given capacity value.
|
|
101
|
-
*
|
|
102
|
-
* @default 1
|
|
103
|
-
*/
|
|
104
|
-
simultaneous?: number;
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Extension of dynamic functions.
|
|
108
|
-
*
|
|
109
|
-
* @default js
|
|
110
|
-
*/
|
|
111
|
-
extension?: string;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** Report, result of dynamic execution. */
|
|
115
|
-
export interface IReport {
|
|
116
|
-
/** Location path of dynamic functions. */
|
|
117
|
-
location: string;
|
|
118
|
-
|
|
119
|
-
/** Execution results of dynamic functions. */
|
|
120
|
-
executions: IExecution[];
|
|
121
|
-
|
|
122
|
-
/** Total elapsed time. */
|
|
123
|
-
time: number;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/** Execution of a test function. */
|
|
127
|
-
export interface IExecution {
|
|
128
|
-
/** Name of function. */
|
|
129
|
-
name: string;
|
|
130
|
-
|
|
131
|
-
/** Location path of the function. */
|
|
132
|
-
location: string;
|
|
133
|
-
|
|
134
|
-
/** Returned value from the function. */
|
|
135
|
-
value: unknown;
|
|
136
|
-
|
|
137
|
-
/** Error when occurred. */
|
|
138
|
-
error: Error | null;
|
|
139
|
-
|
|
140
|
-
/** Elapsed time. */
|
|
141
|
-
started_at: string;
|
|
142
|
-
|
|
143
|
-
/** Completion time. */
|
|
144
|
-
completed_at: string;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Prepare dynamic executor in strict mode.
|
|
149
|
-
*
|
|
150
|
-
* In strict mode, if any error occurs, the program will be terminated
|
|
151
|
-
* directly. Otherwise, {@link validate} mode does not terminate when error
|
|
152
|
-
* occurs, but just archive the error log.
|
|
153
|
-
*
|
|
154
|
-
* @param props Properties of dynamic execution
|
|
155
|
-
* @returns Report of dynamic test functions execution
|
|
156
|
-
*/
|
|
157
|
-
export const assert = <Arguments extends any[]>(
|
|
158
|
-
props: IProps<Arguments>,
|
|
159
|
-
): Promise<IReport> => main(true)(props);
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Prepare dynamic executor in loose mode.
|
|
163
|
-
*
|
|
164
|
-
* In loose mode, the program would not be terminated even when error occurs.
|
|
165
|
-
* Instead, the error would be archived and returns as a list. Otherwise,
|
|
166
|
-
* {@link assert} mode terminates the program directly when error occurs.
|
|
167
|
-
*
|
|
168
|
-
* @param props Properties of dynamic executor
|
|
169
|
-
* @returns Report of dynamic test functions execution
|
|
170
|
-
*/
|
|
171
|
-
export const validate = <Arguments extends any[]>(
|
|
172
|
-
props: IProps<Arguments>,
|
|
173
|
-
): Promise<IReport> => main(false)(props);
|
|
174
|
-
|
|
175
|
-
const main =
|
|
176
|
-
(assert: boolean) =>
|
|
177
|
-
async <Arguments extends any[]>(
|
|
178
|
-
props: IProps<Arguments>,
|
|
179
|
-
): Promise<IReport> => {
|
|
180
|
-
const report: IReport = {
|
|
181
|
-
location: props.location,
|
|
182
|
-
time: Date.now(),
|
|
183
|
-
executions: [],
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
const executor = execute(props)(report)(assert);
|
|
187
|
-
const processes: Array<() => Promise<void>> = await iterate({
|
|
188
|
-
extension: props.extension ?? "js",
|
|
189
|
-
location: props.location,
|
|
190
|
-
executor,
|
|
191
|
-
});
|
|
192
|
-
await Promise.all(
|
|
193
|
-
new Array(props.simultaneous ?? 1).fill(0).map(async () => {
|
|
194
|
-
while (processes.length !== 0) {
|
|
195
|
-
const task = processes.shift();
|
|
196
|
-
await task?.();
|
|
197
|
-
}
|
|
198
|
-
}),
|
|
199
|
-
);
|
|
200
|
-
report.time = Date.now() - report.time;
|
|
201
|
-
return report;
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
const iterate = async <Arguments extends any[]>(props: {
|
|
205
|
-
location: string;
|
|
206
|
-
extension: string;
|
|
207
|
-
executor: (path: string, modulo: Module<Arguments>) => Promise<void>;
|
|
208
|
-
}): Promise<Array<() => Promise<void>>> => {
|
|
209
|
-
const container: Array<() => Promise<void>> = [];
|
|
210
|
-
const visitor = async (path: string): Promise<void> => {
|
|
211
|
-
const directory: string[] = await fs.promises.readdir(path);
|
|
212
|
-
for (const file of directory) {
|
|
213
|
-
const location: string = NodePath.resolve(`${path}/${file}`);
|
|
214
|
-
const stats: fs.Stats = await fs.promises.lstat(location);
|
|
215
|
-
|
|
216
|
-
if (stats.isDirectory() === true) {
|
|
217
|
-
await visitor(location);
|
|
218
|
-
continue;
|
|
219
|
-
} else if (file.substr(-3) !== `.${props.extension}`) continue;
|
|
220
|
-
|
|
221
|
-
const modulo: Module<Arguments> = await import(location);
|
|
222
|
-
container.push(() => props.executor(location, modulo));
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
await visitor(props.location);
|
|
226
|
-
return container;
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
const execute =
|
|
230
|
-
<Arguments extends any[]>(props: IProps<Arguments>) =>
|
|
231
|
-
(report: IReport) =>
|
|
232
|
-
(assert: boolean) =>
|
|
233
|
-
async (location: string, modulo: Module<Arguments>): Promise<void> => {
|
|
234
|
-
for (const [key, closure] of Object.entries(modulo)) {
|
|
235
|
-
if (
|
|
236
|
-
key.substring(0, props.prefix.length) !== props.prefix ||
|
|
237
|
-
typeof closure !== "function" ||
|
|
238
|
-
(props.filter && props.filter(key) === false)
|
|
239
|
-
)
|
|
240
|
-
continue;
|
|
241
|
-
|
|
242
|
-
const func = () => {
|
|
243
|
-
if (props.wrapper !== undefined)
|
|
244
|
-
return props.wrapper(key, closure, props.parameters(key));
|
|
245
|
-
else return closure(...props.parameters(key));
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
const result: IExecution = {
|
|
249
|
-
name: key,
|
|
250
|
-
location,
|
|
251
|
-
value: undefined,
|
|
252
|
-
error: null,
|
|
253
|
-
started_at: new Date().toISOString(),
|
|
254
|
-
completed_at: new Date().toISOString(),
|
|
255
|
-
};
|
|
256
|
-
report.executions.push(result);
|
|
257
|
-
|
|
258
|
-
try {
|
|
259
|
-
result.value = await func();
|
|
260
|
-
result.completed_at = new Date().toISOString();
|
|
261
|
-
} catch (exp) {
|
|
262
|
-
result.error = exp as Error;
|
|
263
|
-
if (assert === true) throw exp;
|
|
264
|
-
} finally {
|
|
265
|
-
result.completed_at = new Date().toISOString();
|
|
266
|
-
if (props.onComplete) props.onComplete(result);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
interface Module<Arguments extends any[]> {
|
|
272
|
-
[key: string]: Closure<Arguments>;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import NodePath from "path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Dynamic Executor running prefixed functions.
|
|
6
|
+
*
|
|
7
|
+
* `DynamicExecutor` runs every (or some filtered) prefixed functions in a
|
|
8
|
+
* specific directory.
|
|
9
|
+
*
|
|
10
|
+
* For reference, it's useful for test program development of a backend server.
|
|
11
|
+
* Just write test functions under a directory, and just specify it.
|
|
12
|
+
* Furthermore, if you compose e2e test programs to utilize the `@nestia/sdk`
|
|
13
|
+
* generated API functions, you can take advantage of {@link DynamicBenchmarker}
|
|
14
|
+
* at the same time.
|
|
15
|
+
*
|
|
16
|
+
* When you want to see some utilization cases, see the below example links.
|
|
17
|
+
*
|
|
18
|
+
* @author Jeongho Nam - https://github.com/samchon
|
|
19
|
+
* @example
|
|
20
|
+
* https://github.com/samchon/nestia-start/blob/master/test/index.ts
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* https://github.com/samchon/backend/blob/master/test/index.ts
|
|
24
|
+
*/
|
|
25
|
+
export namespace DynamicExecutor {
|
|
26
|
+
/**
|
|
27
|
+
* Function type of a prefixed.
|
|
28
|
+
*
|
|
29
|
+
* @template Arguments Type of parameters
|
|
30
|
+
* @template Ret Type of return value
|
|
31
|
+
*/
|
|
32
|
+
export interface Closure<Arguments extends any[], Ret = any> {
|
|
33
|
+
(...args: Arguments): Promise<Ret>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Options for dynamic executor. */
|
|
37
|
+
export interface IProps<Parameters extends any[], Ret = any> {
|
|
38
|
+
/**
|
|
39
|
+
* Prefix of function name.
|
|
40
|
+
*
|
|
41
|
+
* Every prefixed function will be executed.
|
|
42
|
+
*
|
|
43
|
+
* In other words, if a function name doesn't start with the prefix, then it
|
|
44
|
+
* would never be executed.
|
|
45
|
+
*/
|
|
46
|
+
prefix: string;
|
|
47
|
+
|
|
48
|
+
/** Location of the test functions. */
|
|
49
|
+
location: string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get parameters of a function.
|
|
53
|
+
*
|
|
54
|
+
* @param name Function name
|
|
55
|
+
* @returns Parameters
|
|
56
|
+
*/
|
|
57
|
+
parameters: (name: string) => Parameters;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* On complete function.
|
|
61
|
+
*
|
|
62
|
+
* Listener of completion of a test function.
|
|
63
|
+
*
|
|
64
|
+
* @param exec Execution result of a test function
|
|
65
|
+
*/
|
|
66
|
+
onComplete?: (exec: IExecution) => void;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Filter function whether to run or not.
|
|
70
|
+
*
|
|
71
|
+
* @param name Function name
|
|
72
|
+
* @returns Whether to run or not
|
|
73
|
+
*/
|
|
74
|
+
filter?: (name: string) => boolean;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Wrapper of test function.
|
|
78
|
+
*
|
|
79
|
+
* If you specify this `wrapper` property, every dynamic functions loaded
|
|
80
|
+
* and called by this `DynamicExecutor` would be wrapped by the `wrapper`
|
|
81
|
+
* function.
|
|
82
|
+
*
|
|
83
|
+
* @param name Function name
|
|
84
|
+
* @param closure Function to be executed
|
|
85
|
+
* @param parameters Parameters, result of options.parameters function.
|
|
86
|
+
* @returns Wrapper function
|
|
87
|
+
*/
|
|
88
|
+
wrapper?: (
|
|
89
|
+
name: string,
|
|
90
|
+
closure: Closure<Parameters, Ret>,
|
|
91
|
+
parameters: Parameters,
|
|
92
|
+
) => Promise<any>;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Number of simultaneous requests.
|
|
96
|
+
*
|
|
97
|
+
* The number of requests to be executed simultaneously.
|
|
98
|
+
*
|
|
99
|
+
* If you configure a value greater than one, the dynamic executor will
|
|
100
|
+
* process the functions concurrently with the given capacity value.
|
|
101
|
+
*
|
|
102
|
+
* @default 1
|
|
103
|
+
*/
|
|
104
|
+
simultaneous?: number;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Extension of dynamic functions.
|
|
108
|
+
*
|
|
109
|
+
* @default js
|
|
110
|
+
*/
|
|
111
|
+
extension?: string;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Report, result of dynamic execution. */
|
|
115
|
+
export interface IReport {
|
|
116
|
+
/** Location path of dynamic functions. */
|
|
117
|
+
location: string;
|
|
118
|
+
|
|
119
|
+
/** Execution results of dynamic functions. */
|
|
120
|
+
executions: IExecution[];
|
|
121
|
+
|
|
122
|
+
/** Total elapsed time. */
|
|
123
|
+
time: number;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Execution of a test function. */
|
|
127
|
+
export interface IExecution {
|
|
128
|
+
/** Name of function. */
|
|
129
|
+
name: string;
|
|
130
|
+
|
|
131
|
+
/** Location path of the function. */
|
|
132
|
+
location: string;
|
|
133
|
+
|
|
134
|
+
/** Returned value from the function. */
|
|
135
|
+
value: unknown;
|
|
136
|
+
|
|
137
|
+
/** Error when occurred. */
|
|
138
|
+
error: Error | null;
|
|
139
|
+
|
|
140
|
+
/** Elapsed time. */
|
|
141
|
+
started_at: string;
|
|
142
|
+
|
|
143
|
+
/** Completion time. */
|
|
144
|
+
completed_at: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Prepare dynamic executor in strict mode.
|
|
149
|
+
*
|
|
150
|
+
* In strict mode, if any error occurs, the program will be terminated
|
|
151
|
+
* directly. Otherwise, {@link validate} mode does not terminate when error
|
|
152
|
+
* occurs, but just archive the error log.
|
|
153
|
+
*
|
|
154
|
+
* @param props Properties of dynamic execution
|
|
155
|
+
* @returns Report of dynamic test functions execution
|
|
156
|
+
*/
|
|
157
|
+
export const assert = <Arguments extends any[]>(
|
|
158
|
+
props: IProps<Arguments>,
|
|
159
|
+
): Promise<IReport> => main(true)(props);
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Prepare dynamic executor in loose mode.
|
|
163
|
+
*
|
|
164
|
+
* In loose mode, the program would not be terminated even when error occurs.
|
|
165
|
+
* Instead, the error would be archived and returns as a list. Otherwise,
|
|
166
|
+
* {@link assert} mode terminates the program directly when error occurs.
|
|
167
|
+
*
|
|
168
|
+
* @param props Properties of dynamic executor
|
|
169
|
+
* @returns Report of dynamic test functions execution
|
|
170
|
+
*/
|
|
171
|
+
export const validate = <Arguments extends any[]>(
|
|
172
|
+
props: IProps<Arguments>,
|
|
173
|
+
): Promise<IReport> => main(false)(props);
|
|
174
|
+
|
|
175
|
+
const main =
|
|
176
|
+
(assert: boolean) =>
|
|
177
|
+
async <Arguments extends any[]>(
|
|
178
|
+
props: IProps<Arguments>,
|
|
179
|
+
): Promise<IReport> => {
|
|
180
|
+
const report: IReport = {
|
|
181
|
+
location: props.location,
|
|
182
|
+
time: Date.now(),
|
|
183
|
+
executions: [],
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const executor = execute(props)(report)(assert);
|
|
187
|
+
const processes: Array<() => Promise<void>> = await iterate({
|
|
188
|
+
extension: props.extension ?? "js",
|
|
189
|
+
location: props.location,
|
|
190
|
+
executor,
|
|
191
|
+
});
|
|
192
|
+
await Promise.all(
|
|
193
|
+
new Array(props.simultaneous ?? 1).fill(0).map(async () => {
|
|
194
|
+
while (processes.length !== 0) {
|
|
195
|
+
const task = processes.shift();
|
|
196
|
+
await task?.();
|
|
197
|
+
}
|
|
198
|
+
}),
|
|
199
|
+
);
|
|
200
|
+
report.time = Date.now() - report.time;
|
|
201
|
+
return report;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const iterate = async <Arguments extends any[]>(props: {
|
|
205
|
+
location: string;
|
|
206
|
+
extension: string;
|
|
207
|
+
executor: (path: string, modulo: Module<Arguments>) => Promise<void>;
|
|
208
|
+
}): Promise<Array<() => Promise<void>>> => {
|
|
209
|
+
const container: Array<() => Promise<void>> = [];
|
|
210
|
+
const visitor = async (path: string): Promise<void> => {
|
|
211
|
+
const directory: string[] = await fs.promises.readdir(path);
|
|
212
|
+
for (const file of directory) {
|
|
213
|
+
const location: string = NodePath.resolve(`${path}/${file}`);
|
|
214
|
+
const stats: fs.Stats = await fs.promises.lstat(location);
|
|
215
|
+
|
|
216
|
+
if (stats.isDirectory() === true) {
|
|
217
|
+
await visitor(location);
|
|
218
|
+
continue;
|
|
219
|
+
} else if (file.substr(-3) !== `.${props.extension}`) continue;
|
|
220
|
+
|
|
221
|
+
const modulo: Module<Arguments> = await import(location);
|
|
222
|
+
container.push(() => props.executor(location, modulo));
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
await visitor(props.location);
|
|
226
|
+
return container;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const execute =
|
|
230
|
+
<Arguments extends any[]>(props: IProps<Arguments>) =>
|
|
231
|
+
(report: IReport) =>
|
|
232
|
+
(assert: boolean) =>
|
|
233
|
+
async (location: string, modulo: Module<Arguments>): Promise<void> => {
|
|
234
|
+
for (const [key, closure] of Object.entries(modulo)) {
|
|
235
|
+
if (
|
|
236
|
+
key.substring(0, props.prefix.length) !== props.prefix ||
|
|
237
|
+
typeof closure !== "function" ||
|
|
238
|
+
(props.filter && props.filter(key) === false)
|
|
239
|
+
)
|
|
240
|
+
continue;
|
|
241
|
+
|
|
242
|
+
const func = () => {
|
|
243
|
+
if (props.wrapper !== undefined)
|
|
244
|
+
return props.wrapper(key, closure, props.parameters(key));
|
|
245
|
+
else return closure(...props.parameters(key));
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const result: IExecution = {
|
|
249
|
+
name: key,
|
|
250
|
+
location,
|
|
251
|
+
value: undefined,
|
|
252
|
+
error: null,
|
|
253
|
+
started_at: new Date().toISOString(),
|
|
254
|
+
completed_at: new Date().toISOString(),
|
|
255
|
+
};
|
|
256
|
+
report.executions.push(result);
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
result.value = await func();
|
|
260
|
+
result.completed_at = new Date().toISOString();
|
|
261
|
+
} catch (exp) {
|
|
262
|
+
result.error = exp as Error;
|
|
263
|
+
if (assert === true) throw exp;
|
|
264
|
+
} finally {
|
|
265
|
+
result.completed_at = new Date().toISOString();
|
|
266
|
+
if (props.onComplete) props.onComplete(result);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
interface Module<Arguments extends any[]> {
|
|
272
|
+
[key: string]: Closure<Arguments>;
|
|
273
|
+
}
|
|
274
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as e2e from "./module";
|
|
2
|
-
|
|
3
|
-
export default e2e;
|
|
4
|
-
export * from "./module";
|
|
1
|
+
import * as e2e from "./module";
|
|
2
|
+
|
|
3
|
+
export default e2e;
|
|
4
|
+
export * from "./module";
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
export const json_equal_to =
|
|
2
|
-
(exception: (key: string) => boolean) =>
|
|
3
|
-
<T>(x: T) =>
|
|
4
|
-
(y: T | null | undefined): string[] => {
|
|
5
|
-
const container: string[] = [];
|
|
6
|
-
const iterate =
|
|
7
|
-
(accessor: string) =>
|
|
8
|
-
(x: any) =>
|
|
9
|
-
(y: any): void => {
|
|
10
|
-
if (typeof x === "function" || typeof y === "function") return;
|
|
11
|
-
else if (typeof x !== typeof y) container.push(accessor);
|
|
12
|
-
else if (x instanceof Array)
|
|
13
|
-
if (!(y instanceof Array)) container.push(accessor);
|
|
14
|
-
else array(accessor)(x)(y);
|
|
15
|
-
else if (x instanceof Object) object(accessor)(x)(y);
|
|
16
|
-
else if (x !== y) container.push(accessor);
|
|
17
|
-
};
|
|
18
|
-
const array =
|
|
19
|
-
(accessor: string) =>
|
|
20
|
-
(x: any[]) =>
|
|
21
|
-
(y: any[]): void => {
|
|
22
|
-
if (x.length !== y.length) container.push(`${accessor}.length`);
|
|
23
|
-
x.forEach((xItem, i) => iterate(`${accessor}[${i}]`)(xItem)(y[i]));
|
|
24
|
-
};
|
|
25
|
-
const object =
|
|
26
|
-
(accessor: string) =>
|
|
27
|
-
(x: any) =>
|
|
28
|
-
(y: any): void =>
|
|
29
|
-
Object.keys(x)
|
|
30
|
-
.filter((key) => x[key] !== undefined && !exception(key))
|
|
31
|
-
.forEach((key) => iterate(`${accessor}.${key}`)(x[key])(y[key]));
|
|
32
|
-
|
|
33
|
-
iterate("")(x)(y);
|
|
34
|
-
return container;
|
|
35
|
-
};
|
|
1
|
+
export const json_equal_to =
|
|
2
|
+
(exception: (key: string) => boolean) =>
|
|
3
|
+
<T>(x: T) =>
|
|
4
|
+
(y: T | null | undefined): string[] => {
|
|
5
|
+
const container: string[] = [];
|
|
6
|
+
const iterate =
|
|
7
|
+
(accessor: string) =>
|
|
8
|
+
(x: any) =>
|
|
9
|
+
(y: any): void => {
|
|
10
|
+
if (typeof x === "function" || typeof y === "function") return;
|
|
11
|
+
else if (typeof x !== typeof y) container.push(accessor);
|
|
12
|
+
else if (x instanceof Array)
|
|
13
|
+
if (!(y instanceof Array)) container.push(accessor);
|
|
14
|
+
else array(accessor)(x)(y);
|
|
15
|
+
else if (x instanceof Object) object(accessor)(x)(y);
|
|
16
|
+
else if (x !== y) container.push(accessor);
|
|
17
|
+
};
|
|
18
|
+
const array =
|
|
19
|
+
(accessor: string) =>
|
|
20
|
+
(x: any[]) =>
|
|
21
|
+
(y: any[]): void => {
|
|
22
|
+
if (x.length !== y.length) container.push(`${accessor}.length`);
|
|
23
|
+
x.forEach((xItem, i) => iterate(`${accessor}[${i}]`)(xItem)(y[i]));
|
|
24
|
+
};
|
|
25
|
+
const object =
|
|
26
|
+
(accessor: string) =>
|
|
27
|
+
(x: any) =>
|
|
28
|
+
(y: any): void =>
|
|
29
|
+
Object.keys(x)
|
|
30
|
+
.filter((key) => x[key] !== undefined && !exception(key))
|
|
31
|
+
.forEach((key) => iterate(`${accessor}.${key}`)(x[key])(y[key]));
|
|
32
|
+
|
|
33
|
+
iterate("")(x)(y);
|
|
34
|
+
return container;
|
|
35
|
+
};
|