@weapp-vite/miniprogram-automator 1.0.5 → 1.1.1

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
@@ -4,10 +4,11 @@ import process from "node:process";
4
4
  import { spawn } from "node:child_process";
5
5
  import path from "node:path";
6
6
  import { EventEmitter } from "node:events";
7
- import debug from "debug";
7
+ import { createDebug } from "obug";
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 异步控制工具。
@@ -223,6 +224,8 @@ function toStr(value) {
223
224
  //#region src/Element.ts
224
225
  /** Element 的实现。 */
225
226
  var Element = class Element {
227
+ connection;
228
+ elementMap;
226
229
  tagName = "";
227
230
  nodeId;
228
231
  videoId;
@@ -473,6 +476,7 @@ var ContextElement = class extends Element {
473
476
  //#region src/Transport.ts
474
477
  /** Transport 的实现。 */
475
478
  var Transport = class extends EventEmitter {
479
+ ws;
476
480
  constructor(ws) {
477
481
  super();
478
482
  this.ws = ws;
@@ -495,11 +499,12 @@ var Transport = class extends EventEmitter {
495
499
  /**
496
500
  * @file 自动化协议连接实现。
497
501
  */
498
- const debugProtocol = debug("automator:protocol");
502
+ const debugProtocol = createDebug("automator:protocol");
499
503
  const closeErrTip = "Connection closed, check if wechat web devTools is still running";
500
504
  const REQUEST_TIMEOUT = 3e4;
501
505
  /** Connection 的实现。 */
502
506
  var Connection = class Connection extends EventEmitter {
507
+ transport;
503
508
  callbacks = /* @__PURE__ */ new Map();
504
509
  constructor(transport) {
505
510
  super();
@@ -577,15 +582,16 @@ var Connection = class Connection extends EventEmitter {
577
582
  //#endregion
578
583
  //#region src/headless.ts
579
584
  async function launchHeadlessAutomator(options) {
580
- return await (await import("./launch-Didv0lMX.mjs")).launch({ projectPath: options.projectPath });
585
+ return await (await import("./launch-CDd9gHVW.mjs")).launch({ projectPath: options.projectPath });
581
586
  }
582
587
  //#endregion
583
588
  //#region package.json
584
- var version = "1.0.5";
589
+ var version = "1.1.1";
585
590
  //#endregion
586
591
  //#region src/Native.ts
587
592
  /** Native 的实现。 */
588
593
  var Native = class extends EventEmitter {
594
+ connection;
589
595
  constructor(connection) {
590
596
  super();
591
597
  this.connection = connection;
@@ -634,6 +640,7 @@ var Native = class extends EventEmitter {
634
640
  //#region src/Page.ts
635
641
  /** Page 的实现。 */
636
642
  var Page = class Page {
643
+ connection;
637
644
  path = "";
638
645
  query = {};
639
646
  id;
@@ -809,6 +816,7 @@ function logChangeRouteDebug(message) {
809
816
  }
810
817
  /** MiniProgram 的实现。 */
811
818
  var MiniProgram = class extends EventEmitter {
819
+ connection;
812
820
  appBindings = /* @__PURE__ */ new Map();
813
821
  pageMap = /* @__PURE__ */ new Map();
814
822
  nativeIns;
@@ -1041,7 +1049,8 @@ var MiniProgram = class extends EventEmitter {
1041
1049
  logChangeRouteDebug(`poll-error method=${method} url=${url ?? "<none>"} error=${error instanceof Error ? error.message : String(error)}`);
1042
1050
  }
1043
1051
  try {
1044
- const stackTop = (await this.pageStack()).at(-1);
1052
+ const stack = await this.pageStack();
1053
+ const stackTop = stack[stack.length - 1];
1045
1054
  if (stackTop) {
1046
1055
  lastPage = stackTop;
1047
1056
  logChangeRouteDebug(`stack method=${method} url=${url ?? "<none>"} current=${stackTop.path}`);
@@ -1081,6 +1090,425 @@ var MiniProgram = class extends EventEmitter {
1081
1090
  };
1082
1091
  };
1083
1092
  //#endregion
1093
+ //#region src/platform.ts
1094
+ function normalizePlatform(platform = "wechat") {
1095
+ return platform === "baidu" ? "swan" : platform;
1096
+ }
1097
+ //#endregion
1098
+ //#region src/smartapp/errors.ts
1099
+ /**
1100
+ * @file 百度智能小程序自动化错误定义。
1101
+ */
1102
+ var SmartappUnsupportedError = class extends Error {
1103
+ constructor(feature) {
1104
+ super(`${feature} is not available in the lightweight TypeScript smartapp runtime.`);
1105
+ this.name = "SmartappUnsupportedError";
1106
+ }
1107
+ };
1108
+ function unsupported(feature) {
1109
+ throw new SmartappUnsupportedError(feature);
1110
+ }
1111
+ //#endregion
1112
+ //#region src/smartapp/time.ts
1113
+ /**
1114
+ * @file 百度智能小程序自动化时间工具。
1115
+ */
1116
+ function currentTimestamp() {
1117
+ return Date.now();
1118
+ }
1119
+ async function delay(ms) {
1120
+ await new Promise((resolve) => setTimeout(resolve, ms));
1121
+ }
1122
+ const time = {
1123
+ currentTimestamp,
1124
+ delay
1125
+ };
1126
+ //#endregion
1127
+ //#region src/smartapp/Element.ts
1128
+ function getCoreElementId(element, selectors, index) {
1129
+ if (!element) return `${selectors}:${index}`;
1130
+ const elementId = Reflect.get(element, "id");
1131
+ return typeof elementId === "string" ? elementId : `${selectors}:${index}`;
1132
+ }
1133
+ function isInputCapableElement(element) {
1134
+ return typeof Reflect.get(element, "input") === "function";
1135
+ }
1136
+ var SmartappElement = class {
1137
+ element;
1138
+ selectors;
1139
+ index;
1140
+ id;
1141
+ tagName;
1142
+ constructor(element, selectors = "", index = 0) {
1143
+ this.element = element;
1144
+ this.selectors = selectors;
1145
+ this.index = index;
1146
+ this.id = getCoreElementId(element, selectors, index);
1147
+ this.tagName = element?.tagName || "";
1148
+ }
1149
+ async scrollIntoView(options = {}) {
1150
+ await delay(options.wait ?? 1e3);
1151
+ }
1152
+ async boundingBox() {
1153
+ if (!this.element) return null;
1154
+ return await this.element.offset();
1155
+ }
1156
+ async tap(options = {}) {
1157
+ const count = options.count ?? 1;
1158
+ for (let index = 0; index < count; index++) await this.element?.tap();
1159
+ await delay(options.wait ?? 1e3);
1160
+ }
1161
+ async input(text, options = {}) {
1162
+ if (this.element) {
1163
+ if (!isInputCapableElement(this.element)) throw new SmartappUnsupportedError(`element.input(${this.tagName || "unknown"})`);
1164
+ await this.element.input(text);
1165
+ }
1166
+ await delay(options.wait ?? 1e3);
1167
+ }
1168
+ async text() {
1169
+ return await this.element?.text();
1170
+ }
1171
+ async value() {
1172
+ return await this.property("value");
1173
+ }
1174
+ async attribute(name) {
1175
+ return await this.element?.attribute(name);
1176
+ }
1177
+ async property(name) {
1178
+ return await this.element?.property(name);
1179
+ }
1180
+ async style(style) {
1181
+ return await this.element?.property(style);
1182
+ }
1183
+ async longpress(options = {}) {
1184
+ await this.element?.longpress();
1185
+ await delay(options.duration ?? 0);
1186
+ }
1187
+ async move(options = {}) {
1188
+ await delay(options.wait ?? 1e3);
1189
+ }
1190
+ async screenshot(options = {}) {
1191
+ return Buffer.alloc(0);
1192
+ }
1193
+ };
1194
+ //#endregion
1195
+ //#region src/smartapp/Page.ts
1196
+ var SmartappPage = class {
1197
+ page;
1198
+ path;
1199
+ query;
1200
+ uri;
1201
+ constructor(page, path = "", query = {}) {
1202
+ this.page = page;
1203
+ this.path = page?.path || path;
1204
+ this.query = page?.query || query;
1205
+ const queryText = new URLSearchParams(this.query).toString();
1206
+ this.uri = queryText ? `${this.path}?${queryText}` : this.path;
1207
+ }
1208
+ async data(path) {
1209
+ return await this.page?.data(path);
1210
+ }
1211
+ async setData(data) {
1212
+ await this.page?.setData(data);
1213
+ }
1214
+ async callMethod(method, ...args) {
1215
+ return await this.page?.callMethod(method, ...args);
1216
+ }
1217
+ };
1218
+ //#endregion
1219
+ //#region src/smartapp/App.ts
1220
+ var SmartappApp = class {
1221
+ miniProgram;
1222
+ appKey;
1223
+ constructor(miniProgram, appKey) {
1224
+ this.miniProgram = miniProgram;
1225
+ this.appKey = appKey;
1226
+ }
1227
+ async goto(path = "", options = {}) {
1228
+ const retry = options.retry ?? 0;
1229
+ let lastError;
1230
+ for (let count = 0; count <= retry; count++) try {
1231
+ return new SmartappPage(await this.miniProgram?.reLaunch(path) || null, path);
1232
+ } catch (error) {
1233
+ lastError = error;
1234
+ }
1235
+ throw lastError;
1236
+ }
1237
+ async screenshot(options = {}) {
1238
+ return await this.miniProgram?.screenshot(options);
1239
+ }
1240
+ async currentPage() {
1241
+ return new SmartappPage(await this.miniProgram?.currentPage() || null);
1242
+ }
1243
+ async data() {
1244
+ return await this.miniProgram?.callWxMethod("getSystemInfo", {});
1245
+ }
1246
+ async tabs() {
1247
+ return [];
1248
+ }
1249
+ async pages() {
1250
+ return await this.miniProgram?.pageStack();
1251
+ }
1252
+ async getSystemInfo() {
1253
+ return await this.miniProgram?.callWxMethod("getSystemInfo", {});
1254
+ }
1255
+ async source() {
1256
+ const page = await this.miniProgram?.currentPage();
1257
+ return JSON.stringify(await page?.data());
1258
+ }
1259
+ async swan(method, ...args) {
1260
+ return await this.miniProgram?.callWxMethod(method, ...args);
1261
+ }
1262
+ async getAbTestInfo() {
1263
+ return {};
1264
+ }
1265
+ async $(selectors, options = {}) {
1266
+ await delay(options.duration ?? 0);
1267
+ const element = await (await this.miniProgram?.currentPage())?.$(selectors);
1268
+ return element ? new SmartappElement(element, selectors, 0) : null;
1269
+ }
1270
+ async $$(selectors, options = {}) {
1271
+ await delay(options.duration ?? 0);
1272
+ return (await (await this.miniProgram?.currentPage())?.$$(selectors) || []).map((element, index) => new SmartappElement(element, selectors, index));
1273
+ }
1274
+ async $x(_expression) {
1275
+ return [];
1276
+ }
1277
+ async close() {
1278
+ this.miniProgram?.disconnect();
1279
+ }
1280
+ };
1281
+ //#endregion
1282
+ //#region src/smartapp/Device.ts
1283
+ var SmartappDevice = class {
1284
+ type;
1285
+ connectType;
1286
+ id;
1287
+ driver;
1288
+ constructor(type, connectType, id, driver = {}) {
1289
+ this.type = type;
1290
+ this.connectType = connectType;
1291
+ this.id = id;
1292
+ this.driver = driver;
1293
+ }
1294
+ async source(options = {}) {
1295
+ if (this.driver.source) return await this.driver.source();
1296
+ return "";
1297
+ }
1298
+ async screenshot(options = {}) {
1299
+ if (this.driver.screenshot) return await this.driver.screenshot();
1300
+ return Buffer.alloc(0);
1301
+ }
1302
+ async launchSmartapp(_container, appKey, path = "") {
1303
+ const app = await this.newSmartapp(_container, appKey);
1304
+ if (path) await app.goto(path);
1305
+ return app;
1306
+ }
1307
+ async getScreenSize() {
1308
+ return {
1309
+ height: 0,
1310
+ width: 0
1311
+ };
1312
+ }
1313
+ async terminateApp() {
1314
+ unsupported("device.terminateApp");
1315
+ }
1316
+ async launchApp() {
1317
+ unsupported("device.launchApp");
1318
+ }
1319
+ async reLaunchApp() {
1320
+ unsupported("device.reLaunchApp");
1321
+ }
1322
+ async install() {
1323
+ unsupported("device.install");
1324
+ }
1325
+ async uninstall() {
1326
+ unsupported("device.uninstall");
1327
+ }
1328
+ async newSmartapp(_container, appKey) {
1329
+ return new SmartappApp(this.driver.miniProgram || null, appKey);
1330
+ }
1331
+ async tap() {
1332
+ unsupported("device.tap");
1333
+ }
1334
+ async swipe() {
1335
+ unsupported("device.swipe");
1336
+ }
1337
+ async longpress() {
1338
+ unsupported("device.longpress");
1339
+ }
1340
+ async $x() {
1341
+ return [];
1342
+ }
1343
+ async home() {
1344
+ unsupported("device.home");
1345
+ }
1346
+ async enter() {
1347
+ unsupported("device.enter");
1348
+ }
1349
+ async back() {
1350
+ unsupported("device.back");
1351
+ }
1352
+ async isInstall() {
1353
+ return false;
1354
+ }
1355
+ async close() {
1356
+ await this.driver.close?.();
1357
+ this.driver.miniProgram?.disconnect();
1358
+ }
1359
+ };
1360
+ //#endregion
1361
+ //#region src/smartapp/file.ts
1362
+ /**
1363
+ * @file 百度智能小程序自动化文件工具。
1364
+ */
1365
+ async function mkdir(dir) {
1366
+ await fs.mkdir(dir, { recursive: true });
1367
+ }
1368
+ async function rmdir(dir) {
1369
+ await fs.rm(dir, {
1370
+ recursive: true,
1371
+ force: true
1372
+ });
1373
+ }
1374
+ async function wget(url, targetPath) {
1375
+ const response = await fetch(url);
1376
+ if (!response.ok) throw new Error(`Failed downloading ${url}: ${response.status} ${response.statusText}`);
1377
+ await mkdir(path.dirname(targetPath));
1378
+ const buffer = Buffer.from(await response.arrayBuffer());
1379
+ await fs.writeFile(targetPath, buffer);
1380
+ }
1381
+ async function changeProjectSwanJson(projectPath, values) {
1382
+ const swanJsonPath = path.resolve(projectPath, "project.swan.json");
1383
+ const raw = await fs.readFile(swanJsonPath, "utf8");
1384
+ const current = JSON.parse(raw);
1385
+ await fs.writeFile(swanJsonPath, JSON.stringify({
1386
+ ...current,
1387
+ ...values
1388
+ }, null, 2), "utf8");
1389
+ }
1390
+ const file = {
1391
+ changeProjectSwanJson,
1392
+ mkdir,
1393
+ rmdir,
1394
+ wget
1395
+ };
1396
+ //#endregion
1397
+ //#region src/smartapp/image.ts
1398
+ async function drawBorder(imageBuffer) {
1399
+ return imageBuffer;
1400
+ }
1401
+ async function extract(imageBuffer) {
1402
+ return imageBuffer;
1403
+ }
1404
+ async function border(imageBuffer) {
1405
+ return imageBuffer;
1406
+ }
1407
+ const image = {
1408
+ border,
1409
+ drawBorder,
1410
+ extract
1411
+ };
1412
+ //#endregion
1413
+ //#region src/smartapp/log.ts
1414
+ const rawConsole = console;
1415
+ const loggers = /* @__PURE__ */ new Map();
1416
+ function createLogger(label) {
1417
+ return {
1418
+ error: (message) => rawConsole.error(`[${label}] ${message}`),
1419
+ info: (message) => rawConsole.info(`[${label}] ${message}`),
1420
+ warn: (message) => rawConsole.warn(`[${label}] ${message}`)
1421
+ };
1422
+ }
1423
+ function set(_dir, label = "smartapp-automator") {
1424
+ const logger = createLogger(label);
1425
+ loggers.set(label, logger);
1426
+ return logger;
1427
+ }
1428
+ function get(label = "smartapp-automator") {
1429
+ const logger = loggers.get(label);
1430
+ if (!logger) return set("", label);
1431
+ return logger;
1432
+ }
1433
+ const log = {
1434
+ get,
1435
+ set
1436
+ };
1437
+ //#endregion
1438
+ //#region src/smartapp/index.ts
1439
+ const DEFAULT_CONNECT_TYPE = "usb";
1440
+ function resolveDeviceType(deviceType) {
1441
+ switch (deviceType) {
1442
+ case "android":
1443
+ case "iOS":
1444
+ case "web":
1445
+ case "devtools":
1446
+ case "simulator": return deviceType;
1447
+ default: return "simulator";
1448
+ }
1449
+ }
1450
+ function resolveConnectType(connectType) {
1451
+ switch (connectType) {
1452
+ case "usb":
1453
+ case "wifi":
1454
+ case "newBaiduCloud":
1455
+ case "mtpaas": return connectType;
1456
+ default: return DEFAULT_CONNECT_TYPE;
1457
+ }
1458
+ }
1459
+ async function connectMiniProgram(wsEndpoint) {
1460
+ return new MiniProgram(await Connection.create(wsEndpoint));
1461
+ }
1462
+ async function launch(options = {}) {
1463
+ const deviceType = resolveDeviceType(options.deviceType);
1464
+ const connectType = resolveConnectType(options.connectType);
1465
+ const deviceId = options.deviceId || `${deviceType}-${connectType}`;
1466
+ if (deviceType === "simulator" || deviceType === "devtools") return new SmartappDevice("devtools", connectType, deviceId, { miniProgram: options.wsEndpoint ? await connectMiniProgram(options.wsEndpoint) : void 0 });
1467
+ return new SmartappDevice(deviceType, connectType, deviceId);
1468
+ }
1469
+ async function connect(options) {
1470
+ if (typeof options.wsEndpoint !== "string") throw new TypeError("wsEndpoint is required for smartapp runtime connection.");
1471
+ return new SmartappDevice("devtools", DEFAULT_CONNECT_TYPE, "devtools-usb", { miniProgram: await connectMiniProgram(options.wsEndpoint) });
1472
+ }
1473
+ async function devices(deviceType, _connectType = DEFAULT_CONNECT_TYPE) {
1474
+ const resolvedDeviceType = resolveDeviceType(deviceType);
1475
+ if (resolvedDeviceType === "simulator" || resolvedDeviceType === "devtools") return { devtools: { status: 0 } };
1476
+ return {};
1477
+ }
1478
+ const SmartappAutomator$1 = {
1479
+ connect,
1480
+ devices,
1481
+ file,
1482
+ image,
1483
+ launch,
1484
+ log,
1485
+ time
1486
+ };
1487
+ //#endregion
1488
+ //#region src/SwanLauncher.ts
1489
+ const smartappAutomatorRuntime = SmartappAutomator$1;
1490
+ function toSmartappLaunchOptions(options) {
1491
+ const { cliPath, platform: _platform, runtimeProvider: _runtimeProvider, ...rest } = options;
1492
+ return {
1493
+ deviceType: options.deviceType || "simulator",
1494
+ ...rest,
1495
+ ...cliPath ? { devtoolsPath: cliPath } : {}
1496
+ };
1497
+ }
1498
+ var SwanLauncher = class {
1499
+ automator;
1500
+ constructor(automator = SmartappAutomator$1) {
1501
+ this.automator = automator;
1502
+ }
1503
+ async launch(options) {
1504
+ return await this.automator.launch(toSmartappLaunchOptions(options));
1505
+ }
1506
+ async connect(options) {
1507
+ if (!this.automator.connect) throw new Error("smartapp-automator does not expose connect(). Please use launch() for Baidu smart program automation.");
1508
+ return await this.automator.connect({ ...options });
1509
+ }
1510
+ };
1511
+ //#endregion
1084
1512
  //#region src/Launcher.ts
1085
1513
  /**
1086
1514
  * @file 开发者工具启动与连接流程。
@@ -1137,7 +1565,11 @@ function resolveRuntimeProvider(options) {
1137
1565
  /** Launcher 的实现。 */
1138
1566
  var Launcher = class {
1139
1567
  async launch(options) {
1140
- if (resolveRuntimeProvider(options) === "headless") return await launchHeadlessAutomator({ projectPath: options.projectPath });
1568
+ if (normalizePlatform(options.platform) === "swan") return await new SwanLauncher().launch(options);
1569
+ if (resolveRuntimeProvider(options) === "headless") {
1570
+ if (!options.projectPath) throw new Error("projectPath is not provided");
1571
+ return await launchHeadlessAutomator({ projectPath: options.projectPath });
1572
+ }
1141
1573
  patchNetListenToLoopback();
1142
1574
  const { cliPath = await this.resolveCliPath(), timeout = DEFAULT_TIMEOUT, projectConfig = {}, ticket = "", cwd = "", account = "", trustProject = false } = options;
1143
1575
  let { args = [], projectPath } = options;
@@ -1225,6 +1657,7 @@ var Launcher = class {
1225
1657
  return resolvedMiniProgram;
1226
1658
  }
1227
1659
  async connect(options) {
1660
+ if (normalizePlatform(options.platform) === "swan") return await new SwanLauncher().connect(options);
1228
1661
  const miniProgram = await this.connectTool(options);
1229
1662
  await miniProgram.checkVersion();
1230
1663
  return miniProgram;
@@ -1281,5 +1714,6 @@ var Automator = class {
1281
1714
  /**
1282
1715
  * @file miniprogram-automator 对外导出入口。
1283
1716
  */
1717
+ const SmartappAutomator = smartappAutomatorRuntime;
1284
1718
  //#endregion
1285
- export { Automator, Connection, ContextElement, CustomElement, Element, InputElement, Launcher, MiniProgram, MovableViewElement, Native, Page, ScrollViewElement, SliderElement, SwiperElement, SwitchElement, TextareaElement, Transport, decodeQrCode, extractPluginId, isPluginPath, printQrCode };
1719
+ export { Automator, Connection, ContextElement, CustomElement, Element, InputElement, Launcher, MiniProgram, MovableViewElement, Native, Page, ScrollViewElement, SliderElement, SmartappAutomator, SwiperElement, SwitchElement, TextareaElement, Transport, decodeQrCode, extractPluginId, isPluginPath, normalizePlatform, printQrCode };
@@ -4047,6 +4047,8 @@ function resolveComponentScopeId(scopeId) {
4047
4047
  return scopeId;
4048
4048
  }
4049
4049
  var HeadlessTestingNodeHandle = class HeadlessTestingNodeHandle {
4050
+ node;
4051
+ interactions;
4050
4052
  constructor(node, interactions) {
4051
4053
  this.node = node;
4052
4054
  this.interactions = interactions;
@@ -7720,6 +7722,9 @@ function createHeadlessSession(options) {
7720
7722
  const DEFAULT_WAIT_TIMEOUT$1 = 1e3;
7721
7723
  const DEFAULT_WAIT_INTERVAL$1 = 10;
7722
7724
  var HeadlessTestingPageHandle = class {
7725
+ project;
7726
+ page;
7727
+ session;
7723
7728
  constructor(project, page, session) {
7724
7729
  this.project = project;
7725
7730
  this.page = page;
@@ -7886,6 +7891,9 @@ async function pollUntil(check, errorMessage, options = {}) {
7886
7891
  //#endregion
7887
7892
  //#region ../../mpcore/packages/simulator/src/testing/sessionHandle/scope.ts
7888
7893
  var HeadlessTestingScopeHandle = class HeadlessTestingScopeHandle {
7894
+ scopeId;
7895
+ project;
7896
+ session;
7889
7897
  constructor(scopeId, project, session) {
7890
7898
  this.scopeId = scopeId;
7891
7899
  this.project = project;
@@ -7940,6 +7948,8 @@ var HeadlessTestingScopeHandle = class HeadlessTestingScopeHandle {
7940
7948
  //#endregion
7941
7949
  //#region ../../mpcore/packages/simulator/src/testing/sessionHandle/index.ts
7942
7950
  var HeadlessTestingSessionHandle = class {
7951
+ project;
7952
+ session;
7943
7953
  constructor(project, session) {
7944
7954
  this.project = project;
7945
7955
  this.session = session;
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.1",
5
5
  "description": "完全兼容微信 miniprogram-automator 的现代化替代实现",
6
6
  "author": "ice breaker <1324318532@qq.com>",
7
7
  "license": "MIT",
@@ -41,8 +41,8 @@
41
41
  "node": "^20.19.0 || >=22.12.0"
42
42
  },
43
43
  "dependencies": {
44
- "debug": "^4.4.3",
45
- "ws": "^8.18.3",
44
+ "obug": "^2.1.1",
45
+ "ws": "^8.20.1",
46
46
  "@weapp-vite/qr": "1.1.0"
47
47
  },
48
48
  "publishConfig": {