@nestia/e2e 0.4.3 → 0.5.0-dev.20240617-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.
@@ -1,277 +1,277 @@
1
- import chalk from "chalk";
2
- import fs from "fs";
3
- import NodePath from "path";
4
-
5
- import { StopWatch } from "./StopWatch";
6
-
7
- /**
8
- * Dynamic Executor running prefixed functions.
9
- *
10
- * `DynamicExecutor` runs every prefixed functions in a specific directory.
11
- * However, if you want to run only specific functions, you can use
12
- * `--include` or `--exclude` option in the CLI (Command Line Interface) level.
13
- *
14
- * When you want to see example utilization cases, see the below example links.
15
- *
16
- * @example https://github.com/samchon/nestia-template/blob/master/src/test/index.ts
17
- * @example https://github.com/samchon/backend/blob/master/src/test/index.ts
18
- * @author Jeongho Nam - https://github.com/samchon
19
- */
20
- export namespace DynamicExecutor {
21
- /**
22
- * Function type of a prefixed.
23
- *
24
- * @template Arguments Type of parameters
25
- * @template Ret Type of return value
26
- */
27
- export interface Closure<Arguments extends any[], Ret = any> {
28
- (...args: Arguments): Promise<Ret>;
29
- }
30
-
31
- /**
32
- * Options for dynamic executor.
33
- */
34
- export interface IOptions<Parameters extends any[], Ret = any> {
35
- /**
36
- * Prefix of function name.
37
- *
38
- * Every prefixed function will be executed.
39
- *
40
- * In other words, if a function name doesn't start with the prefix, then it would never be executed.
41
- */
42
- prefix: string;
43
-
44
- /**
45
- * Get parameters of a function.
46
- *
47
- * @param name Function name
48
- * @returns Parameters
49
- */
50
- parameters: (name: string) => Parameters;
51
-
52
- /**
53
- * Filter function whether to run or not.
54
- *
55
- * @param name Function name
56
- * @returns Whether to run or not
57
- */
58
- filter?: (name: string) => boolean;
59
-
60
- /**
61
- * Wrapper of test function.
62
- *
63
- * If you specify this `wrapper` property, every dynamic functions
64
- * loaded and called by this `DynamicExecutor` would be wrapped by
65
- * the `wrapper` function.
66
- *
67
- * @param name Function name
68
- * @param closure Function to be executed
69
- * @param parameters Parameters, result of options.parameters function.
70
- * @returns Wrapper function
71
- */
72
- wrapper?: (
73
- name: string,
74
- closure: Closure<Parameters, Ret>,
75
- paramters: Parameters,
76
- ) => Promise<any>;
77
-
78
- /**
79
- * Whether to show elapsed time on `console` or not.
80
- *
81
- * @default true
82
- */
83
- showElapsedTime?: boolean;
84
-
85
- /**
86
- * Extension of dynamic functions.
87
- *
88
- * @default js
89
- */
90
- extension?: string;
91
- }
92
-
93
- /**
94
- * Report, result of dynamic execution.
95
- */
96
- export interface IReport {
97
- /**
98
- * Location path of dynamic functions.
99
- */
100
- location: string;
101
-
102
- /**
103
- * Execution results of dynamic functions.
104
- */
105
- executions: IReport.IExecution[];
106
-
107
- /**
108
- * Total elapsed time.
109
- */
110
- time: number;
111
- }
112
- export namespace IReport {
113
- /**
114
- * Execution result of a dynamic function.
115
- */
116
- export interface IExecution {
117
- /**
118
- * Name of function.
119
- */
120
- name: string;
121
-
122
- /**
123
- * Location path of the function.
124
- */
125
- location: string;
126
-
127
- /**
128
- * Error when occured.
129
- */
130
- error: Error | null;
131
-
132
- /**
133
- * Elapsed time.
134
- */
135
- time: number;
136
- }
137
- }
138
-
139
- /**
140
- * Prepare dynamic executor in strict mode.
141
- *
142
- * In strict mode, if any error occurs, the program will be terminated directly.
143
- * Otherwise, {@link validate} mode does not terminate when error occurs, but
144
- * just archive the error log.
145
- *
146
- * @param options Options of dynamic executor
147
- * @returns Runner of dynamic functions with specific location
148
- */
149
- export const assert =
150
- <Arguments extends any[]>(options: IOptions<Arguments>) =>
151
- /**
152
- * Run dynamic executor.
153
- *
154
- * @param path Location of prefixed functions
155
- */
156
- (path: string): Promise<IReport> =>
157
- main(options)(true)(path);
158
-
159
- /**
160
- * Prepare dynamic executor in loose mode.
161
- *
162
- * In loose mode, the program would not be terminated even when error occurs.
163
- * Instead, the error would be archived and returns as a list. Otherwise,
164
- * {@link assert} mode terminates the program directly when error occurs.
165
- *
166
- * @param options Options of dynamic executor
167
- * @returns Runner of dynamic functions with specific location
168
- */
169
- export const validate =
170
- <Arguments extends any[]>(options: IOptions<Arguments>) =>
171
- /**
172
- * Run dynamic executor.
173
- *
174
- * @param path Location of prefix functions
175
- * @returns List of errors
176
- */
177
- (path: string): Promise<IReport> =>
178
- main(options)(false)(path);
179
-
180
- const main =
181
- <Arguments extends any[]>(options: IOptions<Arguments>) =>
182
- (assert: boolean) =>
183
- async (path: string) => {
184
- const report: IReport = {
185
- location: path,
186
- time: Date.now(),
187
- executions: [],
188
- };
189
-
190
- const executor = execute(options)(report)(assert);
191
- const iterator = iterate(options.extension ?? "js")(executor);
192
- await iterator(path);
193
-
194
- report.time = Date.now() - report.time;
195
- return report;
196
- };
197
-
198
- const iterate =
199
- (extension: string) =>
200
- <Arguments extends any[]>(
201
- executor: (path: string, modulo: Module<Arguments>) => Promise<void>,
202
- ) => {
203
- const visitor = async (path: string): Promise<void> => {
204
- const directory: string[] = await fs.promises.readdir(path);
205
- for (const file of directory) {
206
- const location: string = NodePath.resolve(`${path}/${file}`);
207
- const stats: fs.Stats = await fs.promises.lstat(location);
208
-
209
- if (stats.isDirectory() === true) {
210
- await visitor(location);
211
- continue;
212
- } else if (file.substr(-3) !== `.${extension}`) continue;
213
-
214
- const modulo: Module<Arguments> = await import(location);
215
- await executor(location, modulo);
216
- }
217
- };
218
- return visitor;
219
- };
220
-
221
- const execute =
222
- <Arguments extends any[]>(options: IOptions<Arguments>) =>
223
- (report: IReport) =>
224
- (assert: boolean) =>
225
- async (location: string, modulo: Module<Arguments>): Promise<void> => {
226
- for (const [key, closure] of Object.entries(modulo)) {
227
- if (
228
- key.substring(0, options.prefix.length) !== options.prefix ||
229
- typeof closure !== "function" ||
230
- (options.filter && options.filter(key) === false)
231
- )
232
- continue;
233
-
234
- const func = async () => {
235
- if (options.wrapper !== undefined)
236
- await options.wrapper(key, closure, options.parameters(key));
237
- else await closure(...options.parameters(key));
238
- };
239
- const label: string = chalk.greenBright(key);
240
-
241
- const result: IReport.IExecution = {
242
- name: key,
243
- location,
244
- error: null,
245
- time: Date.now(),
246
- };
247
- report.executions.push(result);
248
-
249
- try {
250
- if (options.showElapsedTime === false) {
251
- await func();
252
- result.time = Date.now() - result.time;
253
- console.log(` - ${label}`);
254
- } else {
255
- result.time = (await StopWatch.measure(func))[1];
256
- console.log(
257
- ` - ${label}: ${chalk.yellowBright(
258
- result.time.toLocaleString(),
259
- )} ms`,
260
- );
261
- }
262
- } catch (exp) {
263
- result.time = Date.now() - result.time;
264
- result.error = exp as Error;
265
-
266
- console.log(
267
- ` - ${label} -> ${chalk.redBright((exp as Error)?.name)}`,
268
- );
269
- if (assert === true) throw exp;
270
- }
271
- }
272
- };
273
-
274
- interface Module<Arguments extends any[]> {
275
- [key: string]: Closure<Arguments>;
276
- }
277
- }
1
+ import chalk from "chalk";
2
+ import fs from "fs";
3
+ import NodePath from "path";
4
+
5
+ import { StopWatch } from "./StopWatch";
6
+
7
+ /**
8
+ * Dynamic Executor running prefixed functions.
9
+ *
10
+ * `DynamicExecutor` runs every prefixed functions in a specific directory.
11
+ * However, if you want to run only specific functions, you can use
12
+ * `--include` or `--exclude` option in the CLI (Command Line Interface) level.
13
+ *
14
+ * When you want to see example utilization cases, see the below example links.
15
+ *
16
+ * @example https://github.com/samchon/nestia-template/blob/master/src/test/index.ts
17
+ * @example https://github.com/samchon/backend/blob/master/src/test/index.ts
18
+ * @author Jeongho Nam - https://github.com/samchon
19
+ */
20
+ export namespace DynamicExecutor {
21
+ /**
22
+ * Function type of a prefixed.
23
+ *
24
+ * @template Arguments Type of parameters
25
+ * @template Ret Type of return value
26
+ */
27
+ export interface Closure<Arguments extends any[], Ret = any> {
28
+ (...args: Arguments): Promise<Ret>;
29
+ }
30
+
31
+ /**
32
+ * Options for dynamic executor.
33
+ */
34
+ export interface IOptions<Parameters extends any[], Ret = any> {
35
+ /**
36
+ * Prefix of function name.
37
+ *
38
+ * Every prefixed function will be executed.
39
+ *
40
+ * In other words, if a function name doesn't start with the prefix, then it would never be executed.
41
+ */
42
+ prefix: string;
43
+
44
+ /**
45
+ * Get parameters of a function.
46
+ *
47
+ * @param name Function name
48
+ * @returns Parameters
49
+ */
50
+ parameters: (name: string) => Parameters;
51
+
52
+ /**
53
+ * Filter function whether to run or not.
54
+ *
55
+ * @param name Function name
56
+ * @returns Whether to run or not
57
+ */
58
+ filter?: (name: string) => boolean;
59
+
60
+ /**
61
+ * Wrapper of test function.
62
+ *
63
+ * If you specify this `wrapper` property, every dynamic functions
64
+ * loaded and called by this `DynamicExecutor` would be wrapped by
65
+ * the `wrapper` function.
66
+ *
67
+ * @param name Function name
68
+ * @param closure Function to be executed
69
+ * @param parameters Parameters, result of options.parameters function.
70
+ * @returns Wrapper function
71
+ */
72
+ wrapper?: (
73
+ name: string,
74
+ closure: Closure<Parameters, Ret>,
75
+ paramters: Parameters,
76
+ ) => Promise<any>;
77
+
78
+ /**
79
+ * Whether to show elapsed time on `console` or not.
80
+ *
81
+ * @default true
82
+ */
83
+ showElapsedTime?: boolean;
84
+
85
+ /**
86
+ * Extension of dynamic functions.
87
+ *
88
+ * @default js
89
+ */
90
+ extension?: string;
91
+ }
92
+
93
+ /**
94
+ * Report, result of dynamic execution.
95
+ */
96
+ export interface IReport {
97
+ /**
98
+ * Location path of dynamic functions.
99
+ */
100
+ location: string;
101
+
102
+ /**
103
+ * Execution results of dynamic functions.
104
+ */
105
+ executions: IReport.IExecution[];
106
+
107
+ /**
108
+ * Total elapsed time.
109
+ */
110
+ time: number;
111
+ }
112
+ export namespace IReport {
113
+ /**
114
+ * Execution result of a dynamic function.
115
+ */
116
+ export interface IExecution {
117
+ /**
118
+ * Name of function.
119
+ */
120
+ name: string;
121
+
122
+ /**
123
+ * Location path of the function.
124
+ */
125
+ location: string;
126
+
127
+ /**
128
+ * Error when occured.
129
+ */
130
+ error: Error | null;
131
+
132
+ /**
133
+ * Elapsed time.
134
+ */
135
+ time: number;
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Prepare dynamic executor in strict mode.
141
+ *
142
+ * In strict mode, if any error occurs, the program will be terminated directly.
143
+ * Otherwise, {@link validate} mode does not terminate when error occurs, but
144
+ * just archive the error log.
145
+ *
146
+ * @param options Options of dynamic executor
147
+ * @returns Runner of dynamic functions with specific location
148
+ */
149
+ export const assert =
150
+ <Arguments extends any[]>(options: IOptions<Arguments>) =>
151
+ /**
152
+ * Run dynamic executor.
153
+ *
154
+ * @param path Location of prefixed functions
155
+ */
156
+ (path: string): Promise<IReport> =>
157
+ main(options)(true)(path);
158
+
159
+ /**
160
+ * Prepare dynamic executor in loose mode.
161
+ *
162
+ * In loose mode, the program would not be terminated even when error occurs.
163
+ * Instead, the error would be archived and returns as a list. Otherwise,
164
+ * {@link assert} mode terminates the program directly when error occurs.
165
+ *
166
+ * @param options Options of dynamic executor
167
+ * @returns Runner of dynamic functions with specific location
168
+ */
169
+ export const validate =
170
+ <Arguments extends any[]>(options: IOptions<Arguments>) =>
171
+ /**
172
+ * Run dynamic executor.
173
+ *
174
+ * @param path Location of prefix functions
175
+ * @returns List of errors
176
+ */
177
+ (path: string): Promise<IReport> =>
178
+ main(options)(false)(path);
179
+
180
+ const main =
181
+ <Arguments extends any[]>(options: IOptions<Arguments>) =>
182
+ (assert: boolean) =>
183
+ async (path: string) => {
184
+ const report: IReport = {
185
+ location: path,
186
+ time: Date.now(),
187
+ executions: [],
188
+ };
189
+
190
+ const executor = execute(options)(report)(assert);
191
+ const iterator = iterate(options.extension ?? "js")(executor);
192
+ await iterator(path);
193
+
194
+ report.time = Date.now() - report.time;
195
+ return report;
196
+ };
197
+
198
+ const iterate =
199
+ (extension: string) =>
200
+ <Arguments extends any[]>(
201
+ executor: (path: string, modulo: Module<Arguments>) => Promise<void>,
202
+ ) => {
203
+ const visitor = async (path: string): Promise<void> => {
204
+ const directory: string[] = await fs.promises.readdir(path);
205
+ for (const file of directory) {
206
+ const location: string = NodePath.resolve(`${path}/${file}`);
207
+ const stats: fs.Stats = await fs.promises.lstat(location);
208
+
209
+ if (stats.isDirectory() === true) {
210
+ await visitor(location);
211
+ continue;
212
+ } else if (file.substr(-3) !== `.${extension}`) continue;
213
+
214
+ const modulo: Module<Arguments> = await import(location);
215
+ await executor(location, modulo);
216
+ }
217
+ };
218
+ return visitor;
219
+ };
220
+
221
+ const execute =
222
+ <Arguments extends any[]>(options: IOptions<Arguments>) =>
223
+ (report: IReport) =>
224
+ (assert: boolean) =>
225
+ async (location: string, modulo: Module<Arguments>): Promise<void> => {
226
+ for (const [key, closure] of Object.entries(modulo)) {
227
+ if (
228
+ key.substring(0, options.prefix.length) !== options.prefix ||
229
+ typeof closure !== "function" ||
230
+ (options.filter && options.filter(key) === false)
231
+ )
232
+ continue;
233
+
234
+ const func = async () => {
235
+ if (options.wrapper !== undefined)
236
+ await options.wrapper(key, closure, options.parameters(key));
237
+ else await closure(...options.parameters(key));
238
+ };
239
+ const label: string = chalk.greenBright(key);
240
+
241
+ const result: IReport.IExecution = {
242
+ name: key,
243
+ location,
244
+ error: null,
245
+ time: Date.now(),
246
+ };
247
+ report.executions.push(result);
248
+
249
+ try {
250
+ if (options.showElapsedTime === false) {
251
+ await func();
252
+ result.time = Date.now() - result.time;
253
+ console.log(` - ${label}`);
254
+ } else {
255
+ result.time = (await StopWatch.measure(func))[1];
256
+ console.log(
257
+ ` - ${label}: ${chalk.yellowBright(
258
+ result.time.toLocaleString(),
259
+ )} ms`,
260
+ );
261
+ }
262
+ } catch (exp) {
263
+ result.time = Date.now() - result.time;
264
+ result.error = exp as Error;
265
+
266
+ console.log(
267
+ ` - ${label} -> ${chalk.redBright((exp as Error)?.name)}`,
268
+ );
269
+ if (assert === true) throw exp;
270
+ }
271
+ }
272
+ };
273
+
274
+ interface Module<Arguments extends any[]> {
275
+ [key: string]: Closure<Arguments>;
276
+ }
277
+ }