@weapp-vite/miniprogram-automator 1.1.1 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts
CHANGED
|
@@ -42,12 +42,15 @@ declare class Transport extends EventEmitter {
|
|
|
42
42
|
}
|
|
43
43
|
//#endregion
|
|
44
44
|
//#region src/Connection.d.ts
|
|
45
|
+
interface SendOptions {
|
|
46
|
+
timeout?: number;
|
|
47
|
+
}
|
|
45
48
|
/** Connection 的实现。 */
|
|
46
49
|
declare class Connection extends EventEmitter {
|
|
47
50
|
private transport;
|
|
48
51
|
private callbacks;
|
|
49
52
|
constructor(transport: Transport);
|
|
50
|
-
send(method: string, params?: Record<string, any
|
|
53
|
+
send(method: string, params?: Record<string, any>, options?: SendOptions): Promise<any>;
|
|
51
54
|
dispose(): void;
|
|
52
55
|
private onMessage;
|
|
53
56
|
private onClose;
|
|
@@ -240,6 +243,10 @@ interface IToolClearCacheOptions {
|
|
|
240
243
|
clean: 'all' | 'auth' | 'compile' | 'file' | 'network' | 'session' | 'storage';
|
|
241
244
|
}
|
|
242
245
|
type AutomatorCallable = (...args: any[]) => any;
|
|
246
|
+
interface CurrentPageOptions {
|
|
247
|
+
retries?: number;
|
|
248
|
+
timeout?: number;
|
|
249
|
+
}
|
|
243
250
|
/** MiniProgram 的实现。 */
|
|
244
251
|
declare class MiniProgram extends EventEmitter {
|
|
245
252
|
private connection;
|
|
@@ -253,9 +260,10 @@ declare class MiniProgram extends EventEmitter {
|
|
|
253
260
|
navigateBack(): Promise<any>;
|
|
254
261
|
reLaunch(url: string): Promise<any>;
|
|
255
262
|
switchTab(url: string): Promise<any>;
|
|
256
|
-
currentPage(): Promise<Page>;
|
|
263
|
+
currentPage(options?: CurrentPageOptions): Promise<Page>;
|
|
257
264
|
systemInfo(): Promise<any>;
|
|
258
265
|
callWxMethod(method: string, ...args: any[]): Promise<any>;
|
|
266
|
+
private callWxMethodWithTimeout;
|
|
259
267
|
mockWxMethod(method: string, result: any, ...args: any[]): Promise<void>;
|
|
260
268
|
restoreWxMethod(method: string): Promise<void>;
|
|
261
269
|
callPluginWxMethod(pluginId: string, method: string, ...args: any[]): Promise<any>;
|
|
@@ -293,6 +301,9 @@ declare class MiniProgram extends EventEmitter {
|
|
|
293
301
|
refreshTicket(): Promise<void>;
|
|
294
302
|
native(): Native;
|
|
295
303
|
private changeRoute;
|
|
304
|
+
private resolveRouteContextPage;
|
|
305
|
+
private readRoutePollingCurrentPage;
|
|
306
|
+
private readRoutePollingPageStack;
|
|
296
307
|
private send;
|
|
297
308
|
private onLogAdded;
|
|
298
309
|
private onBindingCalled;
|
package/dist/index.mjs
CHANGED
|
@@ -512,22 +512,23 @@ var Connection = class Connection extends EventEmitter {
|
|
|
512
512
|
transport.on("message", this.onMessage);
|
|
513
513
|
transport.on("close", this.onClose);
|
|
514
514
|
}
|
|
515
|
-
send(method, params = {}) {
|
|
515
|
+
send(method, params = {}, options = {}) {
|
|
516
516
|
const id = uuid();
|
|
517
517
|
const payload = stringify({
|
|
518
518
|
id,
|
|
519
519
|
method,
|
|
520
520
|
params
|
|
521
521
|
});
|
|
522
|
+
const requestTimeout = options.timeout ?? REQUEST_TIMEOUT;
|
|
522
523
|
debugProtocol(`${dateFormat("yyyy-mm-dd HH:MM:ss:l")} SEND ► ${payload}`);
|
|
523
524
|
return new Promise((resolve, reject) => {
|
|
524
525
|
const timeout = setTimeout(() => {
|
|
525
526
|
this.callbacks.delete(id);
|
|
526
|
-
const error = /* @__PURE__ */ new Error(`DevTools did not respond to protocol method ${method} within ${
|
|
527
|
+
const error = /* @__PURE__ */ new Error(`DevTools did not respond to protocol method ${method} within ${requestTimeout}ms`);
|
|
527
528
|
error.code = "DEVTOOLS_PROTOCOL_TIMEOUT";
|
|
528
529
|
error.method = method;
|
|
529
530
|
reject(error);
|
|
530
|
-
},
|
|
531
|
+
}, requestTimeout);
|
|
531
532
|
this.callbacks.set(id, {
|
|
532
533
|
resolve,
|
|
533
534
|
reject,
|
|
@@ -582,11 +583,11 @@ var Connection = class Connection extends EventEmitter {
|
|
|
582
583
|
//#endregion
|
|
583
584
|
//#region src/headless.ts
|
|
584
585
|
async function launchHeadlessAutomator(options) {
|
|
585
|
-
return await (await import("./launch-
|
|
586
|
+
return await (await import("./launch-F4arniwI.mjs")).launch({ projectPath: options.projectPath });
|
|
586
587
|
}
|
|
587
588
|
//#endregion
|
|
588
589
|
//#region package.json
|
|
589
|
-
var version = "1.1.
|
|
590
|
+
var version = "1.1.3";
|
|
590
591
|
//#endregion
|
|
591
592
|
//#region src/Native.ts
|
|
592
593
|
/** Native 的实现。 */
|
|
@@ -779,6 +780,8 @@ function extractPluginId(p) {
|
|
|
779
780
|
const CLOSE_STEP_TIMEOUT = 2e3;
|
|
780
781
|
const CURRENT_PAGE_RETRIES = 3;
|
|
781
782
|
const CURRENT_PAGE_RETRY_DELAY = 400;
|
|
783
|
+
const CHANGE_ROUTE_CONTEXT_TIMEOUT = 12e3;
|
|
784
|
+
const CHANGE_ROUTE_CALL_TIMEOUT = 12e3;
|
|
782
785
|
const CHANGE_ROUTE_READY_TIMEOUT = 15e3;
|
|
783
786
|
const CHANGE_ROUTE_POLL_DELAY = 500;
|
|
784
787
|
const CHANGE_ROUTE_DEBUG_ENABLED = process.env.WEAPP_VITE_E2E_CHANGE_ROUTE_DEBUG === "1";
|
|
@@ -799,6 +802,9 @@ function withTimeout(task, timeoutMs) {
|
|
|
799
802
|
});
|
|
800
803
|
});
|
|
801
804
|
}
|
|
805
|
+
function isOperationTimeoutError(error, timeoutMs) {
|
|
806
|
+
return error instanceof Error && error.message.includes(`Operation timed out after ${timeoutMs}ms`);
|
|
807
|
+
}
|
|
802
808
|
function isFnStr(value) {
|
|
803
809
|
if (!isStr(value)) return false;
|
|
804
810
|
const trimmed = trim(value);
|
|
@@ -807,6 +813,15 @@ function isFnStr(value) {
|
|
|
807
813
|
function isCurrentPageProtocolTimeout(error) {
|
|
808
814
|
return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === "App.getCurrentPage";
|
|
809
815
|
}
|
|
816
|
+
function isPageStackProtocolTimeout(error) {
|
|
817
|
+
return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === "App.getPageStack";
|
|
818
|
+
}
|
|
819
|
+
function isCallWxMethodProtocolTimeout(error) {
|
|
820
|
+
return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === "App.callWxMethod";
|
|
821
|
+
}
|
|
822
|
+
function isRouteContextProbeError(error) {
|
|
823
|
+
return isCurrentPageProtocolTimeout(error) || isPageStackProtocolTimeout(error);
|
|
824
|
+
}
|
|
810
825
|
function normalizeRoutePath(value) {
|
|
811
826
|
return String(value ?? "").split("?", 1)[0].replace(/^\/+/, "").replace(/\/+$/, "");
|
|
812
827
|
}
|
|
@@ -852,10 +867,12 @@ var MiniProgram = class extends EventEmitter {
|
|
|
852
867
|
async switchTab(url) {
|
|
853
868
|
return await this.changeRoute("switchTab", url);
|
|
854
869
|
}
|
|
855
|
-
async currentPage() {
|
|
870
|
+
async currentPage(options = {}) {
|
|
856
871
|
let lastError;
|
|
857
|
-
|
|
858
|
-
|
|
872
|
+
const retries = options.retries ?? CURRENT_PAGE_RETRIES;
|
|
873
|
+
const sendOptions = options.timeout ? { timeout: options.timeout } : void 0;
|
|
874
|
+
for (let attempt = 1; attempt <= retries; attempt += 1) try {
|
|
875
|
+
const { pageId, path, query } = await this.send("App.getCurrentPage", {}, sendOptions);
|
|
859
876
|
return Page.create(this.connection, {
|
|
860
877
|
id: pageId,
|
|
861
878
|
path,
|
|
@@ -863,8 +880,22 @@ var MiniProgram = class extends EventEmitter {
|
|
|
863
880
|
}, this.pageMap);
|
|
864
881
|
} catch (error) {
|
|
865
882
|
lastError = error;
|
|
866
|
-
if (!isCurrentPageProtocolTimeout(error)
|
|
867
|
-
|
|
883
|
+
if (!isCurrentPageProtocolTimeout(error)) throw error;
|
|
884
|
+
if (attempt < retries) {
|
|
885
|
+
await sleep(CURRENT_PAGE_RETRY_DELAY);
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
if (isCurrentPageProtocolTimeout(lastError)) try {
|
|
890
|
+
const { pageStack } = await this.send("App.getPageStack", {}, sendOptions);
|
|
891
|
+
const page = pageStack[pageStack.length - 1];
|
|
892
|
+
if (page) return Page.create(this.connection, {
|
|
893
|
+
id: page.pageId,
|
|
894
|
+
path: page.path,
|
|
895
|
+
query: page.query
|
|
896
|
+
}, this.pageMap);
|
|
897
|
+
} catch (error) {
|
|
898
|
+
if (!isPageStackProtocolTimeout(error)) throw error;
|
|
868
899
|
}
|
|
869
900
|
throw lastError;
|
|
870
901
|
}
|
|
@@ -877,6 +908,12 @@ var MiniProgram = class extends EventEmitter {
|
|
|
877
908
|
args
|
|
878
909
|
})).result;
|
|
879
910
|
}
|
|
911
|
+
async callWxMethodWithTimeout(method, timeout, ...args) {
|
|
912
|
+
return (await this.send("App.callWxMethod", {
|
|
913
|
+
method,
|
|
914
|
+
args
|
|
915
|
+
}, { timeout })).result;
|
|
916
|
+
}
|
|
880
917
|
async mockWxMethod(method, result, ...args) {
|
|
881
918
|
if (isFn(result) || isFnStr(result)) {
|
|
882
919
|
await this.send("App.mockWxMethod", {
|
|
@@ -1025,19 +1062,22 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1025
1062
|
return this.nativeIns;
|
|
1026
1063
|
}
|
|
1027
1064
|
async changeRoute(method, url) {
|
|
1028
|
-
const currentPage = await this.
|
|
1065
|
+
const currentPage = await this.resolveRouteContextPage();
|
|
1029
1066
|
logChangeRouteDebug(`start method=${method} url=${url ?? "<none>"} current=${currentPage?.path ?? "<none>"}`);
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
await this.
|
|
1033
|
-
}
|
|
1067
|
+
try {
|
|
1068
|
+
if (currentPage && isPluginPath(currentPage.path)) await this.callPluginWxMethod(extractPluginId(currentPage.path), method, { url });
|
|
1069
|
+
else await this.callWxMethodWithTimeout(method, CHANGE_ROUTE_CALL_TIMEOUT, { url });
|
|
1070
|
+
} catch (error) {
|
|
1071
|
+
if (isCallWxMethodProtocolTimeout(error) || isOperationTimeoutError(error, CHANGE_ROUTE_CALL_TIMEOUT)) logChangeRouteDebug(`call-timeout method=${method} url=${url ?? "<none>"}`);
|
|
1072
|
+
else throw error;
|
|
1073
|
+
}
|
|
1034
1074
|
const expectedRoute = normalizeRoutePath(url);
|
|
1035
1075
|
const startedAt = Date.now();
|
|
1036
1076
|
let lastPage;
|
|
1037
1077
|
let lastError;
|
|
1038
1078
|
while (Date.now() - startedAt <= CHANGE_ROUTE_READY_TIMEOUT) {
|
|
1039
1079
|
try {
|
|
1040
|
-
const page = await this.
|
|
1080
|
+
const page = await this.readRoutePollingCurrentPage();
|
|
1041
1081
|
lastPage = page;
|
|
1042
1082
|
logChangeRouteDebug(`poll method=${method} url=${url ?? "<none>"} current=${page?.path ?? "<none>"}`);
|
|
1043
1083
|
if (!expectedRoute || normalizeRoutePath(page?.path) === expectedRoute) {
|
|
@@ -1049,7 +1089,7 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1049
1089
|
logChangeRouteDebug(`poll-error method=${method} url=${url ?? "<none>"} error=${error instanceof Error ? error.message : String(error)}`);
|
|
1050
1090
|
}
|
|
1051
1091
|
try {
|
|
1052
|
-
const stack = await this.
|
|
1092
|
+
const stack = await this.readRoutePollingPageStack();
|
|
1053
1093
|
const stackTop = stack[stack.length - 1];
|
|
1054
1094
|
if (stackTop) {
|
|
1055
1095
|
lastPage = stackTop;
|
|
@@ -1062,6 +1102,10 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1062
1102
|
} catch (error) {
|
|
1063
1103
|
lastError = error;
|
|
1064
1104
|
logChangeRouteDebug(`stack-error method=${method} url=${url ?? "<none>"} error=${error instanceof Error ? error.message : String(error)}`);
|
|
1105
|
+
if (isOperationTimeoutError(error, CHANGE_ROUTE_CONTEXT_TIMEOUT)) {
|
|
1106
|
+
await sleep(CHANGE_ROUTE_POLL_DELAY);
|
|
1107
|
+
continue;
|
|
1108
|
+
}
|
|
1065
1109
|
}
|
|
1066
1110
|
await sleep(CHANGE_ROUTE_POLL_DELAY);
|
|
1067
1111
|
}
|
|
@@ -1072,8 +1116,38 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1072
1116
|
logChangeRouteDebug(`timeout method=${method} url=${url ?? "<none>"} current=<none> error=${lastError instanceof Error ? lastError.message : String(lastError)}`);
|
|
1073
1117
|
throw lastError instanceof Error ? lastError : /* @__PURE__ */ new Error(`Timed out waiting route ${expectedRoute || "<current>"} after ${method}`);
|
|
1074
1118
|
}
|
|
1075
|
-
async
|
|
1076
|
-
|
|
1119
|
+
async resolveRouteContextPage() {
|
|
1120
|
+
const currentPageTask = this.currentPage().catch((error) => {
|
|
1121
|
+
if (isRouteContextProbeError(error)) return;
|
|
1122
|
+
throw error;
|
|
1123
|
+
});
|
|
1124
|
+
const timeoutTask = sleep(CHANGE_ROUTE_CONTEXT_TIMEOUT).then(() => void 0);
|
|
1125
|
+
try {
|
|
1126
|
+
return await Promise.race([currentPageTask, timeoutTask]);
|
|
1127
|
+
} finally {
|
|
1128
|
+
currentPageTask.catch(() => {});
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
async readRoutePollingCurrentPage() {
|
|
1132
|
+
const { pageId, path, query } = await this.send("App.getCurrentPage", {}, { timeout: CHANGE_ROUTE_CONTEXT_TIMEOUT });
|
|
1133
|
+
return Page.create(this.connection, {
|
|
1134
|
+
id: pageId,
|
|
1135
|
+
path,
|
|
1136
|
+
query
|
|
1137
|
+
}, this.pageMap);
|
|
1138
|
+
}
|
|
1139
|
+
async readRoutePollingPageStack() {
|
|
1140
|
+
const { pageStack } = await this.send("App.getPageStack", {}, { timeout: CHANGE_ROUTE_CONTEXT_TIMEOUT });
|
|
1141
|
+
return pageStack.map((page) => {
|
|
1142
|
+
return Page.create(this.connection, {
|
|
1143
|
+
id: page.pageId,
|
|
1144
|
+
path: page.path,
|
|
1145
|
+
query: page.query
|
|
1146
|
+
}, this.pageMap);
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
async send(method, params = {}, options) {
|
|
1150
|
+
return options ? await this.connection.send(method, params, options) : await this.connection.send(method, params);
|
|
1077
1151
|
}
|
|
1078
1152
|
onLogAdded = (payload) => {
|
|
1079
1153
|
this.emit("console", payload);
|
|
@@ -5241,11 +5241,10 @@ function deriveMenuButtonBoundingClientRect(systemInfo) {
|
|
|
5241
5241
|
const height = 32;
|
|
5242
5242
|
const top = 32;
|
|
5243
5243
|
const right = Math.max(systemInfo.windowWidth - 12, width);
|
|
5244
|
-
const left = Math.max(0, right - width);
|
|
5245
5244
|
return {
|
|
5246
|
-
bottom:
|
|
5245
|
+
bottom: 64,
|
|
5247
5246
|
height,
|
|
5248
|
-
left,
|
|
5247
|
+
left: Math.max(0, right - width),
|
|
5249
5248
|
right,
|
|
5250
5249
|
top,
|
|
5251
5250
|
width
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weapp-vite/miniprogram-automator",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.3",
|
|
5
5
|
"description": "完全兼容微信 miniprogram-automator 的现代化替代实现",
|
|
6
6
|
"author": "ice breaker <1324318532@qq.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"obug": "^2.1.1",
|
|
45
|
-
"ws": "^8.
|
|
45
|
+
"ws": "^8.21.0",
|
|
46
46
|
"@weapp-vite/qr": "1.1.0"
|
|
47
47
|
},
|
|
48
48
|
"publishConfig": {
|