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