@weapp-vite/miniprogram-automator 1.2.5 → 1.2.7
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 +83 -14
- package/dist/index.mjs +950 -74
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -223,6 +223,8 @@ function toStr(value) {
|
|
|
223
223
|
}
|
|
224
224
|
//#endregion
|
|
225
225
|
//#region src/Element.ts
|
|
226
|
+
const ELEMENT_QUERY_TIMEOUT = 2500;
|
|
227
|
+
const ELEMENT_WXML_TIMEOUT = 8e3;
|
|
226
228
|
/** Element 的实现。 */
|
|
227
229
|
var Element = class Element {
|
|
228
230
|
connection;
|
|
@@ -242,9 +244,9 @@ var Element = class Element {
|
|
|
242
244
|
this.videoId = options.videoId || null;
|
|
243
245
|
this.tagName = options.tagName;
|
|
244
246
|
}
|
|
245
|
-
async $(selector) {
|
|
247
|
+
async $(selector, options = {}) {
|
|
246
248
|
try {
|
|
247
|
-
const element = await this.send("Element.getElement", { selector });
|
|
249
|
+
const element = await this.send("Element.getElement", { selector }, { timeout: options.timeout ?? ELEMENT_QUERY_TIMEOUT });
|
|
248
250
|
return Element.create(this.connection, {
|
|
249
251
|
...element,
|
|
250
252
|
pageId: this.pageId
|
|
@@ -253,8 +255,8 @@ var Element = class Element {
|
|
|
253
255
|
return null;
|
|
254
256
|
}
|
|
255
257
|
}
|
|
256
|
-
async $$(selector) {
|
|
257
|
-
const { elements } = await this.send("Element.getElements", { selector });
|
|
258
|
+
async $$(selector, options = {}) {
|
|
259
|
+
const { elements } = await this.send("Element.getElements", { selector }, { timeout: options.timeout ?? ELEMENT_QUERY_TIMEOUT });
|
|
258
260
|
return elements.map((element) => {
|
|
259
261
|
return Element.create(this.connection, {
|
|
260
262
|
...element,
|
|
@@ -293,10 +295,10 @@ var Element = class Element {
|
|
|
293
295
|
return await this._property(name);
|
|
294
296
|
}
|
|
295
297
|
async wxml() {
|
|
296
|
-
return (await this.send("Element.getWXML", { type: "inner" })).wxml;
|
|
298
|
+
return (await this.send("Element.getWXML", { type: "inner" }, { timeout: ELEMENT_WXML_TIMEOUT })).wxml;
|
|
297
299
|
}
|
|
298
300
|
async outerWxml() {
|
|
299
|
-
return (await this.send("Element.getWXML", { type: "outer" })).wxml;
|
|
301
|
+
return (await this.send("Element.getWXML", { type: "outer" }, { timeout: ELEMENT_WXML_TIMEOUT })).wxml;
|
|
300
302
|
}
|
|
301
303
|
async style(name) {
|
|
302
304
|
if (!isStr(name)) throw new Error("name must be a string");
|
|
@@ -330,12 +332,12 @@ var Element = class Element {
|
|
|
330
332
|
async _property(name) {
|
|
331
333
|
return await this.getter(name, "getProperties", "properties");
|
|
332
334
|
}
|
|
333
|
-
async send(method, params = {}) {
|
|
335
|
+
async send(method, params = {}, options) {
|
|
334
336
|
params.elementId = this.id;
|
|
335
337
|
params.pageId = this.pageId;
|
|
336
338
|
if (this.nodeId) params.nodeId = this.nodeId;
|
|
337
339
|
if (this.videoId) params.videoId = this.videoId;
|
|
338
|
-
return await this.connection.send(method, params);
|
|
340
|
+
return options ? await this.connection.send(method, params, options) : await this.connection.send(method, params);
|
|
339
341
|
}
|
|
340
342
|
async callFunction(functionName, ...args) {
|
|
341
343
|
const { result } = await this.send("Element.callFunction", {
|
|
@@ -504,10 +506,13 @@ const debugProtocol = createDebug("automator:protocol");
|
|
|
504
506
|
const closeErrTip = "Connection closed, check if wechat web devTools is still running";
|
|
505
507
|
const REQUEST_TIMEOUT = 3e4;
|
|
506
508
|
const CONNECT_TIMEOUT = 3e4;
|
|
509
|
+
/** Page frame 定向消息失效、需要切换到 App-service Page 协议的 DevTools 版本。 */
|
|
510
|
+
const APP_SERVICE_PAGE_PROTOCOL_VERSIONS = /* @__PURE__ */ new Set(["2.01.2510290"]);
|
|
507
511
|
/** Connection 的实现。 */
|
|
508
512
|
var Connection = class Connection extends EventEmitter {
|
|
509
513
|
transport;
|
|
510
514
|
callbacks = /* @__PURE__ */ new Map();
|
|
515
|
+
useAppServicePageProtocol = false;
|
|
511
516
|
constructor(transport) {
|
|
512
517
|
super();
|
|
513
518
|
this.transport = transport;
|
|
@@ -548,6 +553,13 @@ var Connection = class Connection extends EventEmitter {
|
|
|
548
553
|
dispose() {
|
|
549
554
|
this.transport.close();
|
|
550
555
|
}
|
|
556
|
+
/** 根据 DevTools 版本选择稳定的 Page 协议实现。 */
|
|
557
|
+
configureToolInfo(info) {
|
|
558
|
+
this.useAppServicePageProtocol = APP_SERVICE_PAGE_PROTOCOL_VERSIONS.has(String(info.version ?? ""));
|
|
559
|
+
}
|
|
560
|
+
get prefersAppServicePageProtocol() {
|
|
561
|
+
return this.useAppServicePageProtocol;
|
|
562
|
+
}
|
|
551
563
|
onMessage = (message) => {
|
|
552
564
|
debugProtocol(`${dateFormat("yyyy-mm-dd HH:MM:ss:l")} ◀ RECV ${message}`);
|
|
553
565
|
const { id, method, error, result, params } = JSON.parse(message);
|
|
@@ -699,7 +711,7 @@ async function acquireAutomatorPortLease(preferredPort) {
|
|
|
699
711
|
}
|
|
700
712
|
//#endregion
|
|
701
713
|
//#region package.json
|
|
702
|
-
var version = "1.2.
|
|
714
|
+
var version = "1.2.7";
|
|
703
715
|
//#endregion
|
|
704
716
|
//#region src/Native.ts
|
|
705
717
|
/** Native 的实现。 */
|
|
@@ -750,7 +762,70 @@ var Native = class extends EventEmitter {
|
|
|
750
762
|
}
|
|
751
763
|
};
|
|
752
764
|
//#endregion
|
|
765
|
+
//#region src/pageRouteFallback.ts
|
|
766
|
+
function normalizeFallbackIdPart(value) {
|
|
767
|
+
return encodeURIComponent(value).replace(/%/g, "_");
|
|
768
|
+
}
|
|
769
|
+
function resolveFallbackTagName(selector) {
|
|
770
|
+
const tagSelector = selector.trim();
|
|
771
|
+
if (/^[a-z][\w-]*$/i.test(tagSelector)) return tagSelector.toLowerCase();
|
|
772
|
+
return "view";
|
|
773
|
+
}
|
|
774
|
+
/** 将 App-Service 查询到的渲染节点包装为 Element 兼容对象。 */
|
|
775
|
+
function createRouteFallbackElement(connection, elementMap, pageId, selector, node, index) {
|
|
776
|
+
const nodeId = typeof node.id === "string" && node.id ? normalizeFallbackIdPart(node.id) : String(index);
|
|
777
|
+
const elementId = `__weapp_vite_route_fallback_${pageId}_${normalizeFallbackIdPart(selector)}_${nodeId}_${index}`;
|
|
778
|
+
return Element.create(connection, {
|
|
779
|
+
elementId,
|
|
780
|
+
pageId,
|
|
781
|
+
tagName: resolveFallbackTagName(selector)
|
|
782
|
+
}, elementMap);
|
|
783
|
+
}
|
|
784
|
+
//#endregion
|
|
753
785
|
//#region src/Page.ts
|
|
786
|
+
const PAGE_QUERY_TIMEOUT = 2500;
|
|
787
|
+
const PAGE_DATA_TIMEOUT = 12e3;
|
|
788
|
+
const PAGE_DATA_PROTOCOL_TIMEOUT = 2500;
|
|
789
|
+
const PAGE_SET_DATA_TIMEOUT = 12e3;
|
|
790
|
+
const PAGE_SET_DATA_PROTOCOL_TIMEOUT = 2500;
|
|
791
|
+
const PAGE_CALL_METHOD_TIMEOUT = 12e3;
|
|
792
|
+
const PAGE_CALL_METHOD_PROTOCOL_TIMEOUT = 2500;
|
|
793
|
+
const PAGE_CALL_METHOD_FALLBACK_RETRIES = 3;
|
|
794
|
+
const PAGE_CALL_METHOD_FALLBACK_RETRY_DELAY = 300;
|
|
795
|
+
const PAGE_RENDERED_TIMEOUT = 15e3;
|
|
796
|
+
const PAGE_RENDERED_POLL_DELAY = 220;
|
|
797
|
+
const PAGE_RENDERED_QUERY_TIMEOUT = 5e3;
|
|
798
|
+
const PAGE_ROOT_SELECTORS = [
|
|
799
|
+
"page",
|
|
800
|
+
"body",
|
|
801
|
+
"weapp-app-shell",
|
|
802
|
+
"view"
|
|
803
|
+
];
|
|
804
|
+
function isProtocolTimeoutError(error, method) {
|
|
805
|
+
return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === method;
|
|
806
|
+
}
|
|
807
|
+
function isPageStackStaleError(error) {
|
|
808
|
+
return (error instanceof Error ? error.message : String(error)).includes("page is not on top of page stack");
|
|
809
|
+
}
|
|
810
|
+
function isPageMetaMissingError$1(error) {
|
|
811
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
812
|
+
return message.includes("getPageMetaByWebviewId") && message.includes("rawPath") && message.includes("is null");
|
|
813
|
+
}
|
|
814
|
+
function isCurrentFrameTimedOutError$1(error) {
|
|
815
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
816
|
+
return message.includes("unexpected current frame status timedout") || message.includes("[loader] unexpected current frame status timedout");
|
|
817
|
+
}
|
|
818
|
+
function isRecoverablePageProtocolError(error, method) {
|
|
819
|
+
return isProtocolTimeoutError(error, method) || isPageMetaMissingError$1(error) || isCurrentFrameTimedOutError$1(error);
|
|
820
|
+
}
|
|
821
|
+
function normalizeRoute(value) {
|
|
822
|
+
return String(value || "").replace(/^\/+/, "").replace(/\/+$/g, "");
|
|
823
|
+
}
|
|
824
|
+
function matchesDataset(node, expected) {
|
|
825
|
+
if (!expected) return true;
|
|
826
|
+
const dataset = node.dataset ?? {};
|
|
827
|
+
return Object.entries(expected).every(([key, value]) => String(dataset[key] ?? "") === String(value));
|
|
828
|
+
}
|
|
754
829
|
/** Page 的实现。 */
|
|
755
830
|
var Page = class Page {
|
|
756
831
|
connection;
|
|
@@ -758,11 +833,17 @@ var Page = class Page {
|
|
|
758
833
|
query = {};
|
|
759
834
|
id;
|
|
760
835
|
elementMap = /* @__PURE__ */ new Map();
|
|
836
|
+
preferAppServicePageProtocol = false;
|
|
761
837
|
constructor(connection, options) {
|
|
762
838
|
this.connection = connection;
|
|
763
839
|
this.id = options.id;
|
|
764
840
|
this.path = options.path;
|
|
765
841
|
this.query = options.query;
|
|
842
|
+
this.preferAppServicePageProtocol = connection.prefersAppServicePageProtocol;
|
|
843
|
+
}
|
|
844
|
+
updateFromOptions(options) {
|
|
845
|
+
this.path = options.path;
|
|
846
|
+
this.query = options.query;
|
|
766
847
|
}
|
|
767
848
|
async waitFor(condition) {
|
|
768
849
|
if (isNum(condition)) {
|
|
@@ -775,29 +856,41 @@ var Page = class Page {
|
|
|
775
856
|
}
|
|
776
857
|
if (isStr(condition)) await waitUntil(async () => (await this.$$(condition)).length > 0);
|
|
777
858
|
}
|
|
778
|
-
async $(selector) {
|
|
859
|
+
async $(selector, options = {}) {
|
|
860
|
+
if (options.routeOnly || options.fallback !== false && this.preferAppServicePageProtocol) return await this.queryRouteElement(selector, options);
|
|
779
861
|
try {
|
|
780
|
-
const element = await this.send("Page.getElement", { selector });
|
|
862
|
+
const element = await this.send("Page.getElement", { selector }, { timeout: options.timeout ?? PAGE_QUERY_TIMEOUT });
|
|
781
863
|
return Element.create(this.connection, {
|
|
782
864
|
...element,
|
|
783
865
|
pageId: this.id
|
|
784
866
|
}, this.elementMap);
|
|
785
|
-
} catch {
|
|
867
|
+
} catch (error) {
|
|
868
|
+
if (options.fallback !== false && isRecoverablePageProtocolError(error, "Page.getElement")) {
|
|
869
|
+
this.preferAppServicePageProtocol = true;
|
|
870
|
+
return await this.queryRouteElement(selector, options);
|
|
871
|
+
}
|
|
786
872
|
return null;
|
|
787
873
|
}
|
|
788
874
|
}
|
|
789
|
-
async $$(selector) {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
875
|
+
async $$(selector, options = {}) {
|
|
876
|
+
if (options.routeOnly || options.fallback !== false && this.preferAppServicePageProtocol) return await this.queryRouteElements(selector, options);
|
|
877
|
+
try {
|
|
878
|
+
const { elements } = await this.send("Page.getElements", { selector }, { timeout: options.timeout ?? PAGE_QUERY_TIMEOUT });
|
|
879
|
+
return elements.map((element) => {
|
|
880
|
+
return Element.create(this.connection, {
|
|
881
|
+
...element,
|
|
882
|
+
pageId: this.id
|
|
883
|
+
}, this.elementMap);
|
|
884
|
+
});
|
|
885
|
+
} catch (error) {
|
|
886
|
+
if (options.fallback === false || !isRecoverablePageProtocolError(error, "Page.getElements")) throw error;
|
|
887
|
+
this.preferAppServicePageProtocol = true;
|
|
888
|
+
return await this.queryRouteElements(selector, options);
|
|
889
|
+
}
|
|
797
890
|
}
|
|
798
|
-
async getElementByXpath(selector) {
|
|
891
|
+
async getElementByXpath(selector, options = {}) {
|
|
799
892
|
try {
|
|
800
|
-
const element = await this.send("Page.getElementByXpath", { selector });
|
|
893
|
+
const element = await this.send("Page.getElementByXpath", { selector }, { timeout: options.timeout ?? PAGE_QUERY_TIMEOUT });
|
|
801
894
|
return Element.create(this.connection, {
|
|
802
895
|
...element,
|
|
803
896
|
pageId: this.id
|
|
@@ -806,8 +899,8 @@ var Page = class Page {
|
|
|
806
899
|
return null;
|
|
807
900
|
}
|
|
808
901
|
}
|
|
809
|
-
async getElementsByXpath(selector) {
|
|
810
|
-
const { elements } = await this.send("Page.getElementsByXpath", { selector });
|
|
902
|
+
async getElementsByXpath(selector, options = {}) {
|
|
903
|
+
const { elements } = await this.send("Page.getElementsByXpath", { selector }, { timeout: options.timeout ?? PAGE_QUERY_TIMEOUT });
|
|
811
904
|
return elements.map((element) => {
|
|
812
905
|
return Element.create(this.connection, {
|
|
813
906
|
...element,
|
|
@@ -818,13 +911,542 @@ var Page = class Page {
|
|
|
818
911
|
async xpath(selector) {
|
|
819
912
|
return await this.getElementByXpath(selector);
|
|
820
913
|
}
|
|
821
|
-
async
|
|
914
|
+
async wxml() {
|
|
915
|
+
let lastError;
|
|
916
|
+
for (const selector of PAGE_ROOT_SELECTORS) try {
|
|
917
|
+
const element = await this.$(selector, { timeout: PAGE_QUERY_TIMEOUT });
|
|
918
|
+
if (!element) continue;
|
|
919
|
+
return await element.wxml();
|
|
920
|
+
} catch (error) {
|
|
921
|
+
lastError = error;
|
|
922
|
+
}
|
|
923
|
+
throw lastError instanceof Error ? lastError : /* @__PURE__ */ new Error("Failed to find page element");
|
|
924
|
+
}
|
|
925
|
+
async renderedNodes(selector, options = {}) {
|
|
926
|
+
const { result } = await this.connection.send("App.callFunction", {
|
|
927
|
+
functionDeclaration: `function (route, query, selector, scopeSelectors) {
|
|
928
|
+
function normalizeRoute(value) {
|
|
929
|
+
return String(value || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
930
|
+
}
|
|
931
|
+
function matchesQuery(page, expectedQuery) {
|
|
932
|
+
if (!expectedQuery || !Object.keys(expectedQuery).length) {
|
|
933
|
+
return true;
|
|
934
|
+
}
|
|
935
|
+
var actualQuery = page && (page.options || page.query || {});
|
|
936
|
+
return Object.keys(expectedQuery).every(function (key) {
|
|
937
|
+
var actualValue = String(actualQuery[key] == null ? '' : actualQuery[key]);
|
|
938
|
+
var expectedValue = String(expectedQuery[key]);
|
|
939
|
+
var decodedActualValue = actualValue;
|
|
940
|
+
try {
|
|
941
|
+
decodedActualValue = decodeURIComponent(actualValue);
|
|
942
|
+
}
|
|
943
|
+
catch (_) {
|
|
944
|
+
}
|
|
945
|
+
return actualValue === expectedValue
|
|
946
|
+
|| decodedActualValue === expectedValue
|
|
947
|
+
|| actualValue === encodeURIComponent(expectedValue);
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
var pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
951
|
+
var expectedRoute = normalizeRoute(route);
|
|
952
|
+
var page = null;
|
|
953
|
+
for (var index = pages.length - 1; index >= 0; index -= 1) {
|
|
954
|
+
var candidate = pages[index];
|
|
955
|
+
var candidateRoute = normalizeRoute(candidate && (candidate.path || candidate.route || candidate.__route__));
|
|
956
|
+
if ((!expectedRoute || candidateRoute === expectedRoute) && matchesQuery(candidate, query)) {
|
|
957
|
+
page = candidate;
|
|
958
|
+
break;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
if (!page) {
|
|
962
|
+
return [];
|
|
963
|
+
}
|
|
964
|
+
function createSelectorQuery(scope) {
|
|
965
|
+
var query = null;
|
|
966
|
+
var createdFromScope = false;
|
|
967
|
+
if (scope && typeof scope.createSelectorQuery === 'function') {
|
|
968
|
+
query = scope.createSelectorQuery();
|
|
969
|
+
createdFromScope = true;
|
|
970
|
+
}
|
|
971
|
+
else if (typeof wx !== 'undefined' && wx && typeof wx.createSelectorQuery === 'function') {
|
|
972
|
+
query = wx.createSelectorQuery();
|
|
973
|
+
}
|
|
974
|
+
else if (typeof page.createSelectorQuery === 'function') {
|
|
975
|
+
query = page.createSelectorQuery();
|
|
976
|
+
}
|
|
977
|
+
if (!query) {
|
|
978
|
+
return null;
|
|
979
|
+
}
|
|
980
|
+
if (!createdFromScope && typeof query.in === 'function') {
|
|
981
|
+
try {
|
|
982
|
+
query = query.in(scope || page);
|
|
983
|
+
}
|
|
984
|
+
catch (_) {
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
return query;
|
|
988
|
+
}
|
|
989
|
+
function pushUnique(list, seen, item) {
|
|
990
|
+
if (!item) {
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
var id = item.is || item.id || item.__wxWebviewId__ || item.__wxExparserNodeId__ || String(list.length);
|
|
994
|
+
if (seen[id]) {
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
seen[id] = true;
|
|
998
|
+
list.push(item);
|
|
999
|
+
}
|
|
1000
|
+
function collectScopes(root) {
|
|
1001
|
+
var scopes = [];
|
|
1002
|
+
var seen = {};
|
|
1003
|
+
var queue = [];
|
|
1004
|
+
pushUnique(scopes, seen, root);
|
|
1005
|
+
queue.push(root);
|
|
1006
|
+
for (var queueIndex = 0; queueIndex < queue.length && queueIndex < 60; queueIndex += 1) {
|
|
1007
|
+
var scope = queue[queueIndex];
|
|
1008
|
+
if (!scope || typeof scope.selectAllComponents !== 'function') {
|
|
1009
|
+
continue;
|
|
1010
|
+
}
|
|
1011
|
+
var children = [];
|
|
1012
|
+
var componentSelectors = Array.isArray(scopeSelectors) ? scopeSelectors.slice() : [];
|
|
1013
|
+
componentSelectors.push(selector, '*', 'weapp-app-shell', 'weapp-layout-default');
|
|
1014
|
+
for (var selectorIndex = 0; selectorIndex < componentSelectors.length; selectorIndex += 1) {
|
|
1015
|
+
if (!componentSelectors[selectorIndex]) {
|
|
1016
|
+
continue;
|
|
1017
|
+
}
|
|
1018
|
+
try {
|
|
1019
|
+
var selected = scope.selectAllComponents(componentSelectors[selectorIndex]);
|
|
1020
|
+
if (Array.isArray(selected)) {
|
|
1021
|
+
children = children.concat(selected);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
catch (_) {
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
for (var childIndex = 0; childIndex < children.length; childIndex += 1) {
|
|
1028
|
+
var child = children[childIndex];
|
|
1029
|
+
var previousLength = scopes.length;
|
|
1030
|
+
pushUnique(scopes, seen, child);
|
|
1031
|
+
if (scopes.length > previousLength) {
|
|
1032
|
+
queue.push(child);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
return scopes;
|
|
1037
|
+
}
|
|
1038
|
+
function queryScope(scope) {
|
|
1039
|
+
return new Promise(function (resolve) {
|
|
1040
|
+
var settled = false;
|
|
1041
|
+
var timer = setTimeout(function () {
|
|
1042
|
+
if (settled) {
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
settled = true;
|
|
1046
|
+
resolve([]);
|
|
1047
|
+
}, 800);
|
|
1048
|
+
function finish(nodes) {
|
|
1049
|
+
if (settled) {
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
settled = true;
|
|
1053
|
+
clearTimeout(timer);
|
|
1054
|
+
resolve(Array.isArray(nodes) ? nodes : nodes ? [nodes] : []);
|
|
1055
|
+
}
|
|
1056
|
+
try {
|
|
1057
|
+
var query = createSelectorQuery(scope);
|
|
1058
|
+
if (!query) {
|
|
1059
|
+
finish([]);
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
query
|
|
1063
|
+
.selectAll(selector)
|
|
1064
|
+
.fields({
|
|
1065
|
+
dataset: true,
|
|
1066
|
+
id: true,
|
|
1067
|
+
rect: true,
|
|
1068
|
+
size: true
|
|
1069
|
+
}, function (nodes) {
|
|
1070
|
+
finish(nodes);
|
|
1071
|
+
})
|
|
1072
|
+
.exec();
|
|
1073
|
+
}
|
|
1074
|
+
catch (_) {
|
|
1075
|
+
finish([]);
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
return new Promise(function (resolve) {
|
|
1080
|
+
try {
|
|
1081
|
+
var scopes = collectScopes(page);
|
|
1082
|
+
var collected = [];
|
|
1083
|
+
var index = 0;
|
|
1084
|
+
function next() {
|
|
1085
|
+
if (index >= scopes.length) {
|
|
1086
|
+
resolve(collected);
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
var scope = scopes[index];
|
|
1090
|
+
index += 1;
|
|
1091
|
+
queryScope(scope).then(function (nodes) {
|
|
1092
|
+
collected = collected.concat(nodes);
|
|
1093
|
+
next();
|
|
1094
|
+
}, function () {
|
|
1095
|
+
next();
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
next();
|
|
1099
|
+
}
|
|
1100
|
+
catch (_) {
|
|
1101
|
+
resolve([]);
|
|
1102
|
+
}
|
|
1103
|
+
});
|
|
1104
|
+
}`,
|
|
1105
|
+
args: [
|
|
1106
|
+
normalizeRoute(this.path),
|
|
1107
|
+
this.query,
|
|
1108
|
+
selector,
|
|
1109
|
+
options.componentSelectors ?? []
|
|
1110
|
+
]
|
|
1111
|
+
}, { timeout: options.timeout ?? PAGE_RENDERED_QUERY_TIMEOUT });
|
|
1112
|
+
return Array.isArray(result) ? result : [];
|
|
1113
|
+
}
|
|
1114
|
+
async renderedSelectorNodes(selectors, options = {}) {
|
|
1115
|
+
const normalizedSelectors = selectors.map((selector) => String(selector || "").trim()).filter(Boolean);
|
|
1116
|
+
if (normalizedSelectors.length === 0) return {};
|
|
1117
|
+
const { result } = await this.connection.send("App.callFunction", {
|
|
1118
|
+
functionDeclaration: `function (route, query, selectors, scopeSelectors) {
|
|
1119
|
+
function normalizeRoute(value) {
|
|
1120
|
+
return String(value || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
1121
|
+
}
|
|
1122
|
+
function matchesQuery(page, expectedQuery) {
|
|
1123
|
+
if (!expectedQuery || !Object.keys(expectedQuery).length) {
|
|
1124
|
+
return true;
|
|
1125
|
+
}
|
|
1126
|
+
var actualQuery = page && (page.options || page.query || {});
|
|
1127
|
+
return Object.keys(expectedQuery).every(function (key) {
|
|
1128
|
+
var actualValue = String(actualQuery[key] == null ? '' : actualQuery[key]);
|
|
1129
|
+
var expectedValue = String(expectedQuery[key]);
|
|
1130
|
+
var decodedActualValue = actualValue;
|
|
1131
|
+
try {
|
|
1132
|
+
decodedActualValue = decodeURIComponent(actualValue);
|
|
1133
|
+
}
|
|
1134
|
+
catch (_) {
|
|
1135
|
+
}
|
|
1136
|
+
return actualValue === expectedValue
|
|
1137
|
+
|| decodedActualValue === expectedValue
|
|
1138
|
+
|| actualValue === encodeURIComponent(expectedValue);
|
|
1139
|
+
});
|
|
1140
|
+
}
|
|
1141
|
+
function createSelectorQuery(scope, page) {
|
|
1142
|
+
var query = null;
|
|
1143
|
+
var createdFromScope = false;
|
|
1144
|
+
if (scope && typeof scope.createSelectorQuery === 'function') {
|
|
1145
|
+
query = scope.createSelectorQuery();
|
|
1146
|
+
createdFromScope = true;
|
|
1147
|
+
}
|
|
1148
|
+
else if (typeof wx !== 'undefined' && wx && typeof wx.createSelectorQuery === 'function') {
|
|
1149
|
+
query = wx.createSelectorQuery();
|
|
1150
|
+
}
|
|
1151
|
+
else if (page && typeof page.createSelectorQuery === 'function') {
|
|
1152
|
+
query = page.createSelectorQuery();
|
|
1153
|
+
}
|
|
1154
|
+
if (!query) {
|
|
1155
|
+
return null;
|
|
1156
|
+
}
|
|
1157
|
+
if (!createdFromScope && typeof query.in === 'function') {
|
|
1158
|
+
try {
|
|
1159
|
+
query = query.in(scope || page);
|
|
1160
|
+
}
|
|
1161
|
+
catch (_) {
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return query;
|
|
1165
|
+
}
|
|
1166
|
+
function pushUnique(list, seen, item) {
|
|
1167
|
+
if (!item) {
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
var id = item.is || item.id || item.__wxWebviewId__ || item.__wxExparserNodeId__ || String(list.length);
|
|
1171
|
+
if (seen[id]) {
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
seen[id] = true;
|
|
1175
|
+
list.push(item);
|
|
1176
|
+
}
|
|
1177
|
+
function collectScopes(root, selectorList) {
|
|
1178
|
+
var scopes = [];
|
|
1179
|
+
var seen = {};
|
|
1180
|
+
var queue = [];
|
|
1181
|
+
pushUnique(scopes, seen, root);
|
|
1182
|
+
queue.push(root);
|
|
1183
|
+
for (var queueIndex = 0; queueIndex < queue.length && queueIndex < 30; queueIndex += 1) {
|
|
1184
|
+
var scope = queue[queueIndex];
|
|
1185
|
+
if (!scope || typeof scope.selectAllComponents !== 'function') {
|
|
1186
|
+
continue;
|
|
1187
|
+
}
|
|
1188
|
+
var children = [];
|
|
1189
|
+
var componentSelectors = Array.isArray(scopeSelectors) ? scopeSelectors.slice() : [];
|
|
1190
|
+
for (var selectorIndex = 0; selectorIndex < selectorList.length; selectorIndex += 1) {
|
|
1191
|
+
componentSelectors.push(selectorList[selectorIndex]);
|
|
1192
|
+
}
|
|
1193
|
+
componentSelectors.push('*', 'weapp-app-shell', 'weapp-layout-default');
|
|
1194
|
+
for (var componentIndex = 0; componentIndex < componentSelectors.length; componentIndex += 1) {
|
|
1195
|
+
if (!componentSelectors[componentIndex]) {
|
|
1196
|
+
continue;
|
|
1197
|
+
}
|
|
1198
|
+
try {
|
|
1199
|
+
var selected = scope.selectAllComponents(componentSelectors[componentIndex]);
|
|
1200
|
+
if (Array.isArray(selected)) {
|
|
1201
|
+
children = children.concat(selected);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
catch (_) {
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
for (var childIndex = 0; childIndex < children.length; childIndex += 1) {
|
|
1208
|
+
var child = children[childIndex];
|
|
1209
|
+
var previousLength = scopes.length;
|
|
1210
|
+
pushUnique(scopes, seen, child);
|
|
1211
|
+
if (scopes.length > previousLength) {
|
|
1212
|
+
queue.push(child);
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
return scopes;
|
|
1217
|
+
}
|
|
1218
|
+
function queryScope(scope, page, selector) {
|
|
1219
|
+
return new Promise(function (resolve) {
|
|
1220
|
+
var settled = false;
|
|
1221
|
+
var timer = setTimeout(function () {
|
|
1222
|
+
if (settled) {
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
settled = true;
|
|
1226
|
+
resolve([]);
|
|
1227
|
+
}, 450);
|
|
1228
|
+
function finish(nodes) {
|
|
1229
|
+
if (settled) {
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
settled = true;
|
|
1233
|
+
clearTimeout(timer);
|
|
1234
|
+
resolve(Array.isArray(nodes) ? nodes : nodes ? [nodes] : []);
|
|
1235
|
+
}
|
|
1236
|
+
try {
|
|
1237
|
+
var query = createSelectorQuery(scope, page);
|
|
1238
|
+
if (!query) {
|
|
1239
|
+
finish([]);
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
query
|
|
1243
|
+
.selectAll(selector)
|
|
1244
|
+
.fields({
|
|
1245
|
+
dataset: true,
|
|
1246
|
+
id: true,
|
|
1247
|
+
rect: true,
|
|
1248
|
+
size: true
|
|
1249
|
+
}, function (nodes) {
|
|
1250
|
+
finish(nodes);
|
|
1251
|
+
})
|
|
1252
|
+
.exec();
|
|
1253
|
+
}
|
|
1254
|
+
catch (_) {
|
|
1255
|
+
finish([]);
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
var selectorList = Array.isArray(selectors)
|
|
1260
|
+
? selectors.map(function (selector) {
|
|
1261
|
+
return String(selector || '').trim();
|
|
1262
|
+
}).filter(Boolean)
|
|
1263
|
+
: [];
|
|
1264
|
+
if (!selectorList.length) {
|
|
1265
|
+
return {};
|
|
1266
|
+
}
|
|
1267
|
+
var pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
1268
|
+
var expectedRoute = normalizeRoute(route);
|
|
1269
|
+
var page = null;
|
|
1270
|
+
for (var index = pages.length - 1; index >= 0; index -= 1) {
|
|
1271
|
+
var candidate = pages[index];
|
|
1272
|
+
var candidateRoute = normalizeRoute(candidate && (candidate.path || candidate.route || candidate.__route__));
|
|
1273
|
+
if ((!expectedRoute || candidateRoute === expectedRoute) && matchesQuery(candidate, query)) {
|
|
1274
|
+
page = candidate;
|
|
1275
|
+
break;
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
if (!page) {
|
|
1279
|
+
return {};
|
|
1280
|
+
}
|
|
1281
|
+
return new Promise(function (resolve) {
|
|
1282
|
+
try {
|
|
1283
|
+
var result = {};
|
|
1284
|
+
var scopes = collectScopes(page, selectorList);
|
|
1285
|
+
var startedAt = Date.now();
|
|
1286
|
+
var maxQueries = 40;
|
|
1287
|
+
var queryCount = 0;
|
|
1288
|
+
var selectorIndex = 0;
|
|
1289
|
+
var scopeIndex = 0;
|
|
1290
|
+
function next() {
|
|
1291
|
+
if (selectorIndex >= selectorList.length || queryCount >= maxQueries || Date.now() - startedAt > 1800) {
|
|
1292
|
+
resolve(result);
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
var selector = selectorList[selectorIndex];
|
|
1296
|
+
if (scopeIndex >= scopes.length) {
|
|
1297
|
+
selectorIndex += 1;
|
|
1298
|
+
scopeIndex = 0;
|
|
1299
|
+
next();
|
|
1300
|
+
return;
|
|
1301
|
+
}
|
|
1302
|
+
var scope = scopes[scopeIndex];
|
|
1303
|
+
scopeIndex += 1;
|
|
1304
|
+
queryCount += 1;
|
|
1305
|
+
queryScope(scope, page, selector).then(function (nodes) {
|
|
1306
|
+
if (Array.isArray(nodes) && nodes.length > 0) {
|
|
1307
|
+
result[selector] = (result[selector] || []).concat(nodes);
|
|
1308
|
+
selectorIndex += 1;
|
|
1309
|
+
scopeIndex = 0;
|
|
1310
|
+
}
|
|
1311
|
+
next();
|
|
1312
|
+
}, function () {
|
|
1313
|
+
next();
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
next();
|
|
1317
|
+
}
|
|
1318
|
+
catch (_) {
|
|
1319
|
+
resolve({});
|
|
1320
|
+
}
|
|
1321
|
+
});
|
|
1322
|
+
}`,
|
|
1323
|
+
args: [
|
|
1324
|
+
normalizeRoute(this.path),
|
|
1325
|
+
this.query,
|
|
1326
|
+
normalizedSelectors,
|
|
1327
|
+
options.componentSelectors ?? []
|
|
1328
|
+
]
|
|
1329
|
+
}, { timeout: options.timeout ?? PAGE_RENDERED_QUERY_TIMEOUT });
|
|
1330
|
+
return result && typeof result === "object" && !Array.isArray(result) ? result : {};
|
|
1331
|
+
}
|
|
1332
|
+
async waitForRendered(options = {}) {
|
|
1333
|
+
const timeout = options.timeout ?? PAGE_RENDERED_TIMEOUT;
|
|
1334
|
+
const start = Date.now();
|
|
1335
|
+
let lastWxml = "";
|
|
1336
|
+
let lastRenderedNodes = [];
|
|
1337
|
+
let lastError;
|
|
1338
|
+
while (Date.now() - start <= timeout) {
|
|
1339
|
+
try {
|
|
1340
|
+
if (options.selector) {
|
|
1341
|
+
const nodes = await this.renderedNodes(options.selector, {
|
|
1342
|
+
componentSelectors: options.componentSelectors,
|
|
1343
|
+
timeout: Math.min(PAGE_RENDERED_QUERY_TIMEOUT, Math.max(1, timeout - (Date.now() - start)))
|
|
1344
|
+
});
|
|
1345
|
+
lastRenderedNodes = nodes;
|
|
1346
|
+
lastError = void 0;
|
|
1347
|
+
if (nodes.find((node) => matchesDataset(node, options.dataset))) return JSON.stringify({
|
|
1348
|
+
selector: options.selector,
|
|
1349
|
+
nodes
|
|
1350
|
+
});
|
|
1351
|
+
} else {
|
|
1352
|
+
const wxml = await this.wxml();
|
|
1353
|
+
lastWxml = wxml;
|
|
1354
|
+
lastError = void 0;
|
|
1355
|
+
const normalized = wxml.trim();
|
|
1356
|
+
if (options.predicate?.(wxml)) return wxml;
|
|
1357
|
+
if (options.text && normalized.includes(options.text)) return wxml;
|
|
1358
|
+
if (!options.text && !options.predicate && normalized && normalized !== "<text></text>") return wxml;
|
|
1359
|
+
}
|
|
1360
|
+
} catch (error) {
|
|
1361
|
+
lastError = error;
|
|
1362
|
+
}
|
|
1363
|
+
await sleep$1(PAGE_RENDERED_POLL_DELAY);
|
|
1364
|
+
}
|
|
1365
|
+
const reason = lastError instanceof Error ? lastError.message : String(lastError ?? "condition not met");
|
|
1366
|
+
const expected = options.selector ? ` selector=${options.selector} dataset=${JSON.stringify(options.dataset ?? {})}` : options.text ? ` text=${options.text}` : options.predicate ? " predicate=true" : " non-empty wxml";
|
|
1367
|
+
const latest = options.selector ? JSON.stringify(lastRenderedNodes).slice(0, 500) : lastWxml.slice(0, 500);
|
|
1368
|
+
throw new Error(`Timed out waiting page rendered:${expected}; reason=${reason}; latest=${latest}`);
|
|
1369
|
+
}
|
|
1370
|
+
async data(path, options = {}) {
|
|
822
1371
|
const payload = {};
|
|
823
1372
|
if (path) payload.path = path;
|
|
824
|
-
|
|
1373
|
+
const timeout = options.timeout ?? PAGE_DATA_TIMEOUT;
|
|
1374
|
+
if (options.routeOnly || options.fallback !== false && this.preferAppServicePageProtocol) return await this.readRouteData(path, timeout);
|
|
1375
|
+
try {
|
|
1376
|
+
return (await this.send("Page.getData", payload, { timeout: Math.min(timeout, PAGE_DATA_PROTOCOL_TIMEOUT) })).data;
|
|
1377
|
+
} catch (error) {
|
|
1378
|
+
if (options.fallback === false) throw error;
|
|
1379
|
+
if (!isRecoverablePageProtocolError(error, "Page.getData")) throw error;
|
|
1380
|
+
this.preferAppServicePageProtocol = true;
|
|
1381
|
+
return await this.readRouteData(path, timeout);
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
async readRouteData(path, timeout) {
|
|
1385
|
+
return (await this.connection.send("App.callFunction", {
|
|
1386
|
+
functionDeclaration: `function (route, query, dataPath) {
|
|
1387
|
+
function normalizeRoute(value) {
|
|
1388
|
+
return String(value || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
1389
|
+
}
|
|
1390
|
+
function matchesQuery(page, expectedQuery) {
|
|
1391
|
+
if (!expectedQuery || !Object.keys(expectedQuery).length) {
|
|
1392
|
+
return true;
|
|
1393
|
+
}
|
|
1394
|
+
var actualQuery = page && (page.options || page.query || {});
|
|
1395
|
+
return Object.keys(expectedQuery).every(function (key) {
|
|
1396
|
+
var actualValue = String(actualQuery[key] == null ? '' : actualQuery[key]);
|
|
1397
|
+
var expectedValue = String(expectedQuery[key]);
|
|
1398
|
+
var decodedActualValue = actualValue;
|
|
1399
|
+
try {
|
|
1400
|
+
decodedActualValue = decodeURIComponent(actualValue);
|
|
1401
|
+
}
|
|
1402
|
+
catch (_) {
|
|
1403
|
+
}
|
|
1404
|
+
return actualValue === expectedValue
|
|
1405
|
+
|| decodedActualValue === expectedValue
|
|
1406
|
+
|| actualValue === encodeURIComponent(expectedValue);
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
function readPath(data, path) {
|
|
1410
|
+
if (!path) {
|
|
1411
|
+
return data;
|
|
1412
|
+
}
|
|
1413
|
+
if (data && Object.prototype.hasOwnProperty.call(data, path)) {
|
|
1414
|
+
return data[path];
|
|
1415
|
+
}
|
|
1416
|
+
return String(path).replace(/\\[(\\d+)\\]/g, '.$1').split('.').filter(Boolean).reduce(function (current, segment) {
|
|
1417
|
+
return current == null ? undefined : current[segment];
|
|
1418
|
+
}, data);
|
|
1419
|
+
}
|
|
1420
|
+
var pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
1421
|
+
var normalizedRoute = normalizeRoute(route);
|
|
1422
|
+
for (var index = pages.length - 1; index >= 0; index -= 1) {
|
|
1423
|
+
var page = pages[index];
|
|
1424
|
+
var pageRoute = normalizeRoute(page.path || page.route || page.__route__);
|
|
1425
|
+
if (pageRoute === normalizedRoute && matchesQuery(page, query)) {
|
|
1426
|
+
return readPath(page.data || {}, dataPath);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
return undefined;
|
|
1430
|
+
}`,
|
|
1431
|
+
args: [
|
|
1432
|
+
this.path,
|
|
1433
|
+
this.query,
|
|
1434
|
+
path
|
|
1435
|
+
]
|
|
1436
|
+
}, { timeout })).result;
|
|
825
1437
|
}
|
|
826
1438
|
async setData(data) {
|
|
827
|
-
|
|
1439
|
+
if (this.preferAppServicePageProtocol) {
|
|
1440
|
+
await this.setRouteData(data);
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
try {
|
|
1444
|
+
await this.send("Page.setData", { data }, { timeout: PAGE_SET_DATA_PROTOCOL_TIMEOUT });
|
|
1445
|
+
} catch (error) {
|
|
1446
|
+
if (!isRecoverablePageProtocolError(error, "Page.setData") && !isPageStackStaleError(error)) throw error;
|
|
1447
|
+
this.preferAppServicePageProtocol = true;
|
|
1448
|
+
await this.setRouteData(data);
|
|
1449
|
+
}
|
|
828
1450
|
}
|
|
829
1451
|
async size() {
|
|
830
1452
|
const [width, height] = await this.windowProperty(["document.documentElement.scrollWidth", "document.documentElement.scrollHeight"]);
|
|
@@ -834,10 +1456,146 @@ var Page = class Page {
|
|
|
834
1456
|
};
|
|
835
1457
|
}
|
|
836
1458
|
async callMethod(method, ...args) {
|
|
837
|
-
return
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
1459
|
+
return await this.callMethodWithOptions(method, {}, ...args);
|
|
1460
|
+
}
|
|
1461
|
+
async callMethodWithOptions(method, options = {}, ...args) {
|
|
1462
|
+
if (options.routeOnly || options.fallback !== false && this.preferAppServicePageProtocol) return await this.callRouteMethod(method, args, options.timeout);
|
|
1463
|
+
try {
|
|
1464
|
+
return (await this.send("Page.callMethod", {
|
|
1465
|
+
method,
|
|
1466
|
+
args
|
|
1467
|
+
}, { timeout: options.timeout ?? PAGE_CALL_METHOD_PROTOCOL_TIMEOUT })).result;
|
|
1468
|
+
} catch (error) {
|
|
1469
|
+
if (options.fallback === false) throw error;
|
|
1470
|
+
if (!isRecoverablePageProtocolError(error, "Page.callMethod") && !isPageStackStaleError(error)) throw error;
|
|
1471
|
+
this.preferAppServicePageProtocol = true;
|
|
1472
|
+
}
|
|
1473
|
+
return await this.callRouteMethod(method, args, options.timeout);
|
|
1474
|
+
}
|
|
1475
|
+
async queryRouteElement(selector, options) {
|
|
1476
|
+
return (await this.queryRouteElements(selector, options))[0] ?? null;
|
|
1477
|
+
}
|
|
1478
|
+
async queryRouteElements(selector, options) {
|
|
1479
|
+
return (await this.renderedNodes(selector, {
|
|
1480
|
+
componentSelectors: options.componentSelectors,
|
|
1481
|
+
timeout: options.timeout ?? PAGE_QUERY_TIMEOUT
|
|
1482
|
+
})).map((node, index) => createRouteFallbackElement(this.connection, this.elementMap, this.id, selector, node, index));
|
|
1483
|
+
}
|
|
1484
|
+
async callRouteMethod(method, args, timeout = PAGE_CALL_METHOD_TIMEOUT) {
|
|
1485
|
+
let latestResult;
|
|
1486
|
+
for (let attempt = 1; attempt <= PAGE_CALL_METHOD_FALLBACK_RETRIES; attempt += 1) {
|
|
1487
|
+
try {
|
|
1488
|
+
const fallbackResult = (await this.connection.send("App.callFunction", {
|
|
1489
|
+
functionDeclaration: `async function (route, query, method, args) {
|
|
1490
|
+
var pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
1491
|
+
var normalizedRoute = String(route || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
1492
|
+
function methodResult(value) {
|
|
1493
|
+
return {
|
|
1494
|
+
__weappVitePageMethodFound: true,
|
|
1495
|
+
value: value
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
function matchesQuery(page, expectedQuery) {
|
|
1499
|
+
if (!expectedQuery || !Object.keys(expectedQuery).length) {
|
|
1500
|
+
return true;
|
|
1501
|
+
}
|
|
1502
|
+
var actualQuery = page && (page.options || page.query || {});
|
|
1503
|
+
return Object.keys(expectedQuery).every(function (key) {
|
|
1504
|
+
var actualValue = String(actualQuery[key] == null ? '' : actualQuery[key]);
|
|
1505
|
+
var expectedValue = String(expectedQuery[key]);
|
|
1506
|
+
var decodedActualValue = actualValue;
|
|
1507
|
+
try {
|
|
1508
|
+
decodedActualValue = decodeURIComponent(actualValue);
|
|
1509
|
+
}
|
|
1510
|
+
catch (_) {
|
|
1511
|
+
}
|
|
1512
|
+
return actualValue === expectedValue
|
|
1513
|
+
|| decodedActualValue === expectedValue
|
|
1514
|
+
|| actualValue === encodeURIComponent(expectedValue);
|
|
1515
|
+
});
|
|
1516
|
+
}
|
|
1517
|
+
for (var index = pages.length - 1; index >= 0; index -= 1) {
|
|
1518
|
+
var page = pages[index];
|
|
1519
|
+
var pageRoute = String(page.path || page.route || page.__route__ || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
1520
|
+
if (pageRoute === normalizedRoute && matchesQuery(page, query) && typeof page[method] === 'function') {
|
|
1521
|
+
return methodResult(await page[method].apply(page, args || []));
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
for (var fallbackIndex = pages.length - 1; fallbackIndex >= 0; fallbackIndex -= 1) {
|
|
1525
|
+
var fallbackPage = pages[fallbackIndex];
|
|
1526
|
+
if (matchesQuery(fallbackPage, query) && typeof fallbackPage[method] === 'function') {
|
|
1527
|
+
return methodResult(await fallbackPage[method].apply(fallbackPage, args || []));
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
return {
|
|
1531
|
+
__weappVitePageMethodFound: false
|
|
1532
|
+
};
|
|
1533
|
+
}`,
|
|
1534
|
+
args: [
|
|
1535
|
+
this.path,
|
|
1536
|
+
this.query,
|
|
1537
|
+
method,
|
|
1538
|
+
args
|
|
1539
|
+
]
|
|
1540
|
+
}, { timeout })).result;
|
|
1541
|
+
if (fallbackResult && typeof fallbackResult === "object" && fallbackResult.__weappVitePageMethodFound === true) return fallbackResult.value;
|
|
1542
|
+
latestResult = fallbackResult && typeof fallbackResult === "object" && fallbackResult.__weappVitePageMethodFound === false ? void 0 : fallbackResult;
|
|
1543
|
+
if (latestResult !== void 0 || attempt === PAGE_CALL_METHOD_FALLBACK_RETRIES) return latestResult;
|
|
1544
|
+
} catch (error) {
|
|
1545
|
+
if (!isProtocolTimeoutError(error, "App.callFunction") || attempt === PAGE_CALL_METHOD_FALLBACK_RETRIES) throw error;
|
|
1546
|
+
}
|
|
1547
|
+
await sleep$1(PAGE_CALL_METHOD_FALLBACK_RETRY_DELAY);
|
|
1548
|
+
}
|
|
1549
|
+
return latestResult;
|
|
1550
|
+
}
|
|
1551
|
+
async setRouteData(data) {
|
|
1552
|
+
for (let attempt = 1; attempt <= PAGE_CALL_METHOD_FALLBACK_RETRIES; attempt += 1) {
|
|
1553
|
+
try {
|
|
1554
|
+
await this.connection.send("App.callFunction", {
|
|
1555
|
+
functionDeclaration: `function (route, query, data) {
|
|
1556
|
+
var pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
1557
|
+
var normalizedRoute = String(route || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
1558
|
+
function matchesQuery(page, expectedQuery) {
|
|
1559
|
+
if (!expectedQuery || !Object.keys(expectedQuery).length) {
|
|
1560
|
+
return true;
|
|
1561
|
+
}
|
|
1562
|
+
var actualQuery = page && (page.options || page.query || {});
|
|
1563
|
+
return Object.keys(expectedQuery).every(function (key) {
|
|
1564
|
+
var actualValue = String(actualQuery[key] == null ? '' : actualQuery[key]);
|
|
1565
|
+
var expectedValue = String(expectedQuery[key]);
|
|
1566
|
+
var decodedActualValue = actualValue;
|
|
1567
|
+
try {
|
|
1568
|
+
decodedActualValue = decodeURIComponent(actualValue);
|
|
1569
|
+
}
|
|
1570
|
+
catch (_) {
|
|
1571
|
+
}
|
|
1572
|
+
return actualValue === expectedValue
|
|
1573
|
+
|| decodedActualValue === expectedValue
|
|
1574
|
+
|| actualValue === encodeURIComponent(expectedValue);
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1577
|
+
for (var index = pages.length - 1; index >= 0; index -= 1) {
|
|
1578
|
+
var page = pages[index];
|
|
1579
|
+
var pageRoute = String(page.path || page.route || page.__route__ || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
1580
|
+
if (pageRoute === normalizedRoute && matchesQuery(page, query) && typeof page.setData === 'function') {
|
|
1581
|
+
page.setData(data || {});
|
|
1582
|
+
return true;
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
return false;
|
|
1586
|
+
}`,
|
|
1587
|
+
args: [
|
|
1588
|
+
this.path,
|
|
1589
|
+
this.query,
|
|
1590
|
+
data
|
|
1591
|
+
]
|
|
1592
|
+
}, { timeout: PAGE_SET_DATA_TIMEOUT });
|
|
1593
|
+
return;
|
|
1594
|
+
} catch (error) {
|
|
1595
|
+
if (!isProtocolTimeoutError(error, "App.callFunction") || attempt === PAGE_CALL_METHOD_FALLBACK_RETRIES) throw error;
|
|
1596
|
+
}
|
|
1597
|
+
await sleep$1(PAGE_CALL_METHOD_FALLBACK_RETRY_DELAY);
|
|
1598
|
+
}
|
|
841
1599
|
}
|
|
842
1600
|
async scrollTop() {
|
|
843
1601
|
const bodyScrollTop = await this.windowProperty("document.body.scrollTop");
|
|
@@ -849,13 +1607,16 @@ var Page = class Page {
|
|
|
849
1607
|
const properties = (await this.send("Page.getWindowProperties", { names })).properties;
|
|
850
1608
|
return isStr(name) ? properties[0] : properties;
|
|
851
1609
|
}
|
|
852
|
-
async send(method, params = {}) {
|
|
1610
|
+
async send(method, params = {}, options) {
|
|
853
1611
|
params.pageId = this.id;
|
|
854
|
-
return await this.connection.send(method, params);
|
|
1612
|
+
return options ? await this.connection.send(method, params, options) : await this.connection.send(method, params);
|
|
855
1613
|
}
|
|
856
1614
|
static create(connection, options, pageMap) {
|
|
857
1615
|
const existing = pageMap.get(options.id);
|
|
858
|
-
if (existing)
|
|
1616
|
+
if (existing) {
|
|
1617
|
+
existing.updateFromOptions(options);
|
|
1618
|
+
return existing;
|
|
1619
|
+
}
|
|
859
1620
|
const page = new Page(connection, options);
|
|
860
1621
|
pageMap.set(options.id, page);
|
|
861
1622
|
return page;
|
|
@@ -866,7 +1627,7 @@ var Page = class Page {
|
|
|
866
1627
|
/**
|
|
867
1628
|
* @file 二维码与插件路径工具。
|
|
868
1629
|
*/
|
|
869
|
-
const regPluginId = /^plugin-private
|
|
1630
|
+
const regPluginId = /^(?:plugin-private:\/\/|__plugin__\/)([0-9a-zA-Z]+)\//;
|
|
870
1631
|
/** decodeQrCode 的方法封装。 */
|
|
871
1632
|
function decodeQrCode(qrCode) {
|
|
872
1633
|
return decodeQrCodeFromBase64(qrCode);
|
|
@@ -881,7 +1642,7 @@ function printQrCode(content) {
|
|
|
881
1642
|
/** isPluginPath 的方法封装。 */
|
|
882
1643
|
function isPluginPath(p) {
|
|
883
1644
|
if (typeof p !== "string") return false;
|
|
884
|
-
return startWith(p, "plugin-private://");
|
|
1645
|
+
return startWith(p, "plugin-private://") || startWith(p, "__plugin__/");
|
|
885
1646
|
}
|
|
886
1647
|
/** extractPluginId 的方法封装。 */
|
|
887
1648
|
function extractPluginId(p) {
|
|
@@ -898,6 +1659,10 @@ const CHANGE_ROUTE_CONTEXT_TIMEOUT = 12e3;
|
|
|
898
1659
|
const CHANGE_ROUTE_CALL_TIMEOUT = 12e3;
|
|
899
1660
|
const CHANGE_ROUTE_READY_TIMEOUT = 15e3;
|
|
900
1661
|
const CHANGE_ROUTE_POLL_DELAY = 500;
|
|
1662
|
+
const CHANGE_ROUTE_POLL_PROTOCOL_TIMEOUT = 2500;
|
|
1663
|
+
const CHANGE_ROUTE_APP_FUNCTION_TIMEOUT = 15e3;
|
|
1664
|
+
const CHANGE_ROUTE_APP_FUNCTION_RETRIES = 2;
|
|
1665
|
+
const CHANGE_ROUTE_APP_FUNCTION_RETRY_DELAY = 800;
|
|
901
1666
|
const APP_READY_TIMEOUT = 2e4;
|
|
902
1667
|
const APP_READY_PROBE_TIMEOUT = 3e3;
|
|
903
1668
|
const APP_READY_POLL_DELAY = 500;
|
|
@@ -935,6 +1700,17 @@ function isCurrentPageProtocolTimeout(error) {
|
|
|
935
1700
|
function isPageStackProtocolTimeout(error) {
|
|
936
1701
|
return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === "App.getPageStack";
|
|
937
1702
|
}
|
|
1703
|
+
function isCallFunctionProtocolTimeout(error) {
|
|
1704
|
+
return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === "App.callFunction";
|
|
1705
|
+
}
|
|
1706
|
+
function isPageMetaMissingError(error) {
|
|
1707
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1708
|
+
return message.includes("getPageMetaByWebviewId") && message.includes("rawPath") && message.includes("is null");
|
|
1709
|
+
}
|
|
1710
|
+
function isCurrentFrameTimedOutError(error) {
|
|
1711
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1712
|
+
return message.includes("unexpected current frame status timedout") || message.includes("[loader] unexpected current frame status timedout");
|
|
1713
|
+
}
|
|
938
1714
|
function isCallWxMethodProtocolTimeout(error) {
|
|
939
1715
|
return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === "App.callWxMethod";
|
|
940
1716
|
}
|
|
@@ -944,11 +1720,44 @@ function isCaptureScreenshotRecoverableError(error) {
|
|
|
944
1720
|
return error.message.includes("fail to capture screenshot") || error.message.includes("App.captureScreenshot");
|
|
945
1721
|
}
|
|
946
1722
|
function isRouteContextProbeError(error) {
|
|
947
|
-
return isCurrentPageProtocolTimeout(error) || isPageStackProtocolTimeout(error);
|
|
1723
|
+
return isCurrentPageProtocolTimeout(error) || isPageStackProtocolTimeout(error) || isPageMetaMissingError(error) || isCurrentFrameTimedOutError(error);
|
|
1724
|
+
}
|
|
1725
|
+
function isRoutePollingRecoverableError(error) {
|
|
1726
|
+
return isRouteContextProbeError(error) || isCallFunctionProtocolTimeout(error) || isPageStackProtocolTimeout(error) || isPageMetaMissingError(error);
|
|
1727
|
+
}
|
|
1728
|
+
function resolveAppFunctionTimeout(timeout) {
|
|
1729
|
+
return Math.max(timeout ?? CHANGE_ROUTE_APP_FUNCTION_TIMEOUT, CHANGE_ROUTE_APP_FUNCTION_TIMEOUT);
|
|
948
1730
|
}
|
|
949
1731
|
function normalizeRoutePath(value) {
|
|
950
1732
|
return String(value ?? "").split("?", 1)[0].replace(/^\/+/, "").replace(/\/+$/, "");
|
|
951
1733
|
}
|
|
1734
|
+
function isPluginNavigationUrl(value) {
|
|
1735
|
+
return String(value ?? "").startsWith("plugin://");
|
|
1736
|
+
}
|
|
1737
|
+
function matchesRouteChange(options) {
|
|
1738
|
+
const normalizedCurrentPath = normalizeRoutePath(options.currentPath);
|
|
1739
|
+
if (!options.expectedRoute || normalizedCurrentPath === options.expectedRoute) return true;
|
|
1740
|
+
if (!isPluginNavigationUrl(options.requestedUrl) || !isPluginPath(options.currentPath)) return false;
|
|
1741
|
+
return normalizedCurrentPath !== normalizeRoutePath(options.previousPath);
|
|
1742
|
+
}
|
|
1743
|
+
function parseRouteQuery(value) {
|
|
1744
|
+
const queryText = String(value ?? "").split("?", 2)[1] ?? "";
|
|
1745
|
+
const query = {};
|
|
1746
|
+
if (!queryText) return query;
|
|
1747
|
+
for (const part of queryText.split("&")) {
|
|
1748
|
+
if (!part) continue;
|
|
1749
|
+
const [rawKey, rawValue = ""] = part.split("=", 2);
|
|
1750
|
+
if (!rawKey) continue;
|
|
1751
|
+
query[decodeURIComponent(rawKey)] = decodeURIComponent(rawValue);
|
|
1752
|
+
}
|
|
1753
|
+
return query;
|
|
1754
|
+
}
|
|
1755
|
+
function resolvePagePayloadId(page, fallbackId) {
|
|
1756
|
+
return page.pageId ?? page.__wxWebviewId__ ?? page.__webviewId__ ?? fallbackId;
|
|
1757
|
+
}
|
|
1758
|
+
function resolvePagePayloadPath(page) {
|
|
1759
|
+
return page.path ?? page.route ?? page.__route__ ?? "";
|
|
1760
|
+
}
|
|
952
1761
|
function logChangeRouteDebug(message) {
|
|
953
1762
|
if (!CHANGE_ROUTE_DEBUG_ENABLED) return;
|
|
954
1763
|
process.stdout.write(`[automator:changeRoute] ${message}\n`);
|
|
@@ -997,30 +1806,27 @@ var MiniProgram = class extends EventEmitter {
|
|
|
997
1806
|
const retries = options.retries ?? CURRENT_PAGE_RETRIES;
|
|
998
1807
|
const sendOptions = options.timeout ? { timeout: options.timeout } : void 0;
|
|
999
1808
|
for (let attempt = 1; attempt <= retries; attempt += 1) try {
|
|
1000
|
-
const
|
|
1001
|
-
return
|
|
1002
|
-
id: pageId,
|
|
1003
|
-
path,
|
|
1004
|
-
query
|
|
1005
|
-
}, this.pageMap);
|
|
1809
|
+
const page = await this.send("App.getCurrentPage", {}, sendOptions);
|
|
1810
|
+
return this.createPageFromPayload(page);
|
|
1006
1811
|
} catch (error) {
|
|
1007
1812
|
lastError = error;
|
|
1008
|
-
if (!isCurrentPageProtocolTimeout(error)) throw error;
|
|
1813
|
+
if (!isCurrentPageProtocolTimeout(error) && !isPageMetaMissingError(error) && !isCurrentFrameTimedOutError(error)) throw error;
|
|
1009
1814
|
if (attempt < retries) {
|
|
1010
1815
|
await sleep(CURRENT_PAGE_RETRY_DELAY);
|
|
1011
1816
|
continue;
|
|
1012
1817
|
}
|
|
1013
1818
|
}
|
|
1014
|
-
if (isCurrentPageProtocolTimeout(lastError)) try {
|
|
1819
|
+
if (isCurrentPageProtocolTimeout(lastError) || isPageMetaMissingError(lastError) || isCurrentFrameTimedOutError(lastError)) try {
|
|
1015
1820
|
const { pageStack } = await this.send("App.getPageStack", {}, sendOptions);
|
|
1016
1821
|
const page = pageStack[pageStack.length - 1];
|
|
1017
|
-
if (page) return
|
|
1018
|
-
id: page.pageId,
|
|
1019
|
-
path: page.path,
|
|
1020
|
-
query: page.query
|
|
1021
|
-
}, this.pageMap);
|
|
1822
|
+
if (page) return this.createPageFromPayload(page, pageStack.length);
|
|
1022
1823
|
} catch (error) {
|
|
1023
|
-
if (!isPageStackProtocolTimeout(error)) throw error;
|
|
1824
|
+
if (!isPageStackProtocolTimeout(error) && !isPageMetaMissingError(error) && !isCurrentFrameTimedOutError(error)) throw error;
|
|
1825
|
+
}
|
|
1826
|
+
if ((options.appFunctionFallback ?? true) && (isCurrentPageProtocolTimeout(lastError) || isPageMetaMissingError(lastError) || isCurrentFrameTimedOutError(lastError))) {
|
|
1827
|
+
const pageStack = await this.readAppFunctionPageStack(resolveAppFunctionTimeout(sendOptions?.timeout));
|
|
1828
|
+
const page = pageStack[pageStack.length - 1];
|
|
1829
|
+
if (page) return page;
|
|
1024
1830
|
}
|
|
1025
1831
|
throw lastError;
|
|
1026
1832
|
}
|
|
@@ -1033,6 +1839,13 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1033
1839
|
args
|
|
1034
1840
|
})).result;
|
|
1035
1841
|
}
|
|
1842
|
+
async callWxMethodWithOptions(method, options = {}, ...args) {
|
|
1843
|
+
const sendOptions = options.timeout ? { timeout: options.timeout } : void 0;
|
|
1844
|
+
return (await this.send("App.callWxMethod", {
|
|
1845
|
+
method,
|
|
1846
|
+
args
|
|
1847
|
+
}, sendOptions)).result;
|
|
1848
|
+
}
|
|
1036
1849
|
async callWxMethodWithTimeout(method, timeout, ...args) {
|
|
1037
1850
|
return (await this.send("App.callWxMethod", {
|
|
1038
1851
|
method,
|
|
@@ -1086,10 +1899,14 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1086
1899
|
});
|
|
1087
1900
|
}
|
|
1088
1901
|
async evaluate(appFunction, ...args) {
|
|
1902
|
+
return await this.evaluateWithOptions(appFunction, {}, ...args);
|
|
1903
|
+
}
|
|
1904
|
+
async evaluateWithOptions(appFunction, options = {}, ...args) {
|
|
1905
|
+
const sendOptions = options.timeout ? { timeout: options.timeout } : void 0;
|
|
1089
1906
|
const { result } = await this.send("App.callFunction", {
|
|
1090
1907
|
functionDeclaration: appFunction.toString(),
|
|
1091
1908
|
args
|
|
1092
|
-
});
|
|
1909
|
+
}, sendOptions);
|
|
1093
1910
|
return result;
|
|
1094
1911
|
}
|
|
1095
1912
|
async pageScrollTo(scrollTop) {
|
|
@@ -1137,7 +1954,9 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1137
1954
|
await this.send("App.addBinding", { name });
|
|
1138
1955
|
}
|
|
1139
1956
|
async checkVersion() {
|
|
1140
|
-
const
|
|
1957
|
+
const toolInfo = await this.send("Tool.getInfo");
|
|
1958
|
+
this.connection.configureToolInfo(toolInfo);
|
|
1959
|
+
const sdkVersion = toolInfo.SDKVersion;
|
|
1141
1960
|
if (sdkVersion !== "dev" && cmpVersion(sdkVersion, "2.7.3") < 0) throw new Error(`SDKVersion is currently ${sdkVersion}, while automator(${version}) requires at least version 2.7.3`);
|
|
1142
1961
|
}
|
|
1143
1962
|
/**
|
|
@@ -1219,14 +2038,19 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1219
2038
|
async changeRoute(method, url) {
|
|
1220
2039
|
const currentPage = await this.resolveRouteContextPage();
|
|
1221
2040
|
logChangeRouteDebug(`start method=${method} url=${url ?? "<none>"} current=${currentPage?.path ?? "<none>"}`);
|
|
2041
|
+
let routeCommandSent = false;
|
|
1222
2042
|
try {
|
|
1223
2043
|
if (currentPage && isPluginPath(currentPage.path)) await this.callPluginWxMethod(extractPluginId(currentPage.path), method, { url });
|
|
1224
2044
|
else await this.callWxMethodWithTimeout(method, CHANGE_ROUTE_CALL_TIMEOUT, { url });
|
|
2045
|
+
routeCommandSent = true;
|
|
1225
2046
|
} catch (error) {
|
|
1226
|
-
if (isCallWxMethodProtocolTimeout(error) || isOperationTimeoutError(error, CHANGE_ROUTE_CALL_TIMEOUT)
|
|
1227
|
-
|
|
2047
|
+
if (isCallWxMethodProtocolTimeout(error) || isOperationTimeoutError(error, CHANGE_ROUTE_CALL_TIMEOUT) || isPageMetaMissingError(error)) {
|
|
2048
|
+
routeCommandSent = true;
|
|
2049
|
+
logChangeRouteDebug(`call-timeout method=${method} url=${url ?? "<none>"}`);
|
|
2050
|
+
} else throw error;
|
|
1228
2051
|
}
|
|
1229
2052
|
const expectedRoute = normalizeRoutePath(url);
|
|
2053
|
+
const expectedRouteQuery = parseRouteQuery(url);
|
|
1230
2054
|
const startedAt = Date.now();
|
|
1231
2055
|
let lastPage;
|
|
1232
2056
|
let lastError;
|
|
@@ -1235,7 +2059,12 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1235
2059
|
const page = await this.readRoutePollingCurrentPage();
|
|
1236
2060
|
lastPage = page;
|
|
1237
2061
|
logChangeRouteDebug(`poll method=${method} url=${url ?? "<none>"} current=${page?.path ?? "<none>"}`);
|
|
1238
|
-
if (
|
|
2062
|
+
if (matchesRouteChange({
|
|
2063
|
+
currentPath: page?.path,
|
|
2064
|
+
previousPath: currentPage?.path,
|
|
2065
|
+
requestedUrl: url,
|
|
2066
|
+
expectedRoute
|
|
2067
|
+
})) {
|
|
1239
2068
|
logChangeRouteDebug(`ready method=${method} url=${url ?? "<none>"} current=${page?.path ?? "<none>"}`);
|
|
1240
2069
|
return page;
|
|
1241
2070
|
}
|
|
@@ -1249,7 +2078,12 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1249
2078
|
if (stackTop) {
|
|
1250
2079
|
lastPage = stackTop;
|
|
1251
2080
|
logChangeRouteDebug(`stack method=${method} url=${url ?? "<none>"} current=${stackTop.path}`);
|
|
1252
|
-
if (
|
|
2081
|
+
if (matchesRouteChange({
|
|
2082
|
+
currentPath: stackTop.path,
|
|
2083
|
+
previousPath: currentPage?.path,
|
|
2084
|
+
requestedUrl: url,
|
|
2085
|
+
expectedRoute
|
|
2086
|
+
})) {
|
|
1253
2087
|
logChangeRouteDebug(`stack-ready method=${method} url=${url ?? "<none>"} current=${stackTop.path}`);
|
|
1254
2088
|
return stackTop;
|
|
1255
2089
|
}
|
|
@@ -1257,7 +2091,7 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1257
2091
|
} catch (error) {
|
|
1258
2092
|
lastError = error;
|
|
1259
2093
|
logChangeRouteDebug(`stack-error method=${method} url=${url ?? "<none>"} error=${error instanceof Error ? error.message : String(error)}`);
|
|
1260
|
-
if (isOperationTimeoutError(error, CHANGE_ROUTE_CONTEXT_TIMEOUT)) {
|
|
2094
|
+
if (isOperationTimeoutError(error, CHANGE_ROUTE_CONTEXT_TIMEOUT) || isRoutePollingRecoverableError(error)) {
|
|
1261
2095
|
await sleep(CHANGE_ROUTE_POLL_DELAY);
|
|
1262
2096
|
continue;
|
|
1263
2097
|
}
|
|
@@ -1269,11 +2103,23 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1269
2103
|
throw new Error(`Timed out waiting route ${expectedRoute || "<current>"} after ${method}; current page: ${lastPage.path}`);
|
|
1270
2104
|
}
|
|
1271
2105
|
logChangeRouteDebug(`timeout method=${method} url=${url ?? "<none>"} current=<none> error=${lastError instanceof Error ? lastError.message : String(lastError)}`);
|
|
2106
|
+
if (isRoutePollingRecoverableError(lastError)) {
|
|
2107
|
+
if (routeCommandSent && expectedRoute) return this.createPageFromPayload({
|
|
2108
|
+
pageId: 1,
|
|
2109
|
+
path: `/${expectedRoute}`,
|
|
2110
|
+
query: expectedRouteQuery
|
|
2111
|
+
});
|
|
2112
|
+
throw new Error(`Timed out waiting route ${expectedRoute || "<current>"} after ${method}; last recoverable error: ${lastError instanceof Error ? lastError.message : String(lastError)}`);
|
|
2113
|
+
}
|
|
1272
2114
|
throw lastError instanceof Error ? lastError : /* @__PURE__ */ new Error(`Timed out waiting route ${expectedRoute || "<current>"} after ${method}`);
|
|
1273
2115
|
}
|
|
1274
2116
|
async resolveRouteContextPage() {
|
|
1275
|
-
const currentPageTask = this.currentPage(
|
|
1276
|
-
|
|
2117
|
+
const currentPageTask = this.currentPage({
|
|
2118
|
+
appFunctionFallback: false,
|
|
2119
|
+
retries: 1,
|
|
2120
|
+
timeout: CHANGE_ROUTE_POLL_PROTOCOL_TIMEOUT
|
|
2121
|
+
}).catch((error) => {
|
|
2122
|
+
if (isRoutePollingRecoverableError(error)) return;
|
|
1277
2123
|
throw error;
|
|
1278
2124
|
});
|
|
1279
2125
|
const timeoutTask = sleep(CHANGE_ROUTE_CONTEXT_TIMEOUT).then(() => void 0);
|
|
@@ -1284,22 +2130,51 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1284
2130
|
}
|
|
1285
2131
|
}
|
|
1286
2132
|
async readRoutePollingCurrentPage() {
|
|
1287
|
-
const
|
|
2133
|
+
const page = await this.send("App.getCurrentPage", {}, { timeout: CHANGE_ROUTE_POLL_PROTOCOL_TIMEOUT });
|
|
2134
|
+
return this.createPageFromPayload(page);
|
|
2135
|
+
}
|
|
2136
|
+
async readRoutePollingPageStack() {
|
|
2137
|
+
try {
|
|
2138
|
+
const { pageStack } = await this.send("App.getPageStack", {}, { timeout: CHANGE_ROUTE_POLL_PROTOCOL_TIMEOUT });
|
|
2139
|
+
return this.createPagesFromPayloads(pageStack);
|
|
2140
|
+
} catch (error) {
|
|
2141
|
+
if (!isPageStackProtocolTimeout(error) && !isPageMetaMissingError(error)) throw error;
|
|
2142
|
+
throw error;
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
createPageFromPayload(page, fallbackId = 1) {
|
|
1288
2146
|
return Page.create(this.connection, {
|
|
1289
|
-
id:
|
|
1290
|
-
path,
|
|
1291
|
-
query
|
|
2147
|
+
id: resolvePagePayloadId(page, fallbackId),
|
|
2148
|
+
path: resolvePagePayloadPath(page),
|
|
2149
|
+
query: page.query ?? page.options ?? {}
|
|
1292
2150
|
}, this.pageMap);
|
|
1293
2151
|
}
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
2152
|
+
createPagesFromPayloads(pageStack) {
|
|
2153
|
+
return pageStack.map((page, index) => this.createPageFromPayload(page, index + 1));
|
|
2154
|
+
}
|
|
2155
|
+
async readAppFunctionPageStack(timeout = CHANGE_ROUTE_APP_FUNCTION_TIMEOUT, retries = CHANGE_ROUTE_APP_FUNCTION_RETRIES) {
|
|
2156
|
+
let lastError;
|
|
2157
|
+
for (let attempt = 1; attempt <= retries; attempt += 1) try {
|
|
2158
|
+
const { result } = await this.send("App.callFunction", {
|
|
2159
|
+
functionDeclaration: `function () {
|
|
2160
|
+
var pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
2161
|
+
return pages.map(function (page, index) {
|
|
2162
|
+
return {
|
|
2163
|
+
pageId: page.pageId || page.__wxWebviewId__ || page.__webviewId__ || index + 1,
|
|
2164
|
+
path: page.path || page.route || page.__route__ || '',
|
|
2165
|
+
query: page.query || page.options || {}
|
|
2166
|
+
};
|
|
2167
|
+
});
|
|
2168
|
+
}`,
|
|
2169
|
+
args: []
|
|
2170
|
+
}, { timeout });
|
|
2171
|
+
return this.createPagesFromPayloads(Array.isArray(result) ? result : []);
|
|
2172
|
+
} catch (error) {
|
|
2173
|
+
lastError = error;
|
|
2174
|
+
if (!isCallFunctionProtocolTimeout(error) || attempt >= retries) throw error;
|
|
2175
|
+
await sleep(CHANGE_ROUTE_APP_FUNCTION_RETRY_DELAY);
|
|
2176
|
+
}
|
|
2177
|
+
throw lastError;
|
|
1303
2178
|
}
|
|
1304
2179
|
async send(method, params = {}, options) {
|
|
1305
2180
|
return options ? await this.connection.send(method, params, options) : await this.connection.send(method, params);
|
|
@@ -1697,7 +2572,8 @@ async function launch(options = {}) {
|
|
|
1697
2572
|
}
|
|
1698
2573
|
async function connect(options) {
|
|
1699
2574
|
if (typeof options.wsEndpoint !== "string") throw new TypeError("wsEndpoint is required for smartapp runtime connection.");
|
|
1700
|
-
|
|
2575
|
+
const miniProgram = await connectMiniProgram(options.wsEndpoint);
|
|
2576
|
+
return new SmartappDevice("devtools", DEFAULT_CONNECT_TYPE, "devtools-usb", { miniProgram });
|
|
1701
2577
|
}
|
|
1702
2578
|
async function devices(deviceType, _connectType = DEFAULT_CONNECT_TYPE) {
|
|
1703
2579
|
const resolvedDeviceType = resolveDeviceType(deviceType);
|