@weapp-vite/miniprogram-automator 1.0.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -4
- package/dist/index.d.mts +248 -4
- package/dist/index.mjs +420 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
它同时服务于:
|
|
8
8
|
|
|
9
9
|
- `weapp-ide-cli` 的自动化能力
|
|
10
|
-
-
|
|
11
|
-
-
|
|
10
|
+
- 仓库内小程序开发者工具相关 e2e 测试
|
|
11
|
+
- 需要直接连接小程序开发者工具自动化协议的 Node 工具
|
|
12
12
|
|
|
13
13
|
## 2. 特性
|
|
14
14
|
|
|
15
15
|
- 对齐官方常见对象模型:`MiniProgram`、`Page`、`Element`、`Native`
|
|
16
16
|
- 提供 `Launcher` 用于启动、连接和复用 DevTools 会话
|
|
17
|
+
- 支持按平台选择自动化后端,默认微信,百度智能小程序提供轻量 TypeScript runtime
|
|
17
18
|
- 支持截图、输入、滚动、点击、页面跳转等自动化操作
|
|
18
19
|
- 默认输出现代 ESM 与完整类型声明
|
|
19
20
|
- 内置二维码打印与解码辅助能力,便于配合登录、连接流程调试
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
pnpm add -D @weapp-vite/miniprogram-automator
|
|
26
27
|
```
|
|
27
28
|
|
|
28
|
-
>
|
|
29
|
+
> **注意**:运行前仍需要本机安装对应平台的开发者工具,并开启自动化所需服务能力。
|
|
29
30
|
|
|
30
31
|
## 4. 快速开始
|
|
31
32
|
|
|
@@ -50,19 +51,52 @@ import { Launcher } from '@weapp-vite/miniprogram-automator'
|
|
|
50
51
|
|
|
51
52
|
const launcher = new Launcher()
|
|
52
53
|
const miniProgram = await launcher.launch({
|
|
54
|
+
platform: 'wechat',
|
|
53
55
|
projectPath: './dist/build/mp-weixin',
|
|
54
56
|
})
|
|
55
57
|
|
|
56
58
|
await miniProgram.reLaunch('/pages/index/index')
|
|
57
59
|
```
|
|
58
60
|
|
|
59
|
-
### 4.3
|
|
61
|
+
### 4.3 启动百度智能小程序
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { Launcher } from '@weapp-vite/miniprogram-automator'
|
|
65
|
+
|
|
66
|
+
const launcher = new Launcher()
|
|
67
|
+
const smartProgram = await launcher.launch({
|
|
68
|
+
platform: 'swan',
|
|
69
|
+
cliPath: '/Applications/百度开发者工具.app/Contents/MacOS/cli',
|
|
70
|
+
projectPath: './dist/build/mp-baidu',
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
await smartProgram.reLaunch('/pages/index/index')
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`platform: 'baidu'` 也会按百度智能小程序处理。
|
|
77
|
+
|
|
78
|
+
如果需要使用百度智能小程序自动化的 runtime 能力,可以直接访问内置入口:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { SmartappAutomator } from '@weapp-vite/miniprogram-automator'
|
|
82
|
+
|
|
83
|
+
const devices = await SmartappAutomator.devices?.('simulator')
|
|
84
|
+
const device = await SmartappAutomator.launch({
|
|
85
|
+
deviceType: 'simulator',
|
|
86
|
+
wsEndpoint: 'ws://127.0.0.1:9420',
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
await device.close()
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 4.4 使用页面与元素对象
|
|
60
93
|
|
|
61
94
|
```ts
|
|
62
95
|
import { Launcher } from '@weapp-vite/miniprogram-automator'
|
|
63
96
|
|
|
64
97
|
const launcher = new Launcher()
|
|
65
98
|
const miniProgram = await launcher.launch({
|
|
99
|
+
platform: 'wechat',
|
|
66
100
|
projectPath: './dist/build/mp-weixin',
|
|
67
101
|
})
|
|
68
102
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
2
|
import WebSocket from "ws";
|
|
3
|
+
import { Buffer } from "node:buffer";
|
|
3
4
|
|
|
5
|
+
//#region src/smartapp/file.d.ts
|
|
6
|
+
declare function mkdir(dir: string): Promise<void>;
|
|
7
|
+
declare function rmdir(dir: string): Promise<void>;
|
|
8
|
+
declare function wget(url: string, targetPath: string): Promise<void>;
|
|
9
|
+
declare function changeProjectSwanJson(projectPath: string, values: Record<string, unknown>): Promise<void>;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/smartapp/image.d.ts
|
|
12
|
+
declare function drawBorder(imageBuffer: Buffer): Promise<Buffer<ArrayBufferLike>>;
|
|
13
|
+
declare function extract(imageBuffer: Buffer): Promise<Buffer<ArrayBufferLike>>;
|
|
14
|
+
declare function border(imageBuffer: Buffer): Promise<Buffer<ArrayBufferLike>>;
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/smartapp/log.d.ts
|
|
17
|
+
/**
|
|
18
|
+
* @file 百度智能小程序自动化日志工具。
|
|
19
|
+
*/
|
|
20
|
+
interface SmartappLogger {
|
|
21
|
+
error: (message: string) => void;
|
|
22
|
+
info: (message: string) => void;
|
|
23
|
+
warn: (message: string) => void;
|
|
24
|
+
}
|
|
25
|
+
declare function set(_dir: string, label?: string): SmartappLogger;
|
|
26
|
+
declare function get(label?: string): SmartappLogger;
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/smartapp/time.d.ts
|
|
29
|
+
/**
|
|
30
|
+
* @file 百度智能小程序自动化时间工具。
|
|
31
|
+
*/
|
|
32
|
+
declare function currentTimestamp(): number;
|
|
33
|
+
declare function delay(ms: number): Promise<void>;
|
|
34
|
+
//#endregion
|
|
4
35
|
//#region src/Transport.d.ts
|
|
5
36
|
/** Transport 的实现。 */
|
|
6
37
|
declare class Transport extends EventEmitter {
|
|
@@ -268,23 +299,210 @@ declare class MiniProgram extends EventEmitter {
|
|
|
268
299
|
private onExceptionThrown;
|
|
269
300
|
}
|
|
270
301
|
//#endregion
|
|
302
|
+
//#region src/smartapp/types.d.ts
|
|
303
|
+
type SmartappDeviceType = 'android' | 'iOS' | 'web' | 'devtools' | 'simulator';
|
|
304
|
+
type SmartappConnectType = 'usb' | 'wifi' | 'newBaiduCloud' | 'mtpaas';
|
|
305
|
+
interface SmartappLaunchOptions {
|
|
306
|
+
deviceType?: SmartappDeviceType;
|
|
307
|
+
connectType?: SmartappConnectType;
|
|
308
|
+
timeout?: number;
|
|
309
|
+
headless?: boolean;
|
|
310
|
+
mtpaas?: Record<string, unknown>;
|
|
311
|
+
devtoolsPath?: string;
|
|
312
|
+
cliPath?: string;
|
|
313
|
+
projectPath?: string;
|
|
314
|
+
swanCoreVersion?: string;
|
|
315
|
+
projectMinVersion?: string;
|
|
316
|
+
deviceId?: string;
|
|
317
|
+
browserPath?: string;
|
|
318
|
+
wdaProjPath?: string;
|
|
319
|
+
isRecord?: boolean;
|
|
320
|
+
containerInfo?: unknown;
|
|
321
|
+
cookies?: unknown;
|
|
322
|
+
coverage?: boolean;
|
|
323
|
+
webModel?: string;
|
|
324
|
+
}
|
|
325
|
+
interface SmartappDevicesResult {
|
|
326
|
+
[deviceId: string]: {
|
|
327
|
+
status: number;
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
interface SmartappDriver {
|
|
331
|
+
miniProgram?: MiniProgram;
|
|
332
|
+
close?: () => Promise<void> | void;
|
|
333
|
+
currentPagePath?: string;
|
|
334
|
+
source?: () => Promise<string>;
|
|
335
|
+
screenshot?: () => Promise<Buffer>;
|
|
336
|
+
}
|
|
337
|
+
interface QueryOptions {
|
|
338
|
+
loop?: number;
|
|
339
|
+
duration?: number;
|
|
340
|
+
retry?: number;
|
|
341
|
+
}
|
|
342
|
+
interface ScreenshotOptions {
|
|
343
|
+
path?: string;
|
|
344
|
+
compressionLevel?: number;
|
|
345
|
+
}
|
|
346
|
+
//#endregion
|
|
347
|
+
//#region src/smartapp/Element.d.ts
|
|
348
|
+
declare class SmartappElement {
|
|
349
|
+
private readonly element;
|
|
350
|
+
selectors: string;
|
|
351
|
+
index: number;
|
|
352
|
+
id: string;
|
|
353
|
+
tagName: string;
|
|
354
|
+
constructor(element: Element | null, selectors?: string, index?: number);
|
|
355
|
+
scrollIntoView(options?: {
|
|
356
|
+
wait?: number;
|
|
357
|
+
}): Promise<void>;
|
|
358
|
+
boundingBox(): Promise<any>;
|
|
359
|
+
tap(options?: {
|
|
360
|
+
count?: number;
|
|
361
|
+
wait?: number;
|
|
362
|
+
}): Promise<void>;
|
|
363
|
+
input(text: string, options?: {
|
|
364
|
+
wait?: number;
|
|
365
|
+
}): Promise<void>;
|
|
366
|
+
text(): Promise<any>;
|
|
367
|
+
value(): Promise<any>;
|
|
368
|
+
attribute(name: string): Promise<any>;
|
|
369
|
+
property(name: string): Promise<any>;
|
|
370
|
+
style(style: string): Promise<any>;
|
|
371
|
+
longpress(options?: {
|
|
372
|
+
duration?: number;
|
|
373
|
+
}): Promise<void>;
|
|
374
|
+
move(options?: {
|
|
375
|
+
wait?: number;
|
|
376
|
+
}): Promise<void>;
|
|
377
|
+
screenshot(options?: ScreenshotOptions): Promise<Buffer<ArrayBuffer>>;
|
|
378
|
+
}
|
|
379
|
+
//#endregion
|
|
380
|
+
//#region src/smartapp/Page.d.ts
|
|
381
|
+
declare class SmartappPage {
|
|
382
|
+
private readonly page;
|
|
383
|
+
path: string;
|
|
384
|
+
query: Record<string, unknown>;
|
|
385
|
+
uri: string;
|
|
386
|
+
constructor(page: Page | null, path?: string, query?: Record<string, unknown>);
|
|
387
|
+
data(path?: string): Promise<any>;
|
|
388
|
+
setData(data: Record<string, unknown>): Promise<void>;
|
|
389
|
+
callMethod(method: string, ...args: unknown[]): Promise<any>;
|
|
390
|
+
}
|
|
391
|
+
//#endregion
|
|
392
|
+
//#region src/smartapp/App.d.ts
|
|
393
|
+
declare class SmartappApp {
|
|
394
|
+
private readonly miniProgram;
|
|
395
|
+
appKey: string;
|
|
396
|
+
constructor(miniProgram: MiniProgram | null, appKey: string);
|
|
397
|
+
goto(path?: string, options?: {
|
|
398
|
+
retry?: number;
|
|
399
|
+
timeout?: number;
|
|
400
|
+
}): Promise<SmartappPage>;
|
|
401
|
+
screenshot(options?: ScreenshotOptions): Promise<any>;
|
|
402
|
+
currentPage(): Promise<SmartappPage>;
|
|
403
|
+
data(): Promise<any>;
|
|
404
|
+
tabs(): Promise<never[]>;
|
|
405
|
+
pages(): Promise<any>;
|
|
406
|
+
getSystemInfo(): Promise<any>;
|
|
407
|
+
source(): Promise<string>;
|
|
408
|
+
swan(method: string, ...args: unknown[]): Promise<any>;
|
|
409
|
+
getAbTestInfo(): Promise<{}>;
|
|
410
|
+
$(selectors: string, options?: QueryOptions): Promise<SmartappElement | null>;
|
|
411
|
+
$$(selectors: string, options?: QueryOptions): Promise<any>;
|
|
412
|
+
$x(_expression: string): Promise<never[]>;
|
|
413
|
+
close(): Promise<void>;
|
|
414
|
+
}
|
|
415
|
+
//#endregion
|
|
416
|
+
//#region src/smartapp/Device.d.ts
|
|
417
|
+
declare class SmartappDevice {
|
|
418
|
+
type: string;
|
|
419
|
+
connectType: string;
|
|
420
|
+
id: string;
|
|
421
|
+
private readonly driver;
|
|
422
|
+
constructor(type: string, connectType: string, id: string, driver?: SmartappDriver);
|
|
423
|
+
source(options?: {
|
|
424
|
+
path?: string;
|
|
425
|
+
}): Promise<string>;
|
|
426
|
+
screenshot(options?: ScreenshotOptions): Promise<Buffer<ArrayBufferLike>>;
|
|
427
|
+
launchSmartapp(_container: string, appKey: string, path?: string): Promise<SmartappApp>;
|
|
428
|
+
getScreenSize(): Promise<{
|
|
429
|
+
height: number;
|
|
430
|
+
width: number;
|
|
431
|
+
}>;
|
|
432
|
+
terminateApp(): Promise<void>;
|
|
433
|
+
launchApp(): Promise<void>;
|
|
434
|
+
reLaunchApp(): Promise<void>;
|
|
435
|
+
install(): Promise<void>;
|
|
436
|
+
uninstall(): Promise<void>;
|
|
437
|
+
newSmartapp(_container: string, appKey: string): Promise<SmartappApp>;
|
|
438
|
+
tap(): Promise<void>;
|
|
439
|
+
swipe(): Promise<void>;
|
|
440
|
+
longpress(): Promise<void>;
|
|
441
|
+
$x(): Promise<never[]>;
|
|
442
|
+
home(): Promise<void>;
|
|
443
|
+
enter(): Promise<void>;
|
|
444
|
+
back(): Promise<void>;
|
|
445
|
+
isInstall(): Promise<boolean>;
|
|
446
|
+
close(): Promise<void>;
|
|
447
|
+
}
|
|
448
|
+
//#endregion
|
|
449
|
+
//#region src/smartapp/index.d.ts
|
|
450
|
+
declare function launch(options?: SmartappLaunchOptions & {
|
|
451
|
+
wsEndpoint?: string;
|
|
452
|
+
}): Promise<SmartappDevice>;
|
|
453
|
+
declare function connect(options: Record<string, unknown>): Promise<SmartappDevice>;
|
|
454
|
+
declare function devices(deviceType: string, _connectType?: string): Promise<SmartappDevicesResult>;
|
|
455
|
+
//#endregion
|
|
456
|
+
//#region src/platform.d.ts
|
|
457
|
+
/**
|
|
458
|
+
* @file 小程序自动化平台适配定义。
|
|
459
|
+
*/
|
|
460
|
+
type MiniprogramAutomatorPlatform = 'wechat' | 'swan' | 'baidu';
|
|
461
|
+
interface IExternalAutomatorModule {
|
|
462
|
+
launch: (options: Record<string, unknown>) => Promise<unknown>;
|
|
463
|
+
connect?: (options: Record<string, unknown>) => Promise<unknown>;
|
|
464
|
+
devices?: (deviceType: string, connectType?: string) => Promise<unknown>;
|
|
465
|
+
file?: unknown;
|
|
466
|
+
image?: unknown;
|
|
467
|
+
log?: unknown;
|
|
468
|
+
time?: unknown;
|
|
469
|
+
}
|
|
470
|
+
type NormalizedMiniprogramAutomatorPlatform = Exclude<MiniprogramAutomatorPlatform, 'baidu'>;
|
|
471
|
+
declare function normalizePlatform(platform?: MiniprogramAutomatorPlatform): NormalizedMiniprogramAutomatorPlatform;
|
|
472
|
+
//#endregion
|
|
271
473
|
//#region src/Launcher.d.ts
|
|
272
474
|
interface IConnectOptions {
|
|
273
475
|
wsEndpoint: string;
|
|
476
|
+
platform?: MiniprogramAutomatorPlatform;
|
|
274
477
|
}
|
|
275
478
|
/** ILaunchOptions 的类型定义。 */
|
|
276
479
|
interface ILaunchOptions {
|
|
480
|
+
platform?: MiniprogramAutomatorPlatform;
|
|
277
481
|
cliPath?: string;
|
|
482
|
+
connectType?: string;
|
|
483
|
+
deviceId?: string;
|
|
484
|
+
deviceType?: string;
|
|
485
|
+
devtoolsPath?: string;
|
|
278
486
|
timeout?: number;
|
|
279
487
|
port?: number;
|
|
280
488
|
account?: string;
|
|
281
489
|
ticket?: string;
|
|
282
490
|
projectConfig?: any;
|
|
283
|
-
projectPath
|
|
491
|
+
projectPath?: string;
|
|
492
|
+
projectMinVersion?: string;
|
|
493
|
+
swanCoreVersion?: string;
|
|
284
494
|
trustProject?: boolean;
|
|
285
495
|
args?: string[];
|
|
496
|
+
browserPath?: string;
|
|
497
|
+
containerInfo?: unknown;
|
|
498
|
+
cookies?: unknown;
|
|
286
499
|
cwd?: string;
|
|
500
|
+
headless?: boolean;
|
|
501
|
+
isRecord?: boolean;
|
|
502
|
+
mtpaas?: Record<string, unknown>;
|
|
287
503
|
runtimeProvider?: 'devtools' | 'headless';
|
|
504
|
+
wdaProjPath?: string;
|
|
505
|
+
webModel?: string;
|
|
288
506
|
}
|
|
289
507
|
interface ILauncherSessionMetadata {
|
|
290
508
|
port: number;
|
|
@@ -294,7 +512,7 @@ interface ILauncherSessionMetadata {
|
|
|
294
512
|
/** Launcher 的实现。 */
|
|
295
513
|
declare class Launcher {
|
|
296
514
|
launch(options: ILaunchOptions): Promise<any>;
|
|
297
|
-
connect(options: IConnectOptions): Promise<
|
|
515
|
+
connect(options: IConnectOptions): Promise<unknown>;
|
|
298
516
|
private extendProjectConfig;
|
|
299
517
|
private connectTool;
|
|
300
518
|
private resolveCliPath;
|
|
@@ -313,7 +531,7 @@ declare class Automator {
|
|
|
313
531
|
SliderElement: typeof SliderElement;
|
|
314
532
|
ContextElement: typeof ContextElement;
|
|
315
533
|
private launcher;
|
|
316
|
-
connect(options: IConnectOptions): Promise<
|
|
534
|
+
connect(options: IConnectOptions): Promise<unknown>;
|
|
317
535
|
launch(options: ILaunchOptions): Promise<any>;
|
|
318
536
|
}
|
|
319
537
|
//#endregion
|
|
@@ -327,4 +545,30 @@ declare function isPluginPath(p: string): boolean;
|
|
|
327
545
|
/** extractPluginId 的方法封装。 */
|
|
328
546
|
declare function extractPluginId(p: string): string;
|
|
329
547
|
//#endregion
|
|
330
|
-
|
|
548
|
+
//#region src/index.d.ts
|
|
549
|
+
declare const SmartappAutomator: {
|
|
550
|
+
connect: typeof connect;
|
|
551
|
+
devices: typeof devices;
|
|
552
|
+
file: {
|
|
553
|
+
changeProjectSwanJson: typeof changeProjectSwanJson;
|
|
554
|
+
mkdir: typeof mkdir;
|
|
555
|
+
rmdir: typeof rmdir;
|
|
556
|
+
wget: typeof wget;
|
|
557
|
+
};
|
|
558
|
+
image: {
|
|
559
|
+
border: typeof border;
|
|
560
|
+
drawBorder: typeof drawBorder;
|
|
561
|
+
extract: typeof extract;
|
|
562
|
+
};
|
|
563
|
+
launch: typeof launch;
|
|
564
|
+
log: {
|
|
565
|
+
get: typeof get;
|
|
566
|
+
set: typeof set;
|
|
567
|
+
};
|
|
568
|
+
time: {
|
|
569
|
+
currentTimestamp: typeof currentTimestamp;
|
|
570
|
+
delay: typeof delay;
|
|
571
|
+
};
|
|
572
|
+
};
|
|
573
|
+
//#endregion
|
|
574
|
+
export { Automator, Connection, ContextElement, CustomElement, Element, IConnectOptions, IExternalAutomatorModule, ILaunchOptions, ILauncherSessionMetadata, InputElement, Launcher, MiniProgram, MiniprogramAutomatorPlatform, MovableViewElement, Native, NormalizedMiniprogramAutomatorPlatform, Page, ScrollViewElement, SliderElement, SmartappAutomator, SwiperElement, SwitchElement, TextareaElement, Transport, decodeQrCode, extractPluginId, isPluginPath, normalizePlatform, printQrCode };
|
package/dist/index.mjs
CHANGED
|
@@ -8,6 +8,7 @@ import debug from "debug";
|
|
|
8
8
|
import WebSocket from "ws";
|
|
9
9
|
import fs from "node:fs/promises";
|
|
10
10
|
import { decodeQrCodeFromBase64, renderTerminalQrCode } from "@weapp-vite/qr";
|
|
11
|
+
import { Buffer } from "node:buffer";
|
|
11
12
|
//#region src/internal/compat/async.ts
|
|
12
13
|
/**
|
|
13
14
|
* @file 异步控制工具。
|
|
@@ -581,7 +582,7 @@ async function launchHeadlessAutomator(options) {
|
|
|
581
582
|
}
|
|
582
583
|
//#endregion
|
|
583
584
|
//#region package.json
|
|
584
|
-
var version = "1.0
|
|
585
|
+
var version = "1.1.0";
|
|
585
586
|
//#endregion
|
|
586
587
|
//#region src/Native.ts
|
|
587
588
|
/** Native 的实现。 */
|
|
@@ -1041,7 +1042,8 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1041
1042
|
logChangeRouteDebug(`poll-error method=${method} url=${url ?? "<none>"} error=${error instanceof Error ? error.message : String(error)}`);
|
|
1042
1043
|
}
|
|
1043
1044
|
try {
|
|
1044
|
-
const
|
|
1045
|
+
const stack = await this.pageStack();
|
|
1046
|
+
const stackTop = stack[stack.length - 1];
|
|
1045
1047
|
if (stackTop) {
|
|
1046
1048
|
lastPage = stackTop;
|
|
1047
1049
|
logChangeRouteDebug(`stack method=${method} url=${url ?? "<none>"} current=${stackTop.path}`);
|
|
@@ -1081,6 +1083,414 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1081
1083
|
};
|
|
1082
1084
|
};
|
|
1083
1085
|
//#endregion
|
|
1086
|
+
//#region src/platform.ts
|
|
1087
|
+
function normalizePlatform(platform = "wechat") {
|
|
1088
|
+
return platform === "baidu" ? "swan" : platform;
|
|
1089
|
+
}
|
|
1090
|
+
//#endregion
|
|
1091
|
+
//#region src/smartapp/errors.ts
|
|
1092
|
+
/**
|
|
1093
|
+
* @file 百度智能小程序自动化错误定义。
|
|
1094
|
+
*/
|
|
1095
|
+
var SmartappUnsupportedError = class extends Error {
|
|
1096
|
+
constructor(feature) {
|
|
1097
|
+
super(`${feature} is not available in the lightweight TypeScript smartapp runtime.`);
|
|
1098
|
+
this.name = "SmartappUnsupportedError";
|
|
1099
|
+
}
|
|
1100
|
+
};
|
|
1101
|
+
function unsupported(feature) {
|
|
1102
|
+
throw new SmartappUnsupportedError(feature);
|
|
1103
|
+
}
|
|
1104
|
+
//#endregion
|
|
1105
|
+
//#region src/smartapp/time.ts
|
|
1106
|
+
/**
|
|
1107
|
+
* @file 百度智能小程序自动化时间工具。
|
|
1108
|
+
*/
|
|
1109
|
+
function currentTimestamp() {
|
|
1110
|
+
return Date.now();
|
|
1111
|
+
}
|
|
1112
|
+
async function delay(ms) {
|
|
1113
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
1114
|
+
}
|
|
1115
|
+
const time = {
|
|
1116
|
+
currentTimestamp,
|
|
1117
|
+
delay
|
|
1118
|
+
};
|
|
1119
|
+
//#endregion
|
|
1120
|
+
//#region src/smartapp/Element.ts
|
|
1121
|
+
function getCoreElementId(element, selectors, index) {
|
|
1122
|
+
if (!element) return `${selectors}:${index}`;
|
|
1123
|
+
const elementId = Reflect.get(element, "id");
|
|
1124
|
+
return typeof elementId === "string" ? elementId : `${selectors}:${index}`;
|
|
1125
|
+
}
|
|
1126
|
+
function isInputCapableElement(element) {
|
|
1127
|
+
return typeof Reflect.get(element, "input") === "function";
|
|
1128
|
+
}
|
|
1129
|
+
var SmartappElement = class {
|
|
1130
|
+
id;
|
|
1131
|
+
tagName;
|
|
1132
|
+
constructor(element, selectors = "", index = 0) {
|
|
1133
|
+
this.element = element;
|
|
1134
|
+
this.selectors = selectors;
|
|
1135
|
+
this.index = index;
|
|
1136
|
+
this.id = getCoreElementId(element, selectors, index);
|
|
1137
|
+
this.tagName = element?.tagName || "";
|
|
1138
|
+
}
|
|
1139
|
+
async scrollIntoView(options = {}) {
|
|
1140
|
+
await delay(options.wait ?? 1e3);
|
|
1141
|
+
}
|
|
1142
|
+
async boundingBox() {
|
|
1143
|
+
if (!this.element) return null;
|
|
1144
|
+
return await this.element.offset();
|
|
1145
|
+
}
|
|
1146
|
+
async tap(options = {}) {
|
|
1147
|
+
const count = options.count ?? 1;
|
|
1148
|
+
for (let index = 0; index < count; index++) await this.element?.tap();
|
|
1149
|
+
await delay(options.wait ?? 1e3);
|
|
1150
|
+
}
|
|
1151
|
+
async input(text, options = {}) {
|
|
1152
|
+
if (this.element) {
|
|
1153
|
+
if (!isInputCapableElement(this.element)) throw new SmartappUnsupportedError(`element.input(${this.tagName || "unknown"})`);
|
|
1154
|
+
await this.element.input(text);
|
|
1155
|
+
}
|
|
1156
|
+
await delay(options.wait ?? 1e3);
|
|
1157
|
+
}
|
|
1158
|
+
async text() {
|
|
1159
|
+
return await this.element?.text();
|
|
1160
|
+
}
|
|
1161
|
+
async value() {
|
|
1162
|
+
return await this.property("value");
|
|
1163
|
+
}
|
|
1164
|
+
async attribute(name) {
|
|
1165
|
+
return await this.element?.attribute(name);
|
|
1166
|
+
}
|
|
1167
|
+
async property(name) {
|
|
1168
|
+
return await this.element?.property(name);
|
|
1169
|
+
}
|
|
1170
|
+
async style(style) {
|
|
1171
|
+
return await this.element?.property(style);
|
|
1172
|
+
}
|
|
1173
|
+
async longpress(options = {}) {
|
|
1174
|
+
await this.element?.longpress();
|
|
1175
|
+
await delay(options.duration ?? 0);
|
|
1176
|
+
}
|
|
1177
|
+
async move(options = {}) {
|
|
1178
|
+
await delay(options.wait ?? 1e3);
|
|
1179
|
+
}
|
|
1180
|
+
async screenshot(options = {}) {
|
|
1181
|
+
return Buffer.alloc(0);
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
//#endregion
|
|
1185
|
+
//#region src/smartapp/Page.ts
|
|
1186
|
+
var SmartappPage = class {
|
|
1187
|
+
path;
|
|
1188
|
+
query;
|
|
1189
|
+
uri;
|
|
1190
|
+
constructor(page, path = "", query = {}) {
|
|
1191
|
+
this.page = page;
|
|
1192
|
+
this.path = page?.path || path;
|
|
1193
|
+
this.query = page?.query || query;
|
|
1194
|
+
const queryText = new URLSearchParams(this.query).toString();
|
|
1195
|
+
this.uri = queryText ? `${this.path}?${queryText}` : this.path;
|
|
1196
|
+
}
|
|
1197
|
+
async data(path) {
|
|
1198
|
+
return await this.page?.data(path);
|
|
1199
|
+
}
|
|
1200
|
+
async setData(data) {
|
|
1201
|
+
await this.page?.setData(data);
|
|
1202
|
+
}
|
|
1203
|
+
async callMethod(method, ...args) {
|
|
1204
|
+
return await this.page?.callMethod(method, ...args);
|
|
1205
|
+
}
|
|
1206
|
+
};
|
|
1207
|
+
//#endregion
|
|
1208
|
+
//#region src/smartapp/App.ts
|
|
1209
|
+
var SmartappApp = class {
|
|
1210
|
+
constructor(miniProgram, appKey) {
|
|
1211
|
+
this.miniProgram = miniProgram;
|
|
1212
|
+
this.appKey = appKey;
|
|
1213
|
+
}
|
|
1214
|
+
async goto(path = "", options = {}) {
|
|
1215
|
+
const retry = options.retry ?? 0;
|
|
1216
|
+
let lastError;
|
|
1217
|
+
for (let count = 0; count <= retry; count++) try {
|
|
1218
|
+
return new SmartappPage(await this.miniProgram?.reLaunch(path) || null, path);
|
|
1219
|
+
} catch (error) {
|
|
1220
|
+
lastError = error;
|
|
1221
|
+
}
|
|
1222
|
+
throw lastError;
|
|
1223
|
+
}
|
|
1224
|
+
async screenshot(options = {}) {
|
|
1225
|
+
return await this.miniProgram?.screenshot(options);
|
|
1226
|
+
}
|
|
1227
|
+
async currentPage() {
|
|
1228
|
+
return new SmartappPage(await this.miniProgram?.currentPage() || null);
|
|
1229
|
+
}
|
|
1230
|
+
async data() {
|
|
1231
|
+
return await this.miniProgram?.callWxMethod("getSystemInfo", {});
|
|
1232
|
+
}
|
|
1233
|
+
async tabs() {
|
|
1234
|
+
return [];
|
|
1235
|
+
}
|
|
1236
|
+
async pages() {
|
|
1237
|
+
return await this.miniProgram?.pageStack();
|
|
1238
|
+
}
|
|
1239
|
+
async getSystemInfo() {
|
|
1240
|
+
return await this.miniProgram?.callWxMethod("getSystemInfo", {});
|
|
1241
|
+
}
|
|
1242
|
+
async source() {
|
|
1243
|
+
const page = await this.miniProgram?.currentPage();
|
|
1244
|
+
return JSON.stringify(await page?.data());
|
|
1245
|
+
}
|
|
1246
|
+
async swan(method, ...args) {
|
|
1247
|
+
return await this.miniProgram?.callWxMethod(method, ...args);
|
|
1248
|
+
}
|
|
1249
|
+
async getAbTestInfo() {
|
|
1250
|
+
return {};
|
|
1251
|
+
}
|
|
1252
|
+
async $(selectors, options = {}) {
|
|
1253
|
+
await delay(options.duration ?? 0);
|
|
1254
|
+
const element = await (await this.miniProgram?.currentPage())?.$(selectors);
|
|
1255
|
+
return element ? new SmartappElement(element, selectors, 0) : null;
|
|
1256
|
+
}
|
|
1257
|
+
async $$(selectors, options = {}) {
|
|
1258
|
+
await delay(options.duration ?? 0);
|
|
1259
|
+
return (await (await this.miniProgram?.currentPage())?.$$(selectors) || []).map((element, index) => new SmartappElement(element, selectors, index));
|
|
1260
|
+
}
|
|
1261
|
+
async $x(_expression) {
|
|
1262
|
+
return [];
|
|
1263
|
+
}
|
|
1264
|
+
async close() {
|
|
1265
|
+
this.miniProgram?.disconnect();
|
|
1266
|
+
}
|
|
1267
|
+
};
|
|
1268
|
+
//#endregion
|
|
1269
|
+
//#region src/smartapp/Device.ts
|
|
1270
|
+
var SmartappDevice = class {
|
|
1271
|
+
constructor(type, connectType, id, driver = {}) {
|
|
1272
|
+
this.type = type;
|
|
1273
|
+
this.connectType = connectType;
|
|
1274
|
+
this.id = id;
|
|
1275
|
+
this.driver = driver;
|
|
1276
|
+
}
|
|
1277
|
+
async source(options = {}) {
|
|
1278
|
+
if (this.driver.source) return await this.driver.source();
|
|
1279
|
+
return "";
|
|
1280
|
+
}
|
|
1281
|
+
async screenshot(options = {}) {
|
|
1282
|
+
if (this.driver.screenshot) return await this.driver.screenshot();
|
|
1283
|
+
return Buffer.alloc(0);
|
|
1284
|
+
}
|
|
1285
|
+
async launchSmartapp(_container, appKey, path = "") {
|
|
1286
|
+
const app = await this.newSmartapp(_container, appKey);
|
|
1287
|
+
if (path) await app.goto(path);
|
|
1288
|
+
return app;
|
|
1289
|
+
}
|
|
1290
|
+
async getScreenSize() {
|
|
1291
|
+
return {
|
|
1292
|
+
height: 0,
|
|
1293
|
+
width: 0
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
async terminateApp() {
|
|
1297
|
+
unsupported("device.terminateApp");
|
|
1298
|
+
}
|
|
1299
|
+
async launchApp() {
|
|
1300
|
+
unsupported("device.launchApp");
|
|
1301
|
+
}
|
|
1302
|
+
async reLaunchApp() {
|
|
1303
|
+
unsupported("device.reLaunchApp");
|
|
1304
|
+
}
|
|
1305
|
+
async install() {
|
|
1306
|
+
unsupported("device.install");
|
|
1307
|
+
}
|
|
1308
|
+
async uninstall() {
|
|
1309
|
+
unsupported("device.uninstall");
|
|
1310
|
+
}
|
|
1311
|
+
async newSmartapp(_container, appKey) {
|
|
1312
|
+
return new SmartappApp(this.driver.miniProgram || null, appKey);
|
|
1313
|
+
}
|
|
1314
|
+
async tap() {
|
|
1315
|
+
unsupported("device.tap");
|
|
1316
|
+
}
|
|
1317
|
+
async swipe() {
|
|
1318
|
+
unsupported("device.swipe");
|
|
1319
|
+
}
|
|
1320
|
+
async longpress() {
|
|
1321
|
+
unsupported("device.longpress");
|
|
1322
|
+
}
|
|
1323
|
+
async $x() {
|
|
1324
|
+
return [];
|
|
1325
|
+
}
|
|
1326
|
+
async home() {
|
|
1327
|
+
unsupported("device.home");
|
|
1328
|
+
}
|
|
1329
|
+
async enter() {
|
|
1330
|
+
unsupported("device.enter");
|
|
1331
|
+
}
|
|
1332
|
+
async back() {
|
|
1333
|
+
unsupported("device.back");
|
|
1334
|
+
}
|
|
1335
|
+
async isInstall() {
|
|
1336
|
+
return false;
|
|
1337
|
+
}
|
|
1338
|
+
async close() {
|
|
1339
|
+
await this.driver.close?.();
|
|
1340
|
+
this.driver.miniProgram?.disconnect();
|
|
1341
|
+
}
|
|
1342
|
+
};
|
|
1343
|
+
//#endregion
|
|
1344
|
+
//#region src/smartapp/file.ts
|
|
1345
|
+
/**
|
|
1346
|
+
* @file 百度智能小程序自动化文件工具。
|
|
1347
|
+
*/
|
|
1348
|
+
async function mkdir(dir) {
|
|
1349
|
+
await fs.mkdir(dir, { recursive: true });
|
|
1350
|
+
}
|
|
1351
|
+
async function rmdir(dir) {
|
|
1352
|
+
await fs.rm(dir, {
|
|
1353
|
+
recursive: true,
|
|
1354
|
+
force: true
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
async function wget(url, targetPath) {
|
|
1358
|
+
const response = await fetch(url);
|
|
1359
|
+
if (!response.ok) throw new Error(`Failed downloading ${url}: ${response.status} ${response.statusText}`);
|
|
1360
|
+
await mkdir(path.dirname(targetPath));
|
|
1361
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
1362
|
+
await fs.writeFile(targetPath, buffer);
|
|
1363
|
+
}
|
|
1364
|
+
async function changeProjectSwanJson(projectPath, values) {
|
|
1365
|
+
const swanJsonPath = path.resolve(projectPath, "project.swan.json");
|
|
1366
|
+
const raw = await fs.readFile(swanJsonPath, "utf8");
|
|
1367
|
+
const current = JSON.parse(raw);
|
|
1368
|
+
await fs.writeFile(swanJsonPath, JSON.stringify({
|
|
1369
|
+
...current,
|
|
1370
|
+
...values
|
|
1371
|
+
}, null, 2), "utf8");
|
|
1372
|
+
}
|
|
1373
|
+
const file = {
|
|
1374
|
+
changeProjectSwanJson,
|
|
1375
|
+
mkdir,
|
|
1376
|
+
rmdir,
|
|
1377
|
+
wget
|
|
1378
|
+
};
|
|
1379
|
+
//#endregion
|
|
1380
|
+
//#region src/smartapp/image.ts
|
|
1381
|
+
async function drawBorder(imageBuffer) {
|
|
1382
|
+
return imageBuffer;
|
|
1383
|
+
}
|
|
1384
|
+
async function extract(imageBuffer) {
|
|
1385
|
+
return imageBuffer;
|
|
1386
|
+
}
|
|
1387
|
+
async function border(imageBuffer) {
|
|
1388
|
+
return imageBuffer;
|
|
1389
|
+
}
|
|
1390
|
+
const image = {
|
|
1391
|
+
border,
|
|
1392
|
+
drawBorder,
|
|
1393
|
+
extract
|
|
1394
|
+
};
|
|
1395
|
+
//#endregion
|
|
1396
|
+
//#region src/smartapp/log.ts
|
|
1397
|
+
const rawConsole = console;
|
|
1398
|
+
const loggers = /* @__PURE__ */ new Map();
|
|
1399
|
+
function createLogger(label) {
|
|
1400
|
+
return {
|
|
1401
|
+
error: (message) => rawConsole.error(`[${label}] ${message}`),
|
|
1402
|
+
info: (message) => rawConsole.info(`[${label}] ${message}`),
|
|
1403
|
+
warn: (message) => rawConsole.warn(`[${label}] ${message}`)
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
function set(_dir, label = "smartapp-automator") {
|
|
1407
|
+
const logger = createLogger(label);
|
|
1408
|
+
loggers.set(label, logger);
|
|
1409
|
+
return logger;
|
|
1410
|
+
}
|
|
1411
|
+
function get(label = "smartapp-automator") {
|
|
1412
|
+
const logger = loggers.get(label);
|
|
1413
|
+
if (!logger) return set("", label);
|
|
1414
|
+
return logger;
|
|
1415
|
+
}
|
|
1416
|
+
const log = {
|
|
1417
|
+
get,
|
|
1418
|
+
set
|
|
1419
|
+
};
|
|
1420
|
+
//#endregion
|
|
1421
|
+
//#region src/smartapp/index.ts
|
|
1422
|
+
const DEFAULT_CONNECT_TYPE = "usb";
|
|
1423
|
+
function resolveDeviceType(deviceType) {
|
|
1424
|
+
switch (deviceType) {
|
|
1425
|
+
case "android":
|
|
1426
|
+
case "iOS":
|
|
1427
|
+
case "web":
|
|
1428
|
+
case "devtools":
|
|
1429
|
+
case "simulator": return deviceType;
|
|
1430
|
+
default: return "simulator";
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
function resolveConnectType(connectType) {
|
|
1434
|
+
switch (connectType) {
|
|
1435
|
+
case "usb":
|
|
1436
|
+
case "wifi":
|
|
1437
|
+
case "newBaiduCloud":
|
|
1438
|
+
case "mtpaas": return connectType;
|
|
1439
|
+
default: return DEFAULT_CONNECT_TYPE;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
async function connectMiniProgram(wsEndpoint) {
|
|
1443
|
+
return new MiniProgram(await Connection.create(wsEndpoint));
|
|
1444
|
+
}
|
|
1445
|
+
async function launch(options = {}) {
|
|
1446
|
+
const deviceType = resolveDeviceType(options.deviceType);
|
|
1447
|
+
const connectType = resolveConnectType(options.connectType);
|
|
1448
|
+
const deviceId = options.deviceId || `${deviceType}-${connectType}`;
|
|
1449
|
+
if (deviceType === "simulator" || deviceType === "devtools") return new SmartappDevice("devtools", connectType, deviceId, { miniProgram: options.wsEndpoint ? await connectMiniProgram(options.wsEndpoint) : void 0 });
|
|
1450
|
+
return new SmartappDevice(deviceType, connectType, deviceId);
|
|
1451
|
+
}
|
|
1452
|
+
async function connect(options) {
|
|
1453
|
+
if (typeof options.wsEndpoint !== "string") throw new TypeError("wsEndpoint is required for smartapp runtime connection.");
|
|
1454
|
+
return new SmartappDevice("devtools", DEFAULT_CONNECT_TYPE, "devtools-usb", { miniProgram: await connectMiniProgram(options.wsEndpoint) });
|
|
1455
|
+
}
|
|
1456
|
+
async function devices(deviceType, _connectType = DEFAULT_CONNECT_TYPE) {
|
|
1457
|
+
const resolvedDeviceType = resolveDeviceType(deviceType);
|
|
1458
|
+
if (resolvedDeviceType === "simulator" || resolvedDeviceType === "devtools") return { devtools: { status: 0 } };
|
|
1459
|
+
return {};
|
|
1460
|
+
}
|
|
1461
|
+
const SmartappAutomator$1 = {
|
|
1462
|
+
connect,
|
|
1463
|
+
devices,
|
|
1464
|
+
file,
|
|
1465
|
+
image,
|
|
1466
|
+
launch,
|
|
1467
|
+
log,
|
|
1468
|
+
time
|
|
1469
|
+
};
|
|
1470
|
+
//#endregion
|
|
1471
|
+
//#region src/SwanLauncher.ts
|
|
1472
|
+
const smartappAutomatorRuntime = SmartappAutomator$1;
|
|
1473
|
+
function toSmartappLaunchOptions(options) {
|
|
1474
|
+
const { cliPath, platform: _platform, runtimeProvider: _runtimeProvider, ...rest } = options;
|
|
1475
|
+
return {
|
|
1476
|
+
deviceType: options.deviceType || "simulator",
|
|
1477
|
+
...rest,
|
|
1478
|
+
...cliPath ? { devtoolsPath: cliPath } : {}
|
|
1479
|
+
};
|
|
1480
|
+
}
|
|
1481
|
+
var SwanLauncher = class {
|
|
1482
|
+
constructor(automator = SmartappAutomator$1) {
|
|
1483
|
+
this.automator = automator;
|
|
1484
|
+
}
|
|
1485
|
+
async launch(options) {
|
|
1486
|
+
return await this.automator.launch(toSmartappLaunchOptions(options));
|
|
1487
|
+
}
|
|
1488
|
+
async connect(options) {
|
|
1489
|
+
if (!this.automator.connect) throw new Error("smartapp-automator does not expose connect(). Please use launch() for Baidu smart program automation.");
|
|
1490
|
+
return await this.automator.connect({ ...options });
|
|
1491
|
+
}
|
|
1492
|
+
};
|
|
1493
|
+
//#endregion
|
|
1084
1494
|
//#region src/Launcher.ts
|
|
1085
1495
|
/**
|
|
1086
1496
|
* @file 开发者工具启动与连接流程。
|
|
@@ -1137,7 +1547,11 @@ function resolveRuntimeProvider(options) {
|
|
|
1137
1547
|
/** Launcher 的实现。 */
|
|
1138
1548
|
var Launcher = class {
|
|
1139
1549
|
async launch(options) {
|
|
1140
|
-
if (
|
|
1550
|
+
if (normalizePlatform(options.platform) === "swan") return await new SwanLauncher().launch(options);
|
|
1551
|
+
if (resolveRuntimeProvider(options) === "headless") {
|
|
1552
|
+
if (!options.projectPath) throw new Error("projectPath is not provided");
|
|
1553
|
+
return await launchHeadlessAutomator({ projectPath: options.projectPath });
|
|
1554
|
+
}
|
|
1141
1555
|
patchNetListenToLoopback();
|
|
1142
1556
|
const { cliPath = await this.resolveCliPath(), timeout = DEFAULT_TIMEOUT, projectConfig = {}, ticket = "", cwd = "", account = "", trustProject = false } = options;
|
|
1143
1557
|
let { args = [], projectPath } = options;
|
|
@@ -1225,6 +1639,7 @@ var Launcher = class {
|
|
|
1225
1639
|
return resolvedMiniProgram;
|
|
1226
1640
|
}
|
|
1227
1641
|
async connect(options) {
|
|
1642
|
+
if (normalizePlatform(options.platform) === "swan") return await new SwanLauncher().connect(options);
|
|
1228
1643
|
const miniProgram = await this.connectTool(options);
|
|
1229
1644
|
await miniProgram.checkVersion();
|
|
1230
1645
|
return miniProgram;
|
|
@@ -1281,5 +1696,6 @@ var Automator = class {
|
|
|
1281
1696
|
/**
|
|
1282
1697
|
* @file miniprogram-automator 对外导出入口。
|
|
1283
1698
|
*/
|
|
1699
|
+
const SmartappAutomator = smartappAutomatorRuntime;
|
|
1284
1700
|
//#endregion
|
|
1285
|
-
export { Automator, Connection, ContextElement, CustomElement, Element, InputElement, Launcher, MiniProgram, MovableViewElement, Native, Page, ScrollViewElement, SliderElement, SwiperElement, SwitchElement, TextareaElement, Transport, decodeQrCode, extractPluginId, isPluginPath, printQrCode };
|
|
1701
|
+
export { Automator, Connection, ContextElement, CustomElement, Element, InputElement, Launcher, MiniProgram, MovableViewElement, Native, Page, ScrollViewElement, SliderElement, SmartappAutomator, SwiperElement, SwitchElement, TextareaElement, Transport, decodeQrCode, extractPluginId, isPluginPath, normalizePlatform, printQrCode };
|
package/package.json
CHANGED