@deot/dev-test 2.9.8 → 2.9.10
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/dist/index.cjs +557 -548
- package/dist/index.js +520 -525
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1,565 +1,574 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __exportAll = (all, no_symbols) => {
|
|
10
|
+
let target = {};
|
|
11
|
+
for (var name in all) __defProp(target, name, {
|
|
12
|
+
get: all[name],
|
|
13
|
+
enumerable: true
|
|
14
|
+
});
|
|
15
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
16
|
+
return target;
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
20
|
+
key = keys[i];
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
22
|
+
get: ((k) => from[k]).bind(null, key),
|
|
23
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
29
|
+
value: mod,
|
|
30
|
+
enumerable: true
|
|
31
|
+
}) : target, mod));
|
|
32
|
+
//#endregion
|
|
33
|
+
let child_process = require("child_process");
|
|
34
|
+
child_process = __toESM(child_process);
|
|
35
|
+
let _deot_dev_shared = require("@deot/dev-shared");
|
|
36
|
+
let puppeteer = require("puppeteer");
|
|
37
|
+
puppeteer = __toESM(puppeteer);
|
|
38
|
+
let http = require("http");
|
|
39
|
+
http = __toESM(http);
|
|
40
|
+
let os = require("os");
|
|
41
|
+
os = __toESM(os);
|
|
42
|
+
//#region packages/test/src/command.ts
|
|
43
|
+
var { LOCAL_COMMAND_MAP } = _deot_dev_shared.Shell;
|
|
44
|
+
var KEY_MAP = {
|
|
45
|
+
DOWN: "\x1B[B",
|
|
46
|
+
UP: "\x1B[A",
|
|
47
|
+
ENTER: "\r",
|
|
48
|
+
SPACE: ""
|
|
49
|
+
};
|
|
50
|
+
var Command = class {
|
|
51
|
+
target;
|
|
52
|
+
code;
|
|
53
|
+
error;
|
|
54
|
+
resolve;
|
|
55
|
+
reject;
|
|
56
|
+
stdout;
|
|
57
|
+
stderr;
|
|
58
|
+
emitter;
|
|
59
|
+
isClose;
|
|
60
|
+
schedule;
|
|
61
|
+
constructor(command, args) {
|
|
62
|
+
this.target = new Promise((resolve, reject) => {
|
|
63
|
+
this.resolve = this._handleEnd(resolve);
|
|
64
|
+
this.reject = this._handleEnd(reject);
|
|
65
|
+
});
|
|
66
|
+
this.code = null;
|
|
67
|
+
this.error = null;
|
|
68
|
+
this.stdout = "";
|
|
69
|
+
this.stderr = "";
|
|
70
|
+
this.schedule = {
|
|
71
|
+
target: Promise.resolve(),
|
|
72
|
+
complete: () => {}
|
|
73
|
+
};
|
|
74
|
+
this.schedule.target = new Promise((resolve) => {
|
|
75
|
+
this.schedule.complete = resolve;
|
|
76
|
+
});
|
|
77
|
+
this.emitter = this.start(command, args);
|
|
78
|
+
this.isClose = false;
|
|
79
|
+
}
|
|
80
|
+
_handleEnd(fn) {
|
|
81
|
+
return (e) => {
|
|
82
|
+
this.isClose = true;
|
|
83
|
+
const { code, error } = e;
|
|
84
|
+
this.code = code;
|
|
85
|
+
this.error = error;
|
|
86
|
+
fn({
|
|
87
|
+
...e,
|
|
88
|
+
stdout: this.stdout,
|
|
89
|
+
stderr: this.stderr
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
start(command, args) {
|
|
94
|
+
const SPACE = " ";
|
|
95
|
+
const [command$, ...args$] = (command + SPACE + args.join(SPACE)).replace(/\s+/g, SPACE).split(SPACE).filter((i) => !!i).map((i) => LOCAL_COMMAND_MAP[i] || i);
|
|
96
|
+
const emitter = child_process.spawn(command$, args$, { stdio: [
|
|
97
|
+
"pipe",
|
|
98
|
+
"pipe",
|
|
99
|
+
"pipe"
|
|
100
|
+
] });
|
|
101
|
+
emitter.on("close", (code) => {
|
|
102
|
+
this.schedule.complete();
|
|
103
|
+
/* istanbul ignore next */
|
|
104
|
+
if (code !== 0) this.reject({ code });
|
|
105
|
+
else this.resolve({ code });
|
|
106
|
+
});
|
|
107
|
+
emitter.on(
|
|
108
|
+
"error",
|
|
109
|
+
/* istanbul ignore next */
|
|
110
|
+
(error) => {
|
|
111
|
+
this.schedule.complete();
|
|
112
|
+
!process.exitCode && (process.exitCode = 1);
|
|
113
|
+
this.reject({
|
|
114
|
+
code: process.exitCode,
|
|
115
|
+
error
|
|
20
116
|
});
|
|
21
117
|
}
|
|
118
|
+
);
|
|
119
|
+
emitter.stdout.on("data", (e) => {
|
|
120
|
+
this.stdout += e.toString();
|
|
121
|
+
this.schedule.complete();
|
|
122
|
+
});
|
|
123
|
+
emitter.stderr.on(
|
|
124
|
+
"data",
|
|
125
|
+
/* istanbul ignore next */
|
|
126
|
+
(e) => this.stderr += e.toString()
|
|
127
|
+
);
|
|
128
|
+
return emitter;
|
|
129
|
+
}
|
|
130
|
+
async stop() {
|
|
131
|
+
await this.schedule.target;
|
|
132
|
+
if (!this.isClose) {
|
|
133
|
+
this.emitter.stdin.end();
|
|
134
|
+
this.isClose = true;
|
|
135
|
+
}
|
|
136
|
+
return await this.target;
|
|
137
|
+
}
|
|
138
|
+
async press(key, timeout = 200) {
|
|
139
|
+
if (!key || this.isClose) return;
|
|
140
|
+
await this.schedule.target;
|
|
141
|
+
this.schedule.target = new Promise((resolve) => {
|
|
142
|
+
this.schedule.complete = resolve;
|
|
143
|
+
});
|
|
144
|
+
await new Promise((resolve) => {
|
|
145
|
+
this.emitter.stdin.write(KEY_MAP[key.toUpperCase()] || key, "utf8", resolve);
|
|
146
|
+
});
|
|
147
|
+
await new Promise((_) => setTimeout(_, timeout));
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
//#endregion
|
|
151
|
+
//#region packages/test/src/operater.ts
|
|
152
|
+
var Operater = class {
|
|
153
|
+
page;
|
|
154
|
+
constructor(v) {
|
|
155
|
+
this.page = v;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* @param selector ~
|
|
159
|
+
* @param options ~
|
|
160
|
+
*/
|
|
161
|
+
async click(selector, options) {
|
|
162
|
+
await this.page.click(selector, options);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* @param selector ~
|
|
166
|
+
* @returns ~
|
|
167
|
+
*/
|
|
168
|
+
async count(selector) {
|
|
169
|
+
return (await this.page.$$(selector)).length;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* @param selector ~
|
|
173
|
+
* @returns ~
|
|
174
|
+
*/
|
|
175
|
+
async text(selector) {
|
|
176
|
+
return await this.page.$eval(selector, (node) => node.textContent);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* @param selector ~
|
|
180
|
+
* @returns ~
|
|
181
|
+
*/
|
|
182
|
+
async value(selector) {
|
|
183
|
+
return await this.page.$eval(selector, (node) => node.value);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* @param selector ~
|
|
187
|
+
* @returns ~
|
|
188
|
+
*/
|
|
189
|
+
async html(selector) {
|
|
190
|
+
return await this.page.$eval(selector, (node) => node.innerHTML);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* @param selector ~
|
|
194
|
+
* @returns ~
|
|
195
|
+
*/
|
|
196
|
+
async classList(selector) {
|
|
197
|
+
return await this.page.$eval(selector, (node) => [...node.classList]);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* @param selector ~
|
|
201
|
+
* @returns ~
|
|
202
|
+
*/
|
|
203
|
+
async children(selector) {
|
|
204
|
+
return await this.page.$eval(selector, (node) => [...node.children]);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* @param selector ~
|
|
208
|
+
* @returns ~
|
|
209
|
+
*/
|
|
210
|
+
async isVisible(selector) {
|
|
211
|
+
return await this.page.$eval(selector, (node) => {
|
|
212
|
+
return window.getComputedStyle(node).display;
|
|
213
|
+
}) !== "none";
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
*
|
|
217
|
+
* @param selector ~
|
|
218
|
+
* @returns ~
|
|
219
|
+
*/
|
|
220
|
+
async isChecked(selector) {
|
|
221
|
+
return await this.page.$eval(selector, (node) => node.checked);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
*
|
|
225
|
+
* @param selector ~
|
|
226
|
+
* @returns ~
|
|
227
|
+
*/
|
|
228
|
+
async isFocused(selector) {
|
|
229
|
+
return await this.page.$eval(selector, (node) => node === document.activeElement);
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* @param selector ~
|
|
233
|
+
* @param value$ ~
|
|
234
|
+
* @returns ~
|
|
235
|
+
*/
|
|
236
|
+
async setValue(selector, value$) {
|
|
237
|
+
await this.page.$eval(selector, (node, value$$) => {
|
|
238
|
+
node.value = value$$;
|
|
239
|
+
node.dispatchEvent(new Event("input"));
|
|
240
|
+
}, value$);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* @param selector ~
|
|
244
|
+
* @param value$ ~
|
|
245
|
+
* @returns ~
|
|
246
|
+
*/
|
|
247
|
+
async typeValue(selector, value$) {
|
|
248
|
+
const el = await this.page.$(selector);
|
|
249
|
+
await el.evaluate((node) => node.value = "");
|
|
250
|
+
await el.type(value$);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* @param selector ~
|
|
254
|
+
* @param value$ ~
|
|
255
|
+
* @returns ~
|
|
256
|
+
*/
|
|
257
|
+
async enterValue(selector, value$) {
|
|
258
|
+
const el = await this.page.$(selector);
|
|
259
|
+
await el.evaluate((node) => node.value = "");
|
|
260
|
+
await el.type(value$);
|
|
261
|
+
await el.press("Enter");
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* @param selector ~
|
|
265
|
+
* @returns ~
|
|
266
|
+
*/
|
|
267
|
+
async clearValue(selector) {
|
|
268
|
+
return await this.page.$eval(selector, (node) => {
|
|
269
|
+
node.value = "";
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
*
|
|
274
|
+
* @param time ~
|
|
275
|
+
* @returns ~
|
|
276
|
+
*/
|
|
277
|
+
sleep(time) {
|
|
278
|
+
return this.page.evaluate((time$) => {
|
|
279
|
+
return new Promise((r) => {
|
|
280
|
+
setTimeout(r, time$);
|
|
281
|
+
});
|
|
282
|
+
}, time);
|
|
283
|
+
}
|
|
284
|
+
nextFrame() {
|
|
285
|
+
return this.page.evaluate(() => {
|
|
286
|
+
return new Promise((resolve) => {
|
|
287
|
+
requestAnimationFrame(() => {
|
|
288
|
+
requestAnimationFrame(resolve);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
//#endregion
|
|
295
|
+
//#region packages/test/src/launch.ts
|
|
296
|
+
var Launch = class {
|
|
297
|
+
browser;
|
|
298
|
+
page;
|
|
299
|
+
operater;
|
|
300
|
+
_browser;
|
|
301
|
+
_page;
|
|
302
|
+
puppeteerOptions;
|
|
303
|
+
options;
|
|
304
|
+
constructor(options) {
|
|
305
|
+
this.options = options || { logLevel: "slient" };
|
|
306
|
+
this.operater = new Proxy({}, { get: () => {
|
|
307
|
+
throw new Error("operater is not defined. create* invote first");
|
|
308
|
+
} });
|
|
309
|
+
this.browser = new Proxy({}, { get: () => {
|
|
310
|
+
throw new Error("browser is not defined. createBrowser invote first");
|
|
311
|
+
} });
|
|
312
|
+
this.page = new Proxy({}, { get: () => {
|
|
313
|
+
throw new Error("page is not defined. createPage invote first");
|
|
314
|
+
} });
|
|
315
|
+
/* istanbul ignore next -- @preserve */
|
|
316
|
+
this.puppeteerOptions = process.env.CI ? { args: ["--no-sandbox", "--disable-setuid-sandbox"] } : {};
|
|
317
|
+
}
|
|
318
|
+
createBrowser(force) {
|
|
319
|
+
if (force || !this._browser) {
|
|
320
|
+
if (force && this._browser) this._browser.then((browser) => {
|
|
321
|
+
browser.isConnected() && browser.close();
|
|
322
|
+
});
|
|
323
|
+
this._browser = puppeteer.default.launch({
|
|
324
|
+
...this.puppeteerOptions,
|
|
325
|
+
headless: true
|
|
326
|
+
});
|
|
327
|
+
this._browser.then((browser) => {
|
|
328
|
+
this.browser = browser;
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
return this._browser;
|
|
332
|
+
}
|
|
333
|
+
async createPage(force) {
|
|
334
|
+
await this.createBrowser();
|
|
335
|
+
if (force || !this._page) {
|
|
336
|
+
if (force && this._page) this._page.then((page) => {
|
|
337
|
+
!page.isClosed() && page.close();
|
|
338
|
+
});
|
|
339
|
+
this._page = new Promise((resolve) => {
|
|
340
|
+
(async () => {
|
|
341
|
+
const page = await this.browser.newPage();
|
|
342
|
+
await page.evaluateOnNewDocument(
|
|
343
|
+
/* istanbul ignore next */
|
|
344
|
+
() => {
|
|
345
|
+
localStorage.clear();
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
/* istanbul ignore next -- @preserve */
|
|
349
|
+
this.options.logLevel !== "slient" && page.on("console", (e) => {
|
|
350
|
+
const key = e.type();
|
|
351
|
+
console[key].call(console[key], `${key} from puppeteer: `, ...e.args().map((i) => i.remoteObject()));
|
|
352
|
+
});
|
|
353
|
+
this.page = page;
|
|
354
|
+
this.operater = new Operater(page);
|
|
355
|
+
resolve(page);
|
|
356
|
+
})();
|
|
357
|
+
});
|
|
22
358
|
}
|
|
359
|
+
return this._page;
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
//#endregion
|
|
363
|
+
//#region packages/test/src/interrupter.ts
|
|
364
|
+
/**
|
|
365
|
+
* 实现的目的:
|
|
366
|
+
* 这是一段代码使用`await interrupter`调度器
|
|
367
|
+
* 永远等待它,直到它上面有任何代码执行了`interrupter.next()`
|
|
368
|
+
* 不论它是同步,微任务,异步执行,之后才会执行它后面的代码
|
|
369
|
+
*/
|
|
370
|
+
var Interrupter = class Interrupter {
|
|
371
|
+
static of(options) {
|
|
372
|
+
return new Interrupter(options);
|
|
373
|
+
}
|
|
374
|
+
options = {};
|
|
375
|
+
_success;
|
|
376
|
+
_fail;
|
|
377
|
+
_task;
|
|
378
|
+
_finish = false;
|
|
379
|
+
constructor(options) {
|
|
380
|
+
if (options) this.options = options;
|
|
381
|
+
this._generateTask();
|
|
382
|
+
}
|
|
383
|
+
_generateTask = () => {
|
|
384
|
+
this._task = new Promise((resolve, reject) => {
|
|
385
|
+
this._success = (value) => {
|
|
386
|
+
this._fail = void 0;
|
|
387
|
+
resolve(value);
|
|
388
|
+
};
|
|
389
|
+
this._fail = (value) => {
|
|
390
|
+
this._success = void 0;
|
|
391
|
+
reject(value);
|
|
392
|
+
};
|
|
393
|
+
});
|
|
394
|
+
};
|
|
395
|
+
next = async (v) => {
|
|
396
|
+
if (!this._finish) {
|
|
397
|
+
this._success?.(v);
|
|
398
|
+
await this._task;
|
|
399
|
+
await Promise.resolve();
|
|
400
|
+
this._generateTask();
|
|
401
|
+
} else await this._task;
|
|
402
|
+
};
|
|
403
|
+
nextWithError = async (v) => {
|
|
404
|
+
if (!this._finish) {
|
|
405
|
+
this._fail?.(v);
|
|
406
|
+
try {
|
|
407
|
+
await this._task;
|
|
408
|
+
} catch {
|
|
409
|
+
await Promise.resolve();
|
|
410
|
+
this._generateTask();
|
|
411
|
+
}
|
|
412
|
+
} else await this._task;
|
|
413
|
+
};
|
|
414
|
+
finish = (v) => {
|
|
415
|
+
this._success?.(v);
|
|
416
|
+
this._finish = true;
|
|
417
|
+
return this;
|
|
418
|
+
};
|
|
419
|
+
finishWithError = (v) => {
|
|
420
|
+
this._fail?.(v);
|
|
421
|
+
this._finish = true;
|
|
422
|
+
return this;
|
|
423
|
+
};
|
|
424
|
+
then(resolve, reject) {
|
|
425
|
+
return this._task.then(resolve, reject);
|
|
426
|
+
}
|
|
427
|
+
catch(callback) {
|
|
428
|
+
return this._task.catch(callback);
|
|
429
|
+
}
|
|
430
|
+
finally(callback) {
|
|
431
|
+
return this._task.finally(callback);
|
|
23
432
|
}
|
|
24
|
-
n.default = e;
|
|
25
|
-
return Object.freeze(n);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const childProcess__namespace = /*#__PURE__*/_interopNamespaceDefault(childProcess);
|
|
29
|
-
const http__namespace = /*#__PURE__*/_interopNamespaceDefault(http);
|
|
30
|
-
const os__namespace = /*#__PURE__*/_interopNamespaceDefault(os);
|
|
31
|
-
|
|
32
|
-
const { LOCAL_COMMAND_MAP } = devShared.Shell;
|
|
33
|
-
const KEY_MAP = {
|
|
34
|
-
DOWN: "\x1B[B",
|
|
35
|
-
UP: "\x1B[A",
|
|
36
|
-
ENTER: "\r",
|
|
37
|
-
// return;
|
|
38
|
-
SPACE: ""
|
|
39
433
|
};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
complete: (
|
|
65
|
-
/* istanbul ignore next */
|
|
66
|
-
() => {
|
|
67
|
-
}
|
|
68
|
-
)
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
_handleEnd(fn) {
|
|
72
|
-
return (e) => {
|
|
73
|
-
this.isClose = true;
|
|
74
|
-
const { code, error } = e;
|
|
75
|
-
this.code = code;
|
|
76
|
-
this.error = error;
|
|
77
|
-
fn({
|
|
78
|
-
...e,
|
|
79
|
-
stdout: this.stdout,
|
|
80
|
-
stderr: this.stderr
|
|
81
|
-
});
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
start(command, args) {
|
|
85
|
-
const SPACE = " ";
|
|
86
|
-
const [command$, ...args$] = (command + SPACE + args.join(SPACE)).replace(/\s+/g, SPACE).split(SPACE).filter((i) => !!i).map((i) => LOCAL_COMMAND_MAP[i] || i);
|
|
87
|
-
const emitter = childProcess__namespace.spawn(command$, args$, {
|
|
88
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
89
|
-
});
|
|
90
|
-
emitter.on("close", (code) => {
|
|
91
|
-
if (code !== 0) {
|
|
92
|
-
this.reject({ code });
|
|
93
|
-
} else {
|
|
94
|
-
this.resolve({ code });
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
emitter.on(
|
|
98
|
-
"error",
|
|
99
|
-
/* istanbul ignore next */
|
|
100
|
-
(error) => {
|
|
101
|
-
!process.exitCode && (process.exitCode = 1);
|
|
102
|
-
this.reject({ code: process.exitCode, error });
|
|
103
|
-
}
|
|
104
|
-
);
|
|
105
|
-
emitter.stdout.on("data", (e) => {
|
|
106
|
-
this.stdout += e.toString();
|
|
107
|
-
this.schedule.complete();
|
|
108
|
-
});
|
|
109
|
-
emitter.stderr.on(
|
|
110
|
-
"data",
|
|
111
|
-
/* istanbul ignore next */
|
|
112
|
-
(e) => this.stderr += e.toString()
|
|
113
|
-
);
|
|
114
|
-
return emitter;
|
|
115
|
-
}
|
|
116
|
-
async stop() {
|
|
117
|
-
await this.schedule.target;
|
|
118
|
-
if (!this.isClose) {
|
|
119
|
-
this.emitter.stdin.end();
|
|
120
|
-
this.isClose = true;
|
|
121
|
-
}
|
|
122
|
-
const response = await this.target;
|
|
123
|
-
return response;
|
|
124
|
-
}
|
|
125
|
-
async press(key, timeout = 200) {
|
|
126
|
-
if (!key || this.isClose) return;
|
|
127
|
-
await this.schedule.target;
|
|
128
|
-
this.schedule.target = new Promise((resolve) => {
|
|
129
|
-
this.schedule.complete = resolve;
|
|
130
|
-
});
|
|
131
|
-
await new Promise((resolve) => {
|
|
132
|
-
this.emitter.stdin.write(
|
|
133
|
-
KEY_MAP[key.toUpperCase()] || key,
|
|
134
|
-
"utf8",
|
|
135
|
-
resolve
|
|
136
|
-
);
|
|
137
|
-
});
|
|
138
|
-
await new Promise((_) => setTimeout(_, timeout));
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
class Operater {
|
|
143
|
-
page;
|
|
144
|
-
constructor(v) {
|
|
145
|
-
this.page = v;
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* @param selector ~
|
|
149
|
-
* @param options ~
|
|
150
|
-
*/
|
|
151
|
-
async click(selector, options) {
|
|
152
|
-
await this.page.click(selector, options);
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* @param selector ~
|
|
156
|
-
* @returns ~
|
|
157
|
-
*/
|
|
158
|
-
async count(selector) {
|
|
159
|
-
return (await this.page.$$(selector)).length;
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* @param selector ~
|
|
163
|
-
* @returns ~
|
|
164
|
-
*/
|
|
165
|
-
async text(selector) {
|
|
166
|
-
return await this.page.$eval(selector, (node) => node.textContent);
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* @param selector ~
|
|
170
|
-
* @returns ~
|
|
171
|
-
*/
|
|
172
|
-
async value(selector) {
|
|
173
|
-
return await this.page.$eval(selector, (node) => node.value);
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* @param selector ~
|
|
177
|
-
* @returns ~
|
|
178
|
-
*/
|
|
179
|
-
async html(selector) {
|
|
180
|
-
return await this.page.$eval(selector, (node) => node.innerHTML);
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* @param selector ~
|
|
184
|
-
* @returns ~
|
|
185
|
-
*/
|
|
186
|
-
async classList(selector) {
|
|
187
|
-
return await this.page.$eval(selector, (node) => [...node.classList]);
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* @param selector ~
|
|
191
|
-
* @returns ~
|
|
192
|
-
*/
|
|
193
|
-
async children(selector) {
|
|
194
|
-
return await this.page.$eval(selector, (node) => [...node.children]);
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* @param selector ~
|
|
198
|
-
* @returns ~
|
|
199
|
-
*/
|
|
200
|
-
async isVisible(selector) {
|
|
201
|
-
const display = await this.page.$eval(selector, (node) => {
|
|
202
|
-
return window.getComputedStyle(node).display;
|
|
203
|
-
});
|
|
204
|
-
return display !== "none";
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
*
|
|
208
|
-
* @param selector ~
|
|
209
|
-
* @returns ~
|
|
210
|
-
*/
|
|
211
|
-
async isChecked(selector) {
|
|
212
|
-
return await this.page.$eval(
|
|
213
|
-
selector,
|
|
214
|
-
(node) => node.checked
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
*
|
|
219
|
-
* @param selector ~
|
|
220
|
-
* @returns ~
|
|
221
|
-
*/
|
|
222
|
-
async isFocused(selector) {
|
|
223
|
-
return await this.page.$eval(selector, (node) => node === document.activeElement);
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* @param selector ~
|
|
227
|
-
* @param value$ ~
|
|
228
|
-
* @returns ~
|
|
229
|
-
*/
|
|
230
|
-
async setValue(selector, value$) {
|
|
231
|
-
await this.page.$eval(
|
|
232
|
-
selector,
|
|
233
|
-
(node, value$$) => {
|
|
234
|
-
node.value = value$$;
|
|
235
|
-
node.dispatchEvent(new Event("input"));
|
|
236
|
-
},
|
|
237
|
-
value$
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* @param selector ~
|
|
242
|
-
* @param value$ ~
|
|
243
|
-
* @returns ~
|
|
244
|
-
*/
|
|
245
|
-
async typeValue(selector, value$) {
|
|
246
|
-
const el = await this.page.$(selector);
|
|
247
|
-
await el.evaluate((node) => node.value = "");
|
|
248
|
-
await el.type(value$);
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* @param selector ~
|
|
252
|
-
* @param value$ ~
|
|
253
|
-
* @returns ~
|
|
254
|
-
*/
|
|
255
|
-
async enterValue(selector, value$) {
|
|
256
|
-
const el = await this.page.$(selector);
|
|
257
|
-
await el.evaluate((node) => node.value = "");
|
|
258
|
-
await el.type(value$);
|
|
259
|
-
await el.press("Enter");
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* @param selector ~
|
|
263
|
-
* @returns ~
|
|
264
|
-
*/
|
|
265
|
-
async clearValue(selector) {
|
|
266
|
-
return await this.page.$eval(
|
|
267
|
-
selector,
|
|
268
|
-
(node) => {
|
|
269
|
-
node.value = "";
|
|
270
|
-
}
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
*
|
|
275
|
-
* @param time ~
|
|
276
|
-
* @returns ~
|
|
277
|
-
*/
|
|
278
|
-
sleep(time) {
|
|
279
|
-
return this.page.evaluate((time$) => {
|
|
280
|
-
return new Promise((r) => {
|
|
281
|
-
setTimeout(r, time$);
|
|
282
|
-
});
|
|
283
|
-
}, time);
|
|
284
|
-
}
|
|
285
|
-
nextFrame() {
|
|
286
|
-
return this.page.evaluate(() => {
|
|
287
|
-
return new Promise((resolve) => {
|
|
288
|
-
requestAnimationFrame(() => {
|
|
289
|
-
requestAnimationFrame(resolve);
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
class Launch {
|
|
297
|
-
browser;
|
|
298
|
-
page;
|
|
299
|
-
operater;
|
|
300
|
-
_browser;
|
|
301
|
-
_page;
|
|
302
|
-
puppeteerOptions;
|
|
303
|
-
options;
|
|
304
|
-
constructor(options) {
|
|
305
|
-
this.options = options || { logLevel: "slient" };
|
|
306
|
-
this.operater = new Proxy({}, {
|
|
307
|
-
get: () => {
|
|
308
|
-
throw new Error("operater is not defined. create* invote first");
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
this.browser = new Proxy({}, {
|
|
312
|
-
get: () => {
|
|
313
|
-
throw new Error("browser is not defined. createBrowser invote first");
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
this.page = new Proxy({}, {
|
|
317
|
-
get: () => {
|
|
318
|
-
throw new Error("page is not defined. createPage invote first");
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
this.puppeteerOptions = process.env.CI ? { args: ["--no-sandbox", "--disable-setuid-sandbox"] } : {};
|
|
322
|
-
}
|
|
323
|
-
createBrowser(force) {
|
|
324
|
-
if (force || !this._browser) {
|
|
325
|
-
if (force && this._browser) {
|
|
326
|
-
this._browser.then((browser) => {
|
|
327
|
-
browser.isConnected() && browser.close();
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
this._browser = puppeteer.launch({
|
|
331
|
-
...this.puppeteerOptions,
|
|
332
|
-
headless: true
|
|
333
|
-
});
|
|
334
|
-
this._browser.then((browser) => {
|
|
335
|
-
this.browser = browser;
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
return this._browser;
|
|
339
|
-
}
|
|
340
|
-
async createPage(force) {
|
|
341
|
-
await this.createBrowser();
|
|
342
|
-
if (force || !this._page) {
|
|
343
|
-
if (force && this._page) {
|
|
344
|
-
this._page.then((page) => {
|
|
345
|
-
!page.isClosed() && page.close();
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
this._page = new Promise((resolve) => {
|
|
349
|
-
(async () => {
|
|
350
|
-
const page = await this.browser.newPage();
|
|
351
|
-
await page.evaluateOnNewDocument(
|
|
352
|
-
/* istanbul ignore next */
|
|
353
|
-
() => {
|
|
354
|
-
localStorage.clear();
|
|
355
|
-
}
|
|
356
|
-
);
|
|
357
|
-
this.options.logLevel !== "slient" && page.on("console", (e) => {
|
|
358
|
-
const key = e.type();
|
|
359
|
-
console[key].call(console[key], `${key} from puppeteer: `, ...e.args().map((i) => i.remoteObject()));
|
|
360
|
-
});
|
|
361
|
-
this.page = page;
|
|
362
|
-
this.operater = new Operater(page);
|
|
363
|
-
resolve(page);
|
|
364
|
-
})();
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
return this._page;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
class Interrupter {
|
|
372
|
-
static of(options) {
|
|
373
|
-
return new Interrupter(options);
|
|
374
|
-
}
|
|
375
|
-
options = {};
|
|
376
|
-
_success;
|
|
377
|
-
_fail;
|
|
378
|
-
_task;
|
|
379
|
-
_finish = false;
|
|
380
|
-
constructor(options) {
|
|
381
|
-
if (options) {
|
|
382
|
-
this.options = options;
|
|
383
|
-
}
|
|
384
|
-
this._generateTask();
|
|
385
|
-
}
|
|
386
|
-
_generateTask = () => {
|
|
387
|
-
this._task = new Promise((resolve, reject) => {
|
|
388
|
-
this._success = (value) => {
|
|
389
|
-
this._fail = void 0;
|
|
390
|
-
resolve(value);
|
|
391
|
-
};
|
|
392
|
-
this._fail = (value) => {
|
|
393
|
-
this._success = void 0;
|
|
394
|
-
reject(value);
|
|
395
|
-
};
|
|
396
|
-
});
|
|
397
|
-
};
|
|
398
|
-
next = async (v) => {
|
|
399
|
-
if (!this._finish) {
|
|
400
|
-
this._success?.(v);
|
|
401
|
-
await this._task;
|
|
402
|
-
await Promise.resolve();
|
|
403
|
-
this._generateTask();
|
|
404
|
-
} else {
|
|
405
|
-
await this._task;
|
|
406
|
-
}
|
|
407
|
-
};
|
|
408
|
-
nextWithError = async (v) => {
|
|
409
|
-
if (!this._finish) {
|
|
410
|
-
this._fail?.(v);
|
|
411
|
-
try {
|
|
412
|
-
await this._task;
|
|
413
|
-
} catch {
|
|
414
|
-
await Promise.resolve();
|
|
415
|
-
this._generateTask();
|
|
416
|
-
}
|
|
417
|
-
} else {
|
|
418
|
-
await this._task;
|
|
419
|
-
}
|
|
420
|
-
};
|
|
421
|
-
finish = (v) => {
|
|
422
|
-
this._success?.(v);
|
|
423
|
-
this._finish = true;
|
|
424
|
-
return this;
|
|
425
|
-
};
|
|
426
|
-
finishWithError = (v) => {
|
|
427
|
-
this._fail?.(v);
|
|
428
|
-
this._finish = true;
|
|
429
|
-
return this;
|
|
430
|
-
};
|
|
431
|
-
then(resolve, reject) {
|
|
432
|
-
return this._task.then(resolve, reject);
|
|
433
|
-
}
|
|
434
|
-
catch(callback) {
|
|
435
|
-
return this._task.catch(callback);
|
|
436
|
-
}
|
|
437
|
-
finally(callback) {
|
|
438
|
-
return this._task.finally(callback);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
const TIME_OUT = 60 * 1e3;
|
|
443
|
-
const impl = () => {
|
|
444
|
-
const launch = new Launch();
|
|
445
|
-
beforeAll(async () => {
|
|
446
|
-
await launch.createBrowser();
|
|
447
|
-
}, 2e4);
|
|
448
|
-
beforeEach(async () => {
|
|
449
|
-
await launch.createPage(true);
|
|
450
|
-
});
|
|
451
|
-
afterEach(async () => {
|
|
452
|
-
if (!launch.page.isClosed()) {
|
|
453
|
-
await launch.page.close();
|
|
454
|
-
}
|
|
455
|
-
});
|
|
456
|
-
afterAll(async () => {
|
|
457
|
-
if (launch.browser.isConnected()) {
|
|
458
|
-
await launch.browser.close();
|
|
459
|
-
}
|
|
460
|
-
});
|
|
461
|
-
return launch;
|
|
434
|
+
//#endregion
|
|
435
|
+
//#region packages/test/src/e2e.ts
|
|
436
|
+
var e2e_exports = /* @__PURE__ */ __exportAll({
|
|
437
|
+
TIME_OUT: () => TIME_OUT,
|
|
438
|
+
impl: () => impl
|
|
439
|
+
});
|
|
440
|
+
var TIME_OUT = 60 * 1e3;
|
|
441
|
+
var impl = () => {
|
|
442
|
+
const launch = new Launch();
|
|
443
|
+
beforeAll(async () => {
|
|
444
|
+
await launch.createBrowser();
|
|
445
|
+
}, 2e4);
|
|
446
|
+
beforeEach(async () => {
|
|
447
|
+
await launch.createPage(true);
|
|
448
|
+
});
|
|
449
|
+
afterEach(async () => {
|
|
450
|
+
/* istanbul ignore else -- @preserve */
|
|
451
|
+
if (!launch.page.isClosed()) await launch.page.close();
|
|
452
|
+
});
|
|
453
|
+
afterAll(async () => {
|
|
454
|
+
/* istanbul ignore else -- @preserve */
|
|
455
|
+
if (launch.browser.isConnected()) await launch.browser.close();
|
|
456
|
+
});
|
|
457
|
+
return launch;
|
|
462
458
|
};
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
const sleep = (s) => new Promise((_) => {
|
|
471
|
-
setTimeout(_, s || 0);
|
|
459
|
+
//#endregion
|
|
460
|
+
//#region packages/test/src/utils.ts
|
|
461
|
+
var utils_exports = /* @__PURE__ */ __exportAll({
|
|
462
|
+
def: () => def,
|
|
463
|
+
expectByPolling: () => expectByPolling,
|
|
464
|
+
sleep: () => sleep
|
|
472
465
|
});
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
466
|
+
var sleep = (s) => new Promise((_) => {
|
|
467
|
+
setTimeout(_, s || 0);
|
|
468
|
+
});
|
|
469
|
+
/**
|
|
470
|
+
* @param poll ~
|
|
471
|
+
* @param expected ~
|
|
472
|
+
* @param options ~
|
|
473
|
+
*/
|
|
474
|
+
var expectByPolling = async (poll, expected, options) => {
|
|
475
|
+
const { maxTries = 30, interval = 50, to } = options || {};
|
|
476
|
+
for (let tries = 0; tries < maxTries; tries++) {
|
|
477
|
+
const actual = await poll();
|
|
478
|
+
const allowMatch = (!to || to === "toMatch") && typeof expected === "string" && typeof actual === "string";
|
|
479
|
+
if (allowMatch && actual.indexOf(expected) > -1 || actual === expected || tries === maxTries - 1) {
|
|
480
|
+
allowMatch ? expect(actual).toMatch(expected) : expect(actual)[to || "toBe"](expected);
|
|
481
|
+
break;
|
|
482
|
+
} else await sleep(interval);
|
|
483
|
+
}
|
|
485
484
|
};
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
485
|
+
var def = (target, key, value, options) => {
|
|
486
|
+
return Object.defineProperty(target, key, {
|
|
487
|
+
value,
|
|
488
|
+
enumerable: false,
|
|
489
|
+
writable: true,
|
|
490
|
+
configurable: true,
|
|
491
|
+
...options
|
|
492
|
+
});
|
|
494
493
|
};
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
return ips[0] || "localhost";
|
|
494
|
+
//#endregion
|
|
495
|
+
//#region packages/test/src/server.ts
|
|
496
|
+
var server_exports = /* @__PURE__ */ __exportAll({
|
|
497
|
+
available: () => available,
|
|
498
|
+
host: () => host,
|
|
499
|
+
port: () => port
|
|
500
|
+
});
|
|
501
|
+
var defaultHost = "";
|
|
502
|
+
var host = (force) => {
|
|
503
|
+
if (!force && defaultHost) return defaultHost;
|
|
504
|
+
const ips = [];
|
|
505
|
+
const ntwk = os.networkInterfaces();
|
|
506
|
+
for (const k in ntwk) for (let i = 0; i < ntwk[k].length; i++) {
|
|
507
|
+
const _add = ntwk[k][i].address;
|
|
508
|
+
if (_add && _add.split(".").length == 4 && !ntwk[k][i].internal && ntwk[k][i].family == "IPv4") ips.push(ntwk[k][i].address);
|
|
509
|
+
}
|
|
510
|
+
/* istanbul ignore next -- @preserve */
|
|
511
|
+
return ips[0] || "localhost";
|
|
517
512
|
};
|
|
518
513
|
defaultHost = host();
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
514
|
+
var port = (host$ = defaultHost, port$ = 1024) => {
|
|
515
|
+
/* istanbul ignore next -- @preserve */
|
|
516
|
+
if (port$ < 1024) throw new Error("port < 1024");
|
|
517
|
+
return new Promise((resolve, reject) => {
|
|
518
|
+
const server = http.createServer();
|
|
519
|
+
server.unref();
|
|
520
|
+
server.on(
|
|
521
|
+
"error",
|
|
522
|
+
/* istanbul ignore next -- @preserve */
|
|
523
|
+
() => {
|
|
524
|
+
if (port$ >= 65535) reject();
|
|
525
|
+
else port(host$, port$ + 1).then(resolve).catch(reject);
|
|
526
|
+
}
|
|
527
|
+
);
|
|
528
|
+
server.listen({
|
|
529
|
+
host: host$,
|
|
530
|
+
port: port$
|
|
531
|
+
}, () => {
|
|
532
|
+
server.close(() => {
|
|
533
|
+
resolve(port$);
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
});
|
|
541
537
|
};
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
538
|
+
var available = async () => {
|
|
539
|
+
const host$ = host();
|
|
540
|
+
const port$ = await port(host$);
|
|
541
|
+
return {
|
|
542
|
+
host: host$,
|
|
543
|
+
port: port$,
|
|
544
|
+
baseUrl: `http://${host$}:${port$}`
|
|
545
|
+
};
|
|
550
546
|
};
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
}, Symbol.toStringTag, { value: 'Module' }));
|
|
558
|
-
|
|
547
|
+
//#endregion
|
|
548
|
+
//#region packages/test/src/index.ts
|
|
549
|
+
/**
|
|
550
|
+
* "export * as ___" syntax is not supported yet (API Extractor@7.x)
|
|
551
|
+
*/
|
|
552
|
+
//#endregion
|
|
559
553
|
exports.Command = Command;
|
|
560
|
-
exports
|
|
554
|
+
Object.defineProperty(exports, "E2E", {
|
|
555
|
+
enumerable: true,
|
|
556
|
+
get: function() {
|
|
557
|
+
return e2e_exports;
|
|
558
|
+
}
|
|
559
|
+
});
|
|
561
560
|
exports.Interrupter = Interrupter;
|
|
562
561
|
exports.Launch = Launch;
|
|
563
562
|
exports.Operater = Operater;
|
|
564
|
-
exports
|
|
565
|
-
|
|
563
|
+
Object.defineProperty(exports, "Server", {
|
|
564
|
+
enumerable: true,
|
|
565
|
+
get: function() {
|
|
566
|
+
return server_exports;
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
Object.defineProperty(exports, "Utils", {
|
|
570
|
+
enumerable: true,
|
|
571
|
+
get: function() {
|
|
572
|
+
return utils_exports;
|
|
573
|
+
}
|
|
574
|
+
});
|