@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 CHANGED
@@ -7,13 +7,14 @@
7
7
  它同时服务于:
8
8
 
9
9
  - `weapp-ide-cli` 的自动化能力
10
- - 仓库内 WeChat DevTools 相关 e2e 测试
11
- - 需要直接连接微信开发者工具 WebSocket 协议的 Node 工具
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: string;
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<MiniProgram>;
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<MiniProgram>;
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
- export { Automator, Connection, ContextElement, CustomElement, Element, IConnectOptions, ILaunchOptions, ILauncherSessionMetadata, InputElement, Launcher, MiniProgram, MovableViewElement, Native, Page, ScrollViewElement, SliderElement, SwiperElement, SwitchElement, TextareaElement, Transport, decodeQrCode, extractPluginId, isPluginPath, printQrCode };
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.5";
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 stackTop = (await this.pageStack()).at(-1);
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 (resolveRuntimeProvider(options) === "headless") return await launchHeadlessAutomator({ projectPath: options.projectPath });
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@weapp-vite/miniprogram-automator",
3
3
  "type": "module",
4
- "version": "1.0.5",
4
+ "version": "1.1.0",
5
5
  "description": "完全兼容微信 miniprogram-automator 的现代化替代实现",
6
6
  "author": "ice breaker <1324318532@qq.com>",
7
7
  "license": "MIT",