@weapp-vite/miniprogram-automator 1.2.4 → 1.2.6
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 +80 -15
- package/dist/index.mjs +966 -79
- package/dist/{launch-2X75zDRY.mjs → launch-mRKloPOa.mjs} +26 -26
- 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", {
|
|
@@ -503,6 +505,7 @@ var Transport = class extends EventEmitter {
|
|
|
503
505
|
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;
|
|
508
|
+
const CONNECT_TIMEOUT = 3e4;
|
|
506
509
|
/** Connection 的实现。 */
|
|
507
510
|
var Connection = class Connection extends EventEmitter {
|
|
508
511
|
transport;
|
|
@@ -571,20 +574,35 @@ var Connection = class Connection extends EventEmitter {
|
|
|
571
574
|
}
|
|
572
575
|
this.callbacks.clear();
|
|
573
576
|
};
|
|
574
|
-
static create(url) {
|
|
577
|
+
static create(url, timeout = CONNECT_TIMEOUT) {
|
|
575
578
|
return new Promise((resolve, reject) => {
|
|
576
579
|
const ws = new WebSocket(url);
|
|
580
|
+
let settled = false;
|
|
581
|
+
const timer = setTimeout(() => {
|
|
582
|
+
if (settled) return;
|
|
583
|
+
settled = true;
|
|
584
|
+
ws.close();
|
|
585
|
+
reject(/* @__PURE__ */ new Error(`Timed out connecting to DevTools websocket ${url} after ${timeout}ms`));
|
|
586
|
+
}, timeout);
|
|
577
587
|
ws.on("open", () => {
|
|
588
|
+
if (settled) return;
|
|
589
|
+
settled = true;
|
|
590
|
+
clearTimeout(timer);
|
|
578
591
|
resolve(new Connection(new Transport(ws)));
|
|
579
592
|
});
|
|
580
|
-
ws.on("error",
|
|
593
|
+
ws.on("error", (error) => {
|
|
594
|
+
if (settled) return;
|
|
595
|
+
settled = true;
|
|
596
|
+
clearTimeout(timer);
|
|
597
|
+
reject(error);
|
|
598
|
+
});
|
|
581
599
|
});
|
|
582
600
|
}
|
|
583
601
|
};
|
|
584
602
|
//#endregion
|
|
585
603
|
//#region src/headless.ts
|
|
586
604
|
async function launchHeadlessAutomator(options) {
|
|
587
|
-
return await (await import("./launch-
|
|
605
|
+
return await (await import("./launch-mRKloPOa.mjs")).launch({ projectPath: options.projectPath });
|
|
588
606
|
}
|
|
589
607
|
//#endregion
|
|
590
608
|
//#region src/launcher/portLease.ts
|
|
@@ -683,7 +701,7 @@ async function acquireAutomatorPortLease(preferredPort) {
|
|
|
683
701
|
}
|
|
684
702
|
//#endregion
|
|
685
703
|
//#region package.json
|
|
686
|
-
var version = "1.2.
|
|
704
|
+
var version = "1.2.6";
|
|
687
705
|
//#endregion
|
|
688
706
|
//#region src/Native.ts
|
|
689
707
|
/** Native 的实现。 */
|
|
@@ -734,7 +752,70 @@ var Native = class extends EventEmitter {
|
|
|
734
752
|
}
|
|
735
753
|
};
|
|
736
754
|
//#endregion
|
|
755
|
+
//#region src/pageRouteFallback.ts
|
|
756
|
+
function normalizeFallbackIdPart(value) {
|
|
757
|
+
return encodeURIComponent(value).replace(/%/g, "_");
|
|
758
|
+
}
|
|
759
|
+
function resolveFallbackTagName(selector) {
|
|
760
|
+
const tagSelector = selector.trim();
|
|
761
|
+
if (/^[a-z][\w-]*$/i.test(tagSelector)) return tagSelector.toLowerCase();
|
|
762
|
+
return "view";
|
|
763
|
+
}
|
|
764
|
+
/** 将 App-Service 查询到的渲染节点包装为 Element 兼容对象。 */
|
|
765
|
+
function createRouteFallbackElement(connection, elementMap, pageId, selector, node, index) {
|
|
766
|
+
const nodeId = typeof node.id === "string" && node.id ? normalizeFallbackIdPart(node.id) : String(index);
|
|
767
|
+
const elementId = `__weapp_vite_route_fallback_${pageId}_${normalizeFallbackIdPart(selector)}_${nodeId}_${index}`;
|
|
768
|
+
return Element.create(connection, {
|
|
769
|
+
elementId,
|
|
770
|
+
pageId,
|
|
771
|
+
tagName: resolveFallbackTagName(selector)
|
|
772
|
+
}, elementMap);
|
|
773
|
+
}
|
|
774
|
+
//#endregion
|
|
737
775
|
//#region src/Page.ts
|
|
776
|
+
const PAGE_QUERY_TIMEOUT = 2500;
|
|
777
|
+
const PAGE_DATA_TIMEOUT = 12e3;
|
|
778
|
+
const PAGE_DATA_PROTOCOL_TIMEOUT = 2500;
|
|
779
|
+
const PAGE_SET_DATA_TIMEOUT = 12e3;
|
|
780
|
+
const PAGE_SET_DATA_PROTOCOL_TIMEOUT = 2500;
|
|
781
|
+
const PAGE_CALL_METHOD_TIMEOUT = 12e3;
|
|
782
|
+
const PAGE_CALL_METHOD_PROTOCOL_TIMEOUT = 2500;
|
|
783
|
+
const PAGE_CALL_METHOD_FALLBACK_RETRIES = 3;
|
|
784
|
+
const PAGE_CALL_METHOD_FALLBACK_RETRY_DELAY = 300;
|
|
785
|
+
const PAGE_RENDERED_TIMEOUT = 15e3;
|
|
786
|
+
const PAGE_RENDERED_POLL_DELAY = 220;
|
|
787
|
+
const PAGE_RENDERED_QUERY_TIMEOUT = 5e3;
|
|
788
|
+
const PAGE_ROOT_SELECTORS = [
|
|
789
|
+
"page",
|
|
790
|
+
"body",
|
|
791
|
+
"weapp-app-shell",
|
|
792
|
+
"view"
|
|
793
|
+
];
|
|
794
|
+
function isProtocolTimeoutError(error, method) {
|
|
795
|
+
return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === method;
|
|
796
|
+
}
|
|
797
|
+
function isPageStackStaleError(error) {
|
|
798
|
+
return (error instanceof Error ? error.message : String(error)).includes("page is not on top of page stack");
|
|
799
|
+
}
|
|
800
|
+
function isPageMetaMissingError$1(error) {
|
|
801
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
802
|
+
return message.includes("getPageMetaByWebviewId") && message.includes("rawPath") && message.includes("is null");
|
|
803
|
+
}
|
|
804
|
+
function isCurrentFrameTimedOutError$1(error) {
|
|
805
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
806
|
+
return message.includes("unexpected current frame status timedout") || message.includes("[loader] unexpected current frame status timedout");
|
|
807
|
+
}
|
|
808
|
+
function isRecoverablePageProtocolError(error, method) {
|
|
809
|
+
return isProtocolTimeoutError(error, method) || isPageMetaMissingError$1(error) || isCurrentFrameTimedOutError$1(error);
|
|
810
|
+
}
|
|
811
|
+
function normalizeRoute(value) {
|
|
812
|
+
return String(value || "").replace(/^\/+/, "").replace(/\/+$/g, "");
|
|
813
|
+
}
|
|
814
|
+
function matchesDataset(node, expected) {
|
|
815
|
+
if (!expected) return true;
|
|
816
|
+
const dataset = node.dataset ?? {};
|
|
817
|
+
return Object.entries(expected).every(([key, value]) => String(dataset[key] ?? "") === String(value));
|
|
818
|
+
}
|
|
738
819
|
/** Page 的实现。 */
|
|
739
820
|
var Page = class Page {
|
|
740
821
|
connection;
|
|
@@ -742,12 +823,17 @@ var Page = class Page {
|
|
|
742
823
|
query = {};
|
|
743
824
|
id;
|
|
744
825
|
elementMap = /* @__PURE__ */ new Map();
|
|
826
|
+
preferRoutePageFallback = false;
|
|
745
827
|
constructor(connection, options) {
|
|
746
828
|
this.connection = connection;
|
|
747
829
|
this.id = options.id;
|
|
748
830
|
this.path = options.path;
|
|
749
831
|
this.query = options.query;
|
|
750
832
|
}
|
|
833
|
+
updateFromOptions(options) {
|
|
834
|
+
this.path = options.path;
|
|
835
|
+
this.query = options.query;
|
|
836
|
+
}
|
|
751
837
|
async waitFor(condition) {
|
|
752
838
|
if (isNum(condition)) {
|
|
753
839
|
await sleep$1(condition);
|
|
@@ -759,29 +845,41 @@ var Page = class Page {
|
|
|
759
845
|
}
|
|
760
846
|
if (isStr(condition)) await waitUntil(async () => (await this.$$(condition)).length > 0);
|
|
761
847
|
}
|
|
762
|
-
async $(selector) {
|
|
848
|
+
async $(selector, options = {}) {
|
|
849
|
+
if (options.routeOnly || this.preferRoutePageFallback) return await this.queryRouteElement(selector, options);
|
|
763
850
|
try {
|
|
764
|
-
const element = await this.send("Page.getElement", { selector });
|
|
851
|
+
const element = await this.send("Page.getElement", { selector }, { timeout: options.timeout ?? PAGE_QUERY_TIMEOUT });
|
|
765
852
|
return Element.create(this.connection, {
|
|
766
853
|
...element,
|
|
767
854
|
pageId: this.id
|
|
768
855
|
}, this.elementMap);
|
|
769
|
-
} catch {
|
|
856
|
+
} catch (error) {
|
|
857
|
+
if (options.fallback !== false && isRecoverablePageProtocolError(error, "Page.getElement")) {
|
|
858
|
+
this.preferRoutePageFallback = true;
|
|
859
|
+
return await this.queryRouteElement(selector, options);
|
|
860
|
+
}
|
|
770
861
|
return null;
|
|
771
862
|
}
|
|
772
863
|
}
|
|
773
|
-
async $$(selector) {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
864
|
+
async $$(selector, options = {}) {
|
|
865
|
+
if (options.routeOnly || this.preferRoutePageFallback) return await this.queryRouteElements(selector, options);
|
|
866
|
+
try {
|
|
867
|
+
const { elements } = await this.send("Page.getElements", { selector }, { timeout: options.timeout ?? PAGE_QUERY_TIMEOUT });
|
|
868
|
+
return elements.map((element) => {
|
|
869
|
+
return Element.create(this.connection, {
|
|
870
|
+
...element,
|
|
871
|
+
pageId: this.id
|
|
872
|
+
}, this.elementMap);
|
|
873
|
+
});
|
|
874
|
+
} catch (error) {
|
|
875
|
+
if (options.fallback === false || !isRecoverablePageProtocolError(error, "Page.getElements")) throw error;
|
|
876
|
+
this.preferRoutePageFallback = true;
|
|
877
|
+
return await this.queryRouteElements(selector, options);
|
|
878
|
+
}
|
|
781
879
|
}
|
|
782
|
-
async getElementByXpath(selector) {
|
|
880
|
+
async getElementByXpath(selector, options = {}) {
|
|
783
881
|
try {
|
|
784
|
-
const element = await this.send("Page.getElementByXpath", { selector });
|
|
882
|
+
const element = await this.send("Page.getElementByXpath", { selector }, { timeout: options.timeout ?? PAGE_QUERY_TIMEOUT });
|
|
785
883
|
return Element.create(this.connection, {
|
|
786
884
|
...element,
|
|
787
885
|
pageId: this.id
|
|
@@ -790,8 +888,8 @@ var Page = class Page {
|
|
|
790
888
|
return null;
|
|
791
889
|
}
|
|
792
890
|
}
|
|
793
|
-
async getElementsByXpath(selector) {
|
|
794
|
-
const { elements } = await this.send("Page.getElementsByXpath", { selector });
|
|
891
|
+
async getElementsByXpath(selector, options = {}) {
|
|
892
|
+
const { elements } = await this.send("Page.getElementsByXpath", { selector }, { timeout: options.timeout ?? PAGE_QUERY_TIMEOUT });
|
|
795
893
|
return elements.map((element) => {
|
|
796
894
|
return Element.create(this.connection, {
|
|
797
895
|
...element,
|
|
@@ -802,13 +900,542 @@ var Page = class Page {
|
|
|
802
900
|
async xpath(selector) {
|
|
803
901
|
return await this.getElementByXpath(selector);
|
|
804
902
|
}
|
|
805
|
-
async
|
|
903
|
+
async wxml() {
|
|
904
|
+
let lastError;
|
|
905
|
+
for (const selector of PAGE_ROOT_SELECTORS) try {
|
|
906
|
+
const element = await this.$(selector, { timeout: PAGE_QUERY_TIMEOUT });
|
|
907
|
+
if (!element) continue;
|
|
908
|
+
return await element.wxml();
|
|
909
|
+
} catch (error) {
|
|
910
|
+
lastError = error;
|
|
911
|
+
}
|
|
912
|
+
throw lastError instanceof Error ? lastError : /* @__PURE__ */ new Error("Failed to find page element");
|
|
913
|
+
}
|
|
914
|
+
async renderedNodes(selector, options = {}) {
|
|
915
|
+
const { result } = await this.connection.send("App.callFunction", {
|
|
916
|
+
functionDeclaration: `function (route, query, selector, scopeSelectors) {
|
|
917
|
+
function normalizeRoute(value) {
|
|
918
|
+
return String(value || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
919
|
+
}
|
|
920
|
+
function matchesQuery(page, expectedQuery) {
|
|
921
|
+
if (!expectedQuery || !Object.keys(expectedQuery).length) {
|
|
922
|
+
return true;
|
|
923
|
+
}
|
|
924
|
+
var actualQuery = page && (page.options || page.query || {});
|
|
925
|
+
return Object.keys(expectedQuery).every(function (key) {
|
|
926
|
+
var actualValue = String(actualQuery[key] == null ? '' : actualQuery[key]);
|
|
927
|
+
var expectedValue = String(expectedQuery[key]);
|
|
928
|
+
var decodedActualValue = actualValue;
|
|
929
|
+
try {
|
|
930
|
+
decodedActualValue = decodeURIComponent(actualValue);
|
|
931
|
+
}
|
|
932
|
+
catch (_) {
|
|
933
|
+
}
|
|
934
|
+
return actualValue === expectedValue
|
|
935
|
+
|| decodedActualValue === expectedValue
|
|
936
|
+
|| actualValue === encodeURIComponent(expectedValue);
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
var pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
940
|
+
var expectedRoute = normalizeRoute(route);
|
|
941
|
+
var page = null;
|
|
942
|
+
for (var index = pages.length - 1; index >= 0; index -= 1) {
|
|
943
|
+
var candidate = pages[index];
|
|
944
|
+
var candidateRoute = normalizeRoute(candidate && (candidate.path || candidate.route || candidate.__route__));
|
|
945
|
+
if ((!expectedRoute || candidateRoute === expectedRoute) && matchesQuery(candidate, query)) {
|
|
946
|
+
page = candidate;
|
|
947
|
+
break;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
if (!page) {
|
|
951
|
+
return [];
|
|
952
|
+
}
|
|
953
|
+
function createSelectorQuery(scope) {
|
|
954
|
+
var query = null;
|
|
955
|
+
var createdFromScope = false;
|
|
956
|
+
if (scope && typeof scope.createSelectorQuery === 'function') {
|
|
957
|
+
query = scope.createSelectorQuery();
|
|
958
|
+
createdFromScope = true;
|
|
959
|
+
}
|
|
960
|
+
else if (typeof wx !== 'undefined' && wx && typeof wx.createSelectorQuery === 'function') {
|
|
961
|
+
query = wx.createSelectorQuery();
|
|
962
|
+
}
|
|
963
|
+
else if (typeof page.createSelectorQuery === 'function') {
|
|
964
|
+
query = page.createSelectorQuery();
|
|
965
|
+
}
|
|
966
|
+
if (!query) {
|
|
967
|
+
return null;
|
|
968
|
+
}
|
|
969
|
+
if (!createdFromScope && typeof query.in === 'function') {
|
|
970
|
+
try {
|
|
971
|
+
query = query.in(scope || page);
|
|
972
|
+
}
|
|
973
|
+
catch (_) {
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
return query;
|
|
977
|
+
}
|
|
978
|
+
function pushUnique(list, seen, item) {
|
|
979
|
+
if (!item) {
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
var id = item.is || item.id || item.__wxWebviewId__ || item.__wxExparserNodeId__ || String(list.length);
|
|
983
|
+
if (seen[id]) {
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
seen[id] = true;
|
|
987
|
+
list.push(item);
|
|
988
|
+
}
|
|
989
|
+
function collectScopes(root) {
|
|
990
|
+
var scopes = [];
|
|
991
|
+
var seen = {};
|
|
992
|
+
var queue = [];
|
|
993
|
+
pushUnique(scopes, seen, root);
|
|
994
|
+
queue.push(root);
|
|
995
|
+
for (var queueIndex = 0; queueIndex < queue.length && queueIndex < 60; queueIndex += 1) {
|
|
996
|
+
var scope = queue[queueIndex];
|
|
997
|
+
if (!scope || typeof scope.selectAllComponents !== 'function') {
|
|
998
|
+
continue;
|
|
999
|
+
}
|
|
1000
|
+
var children = [];
|
|
1001
|
+
var componentSelectors = Array.isArray(scopeSelectors) ? scopeSelectors.slice() : [];
|
|
1002
|
+
componentSelectors.push(selector, '*', 'weapp-app-shell', 'weapp-layout-default');
|
|
1003
|
+
for (var selectorIndex = 0; selectorIndex < componentSelectors.length; selectorIndex += 1) {
|
|
1004
|
+
if (!componentSelectors[selectorIndex]) {
|
|
1005
|
+
continue;
|
|
1006
|
+
}
|
|
1007
|
+
try {
|
|
1008
|
+
var selected = scope.selectAllComponents(componentSelectors[selectorIndex]);
|
|
1009
|
+
if (Array.isArray(selected)) {
|
|
1010
|
+
children = children.concat(selected);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
catch (_) {
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
for (var childIndex = 0; childIndex < children.length; childIndex += 1) {
|
|
1017
|
+
var child = children[childIndex];
|
|
1018
|
+
var previousLength = scopes.length;
|
|
1019
|
+
pushUnique(scopes, seen, child);
|
|
1020
|
+
if (scopes.length > previousLength) {
|
|
1021
|
+
queue.push(child);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
return scopes;
|
|
1026
|
+
}
|
|
1027
|
+
function queryScope(scope) {
|
|
1028
|
+
return new Promise(function (resolve) {
|
|
1029
|
+
var settled = false;
|
|
1030
|
+
var timer = setTimeout(function () {
|
|
1031
|
+
if (settled) {
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
settled = true;
|
|
1035
|
+
resolve([]);
|
|
1036
|
+
}, 800);
|
|
1037
|
+
function finish(nodes) {
|
|
1038
|
+
if (settled) {
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
settled = true;
|
|
1042
|
+
clearTimeout(timer);
|
|
1043
|
+
resolve(Array.isArray(nodes) ? nodes : nodes ? [nodes] : []);
|
|
1044
|
+
}
|
|
1045
|
+
try {
|
|
1046
|
+
var query = createSelectorQuery(scope);
|
|
1047
|
+
if (!query) {
|
|
1048
|
+
finish([]);
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
query
|
|
1052
|
+
.selectAll(selector)
|
|
1053
|
+
.fields({
|
|
1054
|
+
dataset: true,
|
|
1055
|
+
id: true,
|
|
1056
|
+
rect: true,
|
|
1057
|
+
size: true
|
|
1058
|
+
}, function (nodes) {
|
|
1059
|
+
finish(nodes);
|
|
1060
|
+
})
|
|
1061
|
+
.exec();
|
|
1062
|
+
}
|
|
1063
|
+
catch (_) {
|
|
1064
|
+
finish([]);
|
|
1065
|
+
}
|
|
1066
|
+
});
|
|
1067
|
+
}
|
|
1068
|
+
return new Promise(function (resolve) {
|
|
1069
|
+
try {
|
|
1070
|
+
var scopes = collectScopes(page);
|
|
1071
|
+
var collected = [];
|
|
1072
|
+
var index = 0;
|
|
1073
|
+
function next() {
|
|
1074
|
+
if (index >= scopes.length) {
|
|
1075
|
+
resolve(collected);
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
var scope = scopes[index];
|
|
1079
|
+
index += 1;
|
|
1080
|
+
queryScope(scope).then(function (nodes) {
|
|
1081
|
+
collected = collected.concat(nodes);
|
|
1082
|
+
next();
|
|
1083
|
+
}, function () {
|
|
1084
|
+
next();
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
next();
|
|
1088
|
+
}
|
|
1089
|
+
catch (_) {
|
|
1090
|
+
resolve([]);
|
|
1091
|
+
}
|
|
1092
|
+
});
|
|
1093
|
+
}`,
|
|
1094
|
+
args: [
|
|
1095
|
+
normalizeRoute(this.path),
|
|
1096
|
+
this.query,
|
|
1097
|
+
selector,
|
|
1098
|
+
options.componentSelectors ?? []
|
|
1099
|
+
]
|
|
1100
|
+
}, { timeout: options.timeout ?? PAGE_RENDERED_QUERY_TIMEOUT });
|
|
1101
|
+
return Array.isArray(result) ? result : [];
|
|
1102
|
+
}
|
|
1103
|
+
async renderedSelectorNodes(selectors, options = {}) {
|
|
1104
|
+
const normalizedSelectors = selectors.map((selector) => String(selector || "").trim()).filter(Boolean);
|
|
1105
|
+
if (normalizedSelectors.length === 0) return {};
|
|
1106
|
+
const { result } = await this.connection.send("App.callFunction", {
|
|
1107
|
+
functionDeclaration: `function (route, query, selectors, scopeSelectors) {
|
|
1108
|
+
function normalizeRoute(value) {
|
|
1109
|
+
return String(value || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
1110
|
+
}
|
|
1111
|
+
function matchesQuery(page, expectedQuery) {
|
|
1112
|
+
if (!expectedQuery || !Object.keys(expectedQuery).length) {
|
|
1113
|
+
return true;
|
|
1114
|
+
}
|
|
1115
|
+
var actualQuery = page && (page.options || page.query || {});
|
|
1116
|
+
return Object.keys(expectedQuery).every(function (key) {
|
|
1117
|
+
var actualValue = String(actualQuery[key] == null ? '' : actualQuery[key]);
|
|
1118
|
+
var expectedValue = String(expectedQuery[key]);
|
|
1119
|
+
var decodedActualValue = actualValue;
|
|
1120
|
+
try {
|
|
1121
|
+
decodedActualValue = decodeURIComponent(actualValue);
|
|
1122
|
+
}
|
|
1123
|
+
catch (_) {
|
|
1124
|
+
}
|
|
1125
|
+
return actualValue === expectedValue
|
|
1126
|
+
|| decodedActualValue === expectedValue
|
|
1127
|
+
|| actualValue === encodeURIComponent(expectedValue);
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
function createSelectorQuery(scope, page) {
|
|
1131
|
+
var query = null;
|
|
1132
|
+
var createdFromScope = false;
|
|
1133
|
+
if (scope && typeof scope.createSelectorQuery === 'function') {
|
|
1134
|
+
query = scope.createSelectorQuery();
|
|
1135
|
+
createdFromScope = true;
|
|
1136
|
+
}
|
|
1137
|
+
else if (typeof wx !== 'undefined' && wx && typeof wx.createSelectorQuery === 'function') {
|
|
1138
|
+
query = wx.createSelectorQuery();
|
|
1139
|
+
}
|
|
1140
|
+
else if (page && typeof page.createSelectorQuery === 'function') {
|
|
1141
|
+
query = page.createSelectorQuery();
|
|
1142
|
+
}
|
|
1143
|
+
if (!query) {
|
|
1144
|
+
return null;
|
|
1145
|
+
}
|
|
1146
|
+
if (!createdFromScope && typeof query.in === 'function') {
|
|
1147
|
+
try {
|
|
1148
|
+
query = query.in(scope || page);
|
|
1149
|
+
}
|
|
1150
|
+
catch (_) {
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
return query;
|
|
1154
|
+
}
|
|
1155
|
+
function pushUnique(list, seen, item) {
|
|
1156
|
+
if (!item) {
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
var id = item.is || item.id || item.__wxWebviewId__ || item.__wxExparserNodeId__ || String(list.length);
|
|
1160
|
+
if (seen[id]) {
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
1163
|
+
seen[id] = true;
|
|
1164
|
+
list.push(item);
|
|
1165
|
+
}
|
|
1166
|
+
function collectScopes(root, selectorList) {
|
|
1167
|
+
var scopes = [];
|
|
1168
|
+
var seen = {};
|
|
1169
|
+
var queue = [];
|
|
1170
|
+
pushUnique(scopes, seen, root);
|
|
1171
|
+
queue.push(root);
|
|
1172
|
+
for (var queueIndex = 0; queueIndex < queue.length && queueIndex < 30; queueIndex += 1) {
|
|
1173
|
+
var scope = queue[queueIndex];
|
|
1174
|
+
if (!scope || typeof scope.selectAllComponents !== 'function') {
|
|
1175
|
+
continue;
|
|
1176
|
+
}
|
|
1177
|
+
var children = [];
|
|
1178
|
+
var componentSelectors = Array.isArray(scopeSelectors) ? scopeSelectors.slice() : [];
|
|
1179
|
+
for (var selectorIndex = 0; selectorIndex < selectorList.length; selectorIndex += 1) {
|
|
1180
|
+
componentSelectors.push(selectorList[selectorIndex]);
|
|
1181
|
+
}
|
|
1182
|
+
componentSelectors.push('*', 'weapp-app-shell', 'weapp-layout-default');
|
|
1183
|
+
for (var componentIndex = 0; componentIndex < componentSelectors.length; componentIndex += 1) {
|
|
1184
|
+
if (!componentSelectors[componentIndex]) {
|
|
1185
|
+
continue;
|
|
1186
|
+
}
|
|
1187
|
+
try {
|
|
1188
|
+
var selected = scope.selectAllComponents(componentSelectors[componentIndex]);
|
|
1189
|
+
if (Array.isArray(selected)) {
|
|
1190
|
+
children = children.concat(selected);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
catch (_) {
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
for (var childIndex = 0; childIndex < children.length; childIndex += 1) {
|
|
1197
|
+
var child = children[childIndex];
|
|
1198
|
+
var previousLength = scopes.length;
|
|
1199
|
+
pushUnique(scopes, seen, child);
|
|
1200
|
+
if (scopes.length > previousLength) {
|
|
1201
|
+
queue.push(child);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
return scopes;
|
|
1206
|
+
}
|
|
1207
|
+
function queryScope(scope, page, selector) {
|
|
1208
|
+
return new Promise(function (resolve) {
|
|
1209
|
+
var settled = false;
|
|
1210
|
+
var timer = setTimeout(function () {
|
|
1211
|
+
if (settled) {
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
settled = true;
|
|
1215
|
+
resolve([]);
|
|
1216
|
+
}, 450);
|
|
1217
|
+
function finish(nodes) {
|
|
1218
|
+
if (settled) {
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
settled = true;
|
|
1222
|
+
clearTimeout(timer);
|
|
1223
|
+
resolve(Array.isArray(nodes) ? nodes : nodes ? [nodes] : []);
|
|
1224
|
+
}
|
|
1225
|
+
try {
|
|
1226
|
+
var query = createSelectorQuery(scope, page);
|
|
1227
|
+
if (!query) {
|
|
1228
|
+
finish([]);
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
query
|
|
1232
|
+
.selectAll(selector)
|
|
1233
|
+
.fields({
|
|
1234
|
+
dataset: true,
|
|
1235
|
+
id: true,
|
|
1236
|
+
rect: true,
|
|
1237
|
+
size: true
|
|
1238
|
+
}, function (nodes) {
|
|
1239
|
+
finish(nodes);
|
|
1240
|
+
})
|
|
1241
|
+
.exec();
|
|
1242
|
+
}
|
|
1243
|
+
catch (_) {
|
|
1244
|
+
finish([]);
|
|
1245
|
+
}
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
var selectorList = Array.isArray(selectors)
|
|
1249
|
+
? selectors.map(function (selector) {
|
|
1250
|
+
return String(selector || '').trim();
|
|
1251
|
+
}).filter(Boolean)
|
|
1252
|
+
: [];
|
|
1253
|
+
if (!selectorList.length) {
|
|
1254
|
+
return {};
|
|
1255
|
+
}
|
|
1256
|
+
var pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
1257
|
+
var expectedRoute = normalizeRoute(route);
|
|
1258
|
+
var page = null;
|
|
1259
|
+
for (var index = pages.length - 1; index >= 0; index -= 1) {
|
|
1260
|
+
var candidate = pages[index];
|
|
1261
|
+
var candidateRoute = normalizeRoute(candidate && (candidate.path || candidate.route || candidate.__route__));
|
|
1262
|
+
if ((!expectedRoute || candidateRoute === expectedRoute) && matchesQuery(candidate, query)) {
|
|
1263
|
+
page = candidate;
|
|
1264
|
+
break;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
if (!page) {
|
|
1268
|
+
return {};
|
|
1269
|
+
}
|
|
1270
|
+
return new Promise(function (resolve) {
|
|
1271
|
+
try {
|
|
1272
|
+
var result = {};
|
|
1273
|
+
var scopes = collectScopes(page, selectorList);
|
|
1274
|
+
var startedAt = Date.now();
|
|
1275
|
+
var maxQueries = 40;
|
|
1276
|
+
var queryCount = 0;
|
|
1277
|
+
var selectorIndex = 0;
|
|
1278
|
+
var scopeIndex = 0;
|
|
1279
|
+
function next() {
|
|
1280
|
+
if (selectorIndex >= selectorList.length || queryCount >= maxQueries || Date.now() - startedAt > 1800) {
|
|
1281
|
+
resolve(result);
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1284
|
+
var selector = selectorList[selectorIndex];
|
|
1285
|
+
if (scopeIndex >= scopes.length) {
|
|
1286
|
+
selectorIndex += 1;
|
|
1287
|
+
scopeIndex = 0;
|
|
1288
|
+
next();
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
var scope = scopes[scopeIndex];
|
|
1292
|
+
scopeIndex += 1;
|
|
1293
|
+
queryCount += 1;
|
|
1294
|
+
queryScope(scope, page, selector).then(function (nodes) {
|
|
1295
|
+
if (Array.isArray(nodes) && nodes.length > 0) {
|
|
1296
|
+
result[selector] = (result[selector] || []).concat(nodes);
|
|
1297
|
+
selectorIndex += 1;
|
|
1298
|
+
scopeIndex = 0;
|
|
1299
|
+
}
|
|
1300
|
+
next();
|
|
1301
|
+
}, function () {
|
|
1302
|
+
next();
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1305
|
+
next();
|
|
1306
|
+
}
|
|
1307
|
+
catch (_) {
|
|
1308
|
+
resolve({});
|
|
1309
|
+
}
|
|
1310
|
+
});
|
|
1311
|
+
}`,
|
|
1312
|
+
args: [
|
|
1313
|
+
normalizeRoute(this.path),
|
|
1314
|
+
this.query,
|
|
1315
|
+
normalizedSelectors,
|
|
1316
|
+
options.componentSelectors ?? []
|
|
1317
|
+
]
|
|
1318
|
+
}, { timeout: options.timeout ?? PAGE_RENDERED_QUERY_TIMEOUT });
|
|
1319
|
+
return result && typeof result === "object" && !Array.isArray(result) ? result : {};
|
|
1320
|
+
}
|
|
1321
|
+
async waitForRendered(options = {}) {
|
|
1322
|
+
const timeout = options.timeout ?? PAGE_RENDERED_TIMEOUT;
|
|
1323
|
+
const start = Date.now();
|
|
1324
|
+
let lastWxml = "";
|
|
1325
|
+
let lastRenderedNodes = [];
|
|
1326
|
+
let lastError;
|
|
1327
|
+
while (Date.now() - start <= timeout) {
|
|
1328
|
+
try {
|
|
1329
|
+
if (options.selector) {
|
|
1330
|
+
const nodes = await this.renderedNodes(options.selector, {
|
|
1331
|
+
componentSelectors: options.componentSelectors,
|
|
1332
|
+
timeout: Math.min(PAGE_RENDERED_QUERY_TIMEOUT, Math.max(1, timeout - (Date.now() - start)))
|
|
1333
|
+
});
|
|
1334
|
+
lastRenderedNodes = nodes;
|
|
1335
|
+
lastError = void 0;
|
|
1336
|
+
if (nodes.find((node) => matchesDataset(node, options.dataset))) return JSON.stringify({
|
|
1337
|
+
selector: options.selector,
|
|
1338
|
+
nodes
|
|
1339
|
+
});
|
|
1340
|
+
} else {
|
|
1341
|
+
const wxml = await this.wxml();
|
|
1342
|
+
lastWxml = wxml;
|
|
1343
|
+
lastError = void 0;
|
|
1344
|
+
const normalized = wxml.trim();
|
|
1345
|
+
if (options.predicate?.(wxml)) return wxml;
|
|
1346
|
+
if (options.text && normalized.includes(options.text)) return wxml;
|
|
1347
|
+
if (!options.text && !options.predicate && normalized && normalized !== "<text></text>") return wxml;
|
|
1348
|
+
}
|
|
1349
|
+
} catch (error) {
|
|
1350
|
+
lastError = error;
|
|
1351
|
+
}
|
|
1352
|
+
await sleep$1(PAGE_RENDERED_POLL_DELAY);
|
|
1353
|
+
}
|
|
1354
|
+
const reason = lastError instanceof Error ? lastError.message : String(lastError ?? "condition not met");
|
|
1355
|
+
const expected = options.selector ? ` selector=${options.selector} dataset=${JSON.stringify(options.dataset ?? {})}` : options.text ? ` text=${options.text}` : options.predicate ? " predicate=true" : " non-empty wxml";
|
|
1356
|
+
const latest = options.selector ? JSON.stringify(lastRenderedNodes).slice(0, 500) : lastWxml.slice(0, 500);
|
|
1357
|
+
throw new Error(`Timed out waiting page rendered:${expected}; reason=${reason}; latest=${latest}`);
|
|
1358
|
+
}
|
|
1359
|
+
async data(path, options = {}) {
|
|
806
1360
|
const payload = {};
|
|
807
1361
|
if (path) payload.path = path;
|
|
808
|
-
|
|
1362
|
+
const timeout = options.timeout ?? PAGE_DATA_TIMEOUT;
|
|
1363
|
+
if (options.routeOnly || this.preferRoutePageFallback) return await this.readRouteData(path, timeout);
|
|
1364
|
+
try {
|
|
1365
|
+
return (await this.send("Page.getData", payload, { timeout: Math.min(timeout, PAGE_DATA_PROTOCOL_TIMEOUT) })).data;
|
|
1366
|
+
} catch (error) {
|
|
1367
|
+
if (options.fallback === false) throw error;
|
|
1368
|
+
if (!isRecoverablePageProtocolError(error, "Page.getData")) throw error;
|
|
1369
|
+
this.preferRoutePageFallback = true;
|
|
1370
|
+
return await this.readRouteData(path, timeout);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
async readRouteData(path, timeout) {
|
|
1374
|
+
return (await this.connection.send("App.callFunction", {
|
|
1375
|
+
functionDeclaration: `function (route, query, dataPath) {
|
|
1376
|
+
function normalizeRoute(value) {
|
|
1377
|
+
return String(value || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
1378
|
+
}
|
|
1379
|
+
function matchesQuery(page, expectedQuery) {
|
|
1380
|
+
if (!expectedQuery || !Object.keys(expectedQuery).length) {
|
|
1381
|
+
return true;
|
|
1382
|
+
}
|
|
1383
|
+
var actualQuery = page && (page.options || page.query || {});
|
|
1384
|
+
return Object.keys(expectedQuery).every(function (key) {
|
|
1385
|
+
var actualValue = String(actualQuery[key] == null ? '' : actualQuery[key]);
|
|
1386
|
+
var expectedValue = String(expectedQuery[key]);
|
|
1387
|
+
var decodedActualValue = actualValue;
|
|
1388
|
+
try {
|
|
1389
|
+
decodedActualValue = decodeURIComponent(actualValue);
|
|
1390
|
+
}
|
|
1391
|
+
catch (_) {
|
|
1392
|
+
}
|
|
1393
|
+
return actualValue === expectedValue
|
|
1394
|
+
|| decodedActualValue === expectedValue
|
|
1395
|
+
|| actualValue === encodeURIComponent(expectedValue);
|
|
1396
|
+
});
|
|
1397
|
+
}
|
|
1398
|
+
function readPath(data, path) {
|
|
1399
|
+
if (!path) {
|
|
1400
|
+
return data;
|
|
1401
|
+
}
|
|
1402
|
+
if (data && Object.prototype.hasOwnProperty.call(data, path)) {
|
|
1403
|
+
return data[path];
|
|
1404
|
+
}
|
|
1405
|
+
return String(path).replace(/\\[(\\d+)\\]/g, '.$1').split('.').filter(Boolean).reduce(function (current, segment) {
|
|
1406
|
+
return current == null ? undefined : current[segment];
|
|
1407
|
+
}, data);
|
|
1408
|
+
}
|
|
1409
|
+
var pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
1410
|
+
var normalizedRoute = normalizeRoute(route);
|
|
1411
|
+
for (var index = pages.length - 1; index >= 0; index -= 1) {
|
|
1412
|
+
var page = pages[index];
|
|
1413
|
+
var pageRoute = normalizeRoute(page.path || page.route || page.__route__);
|
|
1414
|
+
if (pageRoute === normalizedRoute && matchesQuery(page, query)) {
|
|
1415
|
+
return readPath(page.data || {}, dataPath);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
return undefined;
|
|
1419
|
+
}`,
|
|
1420
|
+
args: [
|
|
1421
|
+
this.path,
|
|
1422
|
+
this.query,
|
|
1423
|
+
path
|
|
1424
|
+
]
|
|
1425
|
+
}, { timeout })).result;
|
|
809
1426
|
}
|
|
810
1427
|
async setData(data) {
|
|
811
|
-
|
|
1428
|
+
if (this.preferRoutePageFallback) {
|
|
1429
|
+
await this.setRouteData(data);
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
try {
|
|
1433
|
+
await this.send("Page.setData", { data }, { timeout: PAGE_SET_DATA_PROTOCOL_TIMEOUT });
|
|
1434
|
+
} catch (error) {
|
|
1435
|
+
if (!isRecoverablePageProtocolError(error, "Page.setData") && !isPageStackStaleError(error)) throw error;
|
|
1436
|
+
this.preferRoutePageFallback = true;
|
|
1437
|
+
await this.setRouteData(data);
|
|
1438
|
+
}
|
|
812
1439
|
}
|
|
813
1440
|
async size() {
|
|
814
1441
|
const [width, height] = await this.windowProperty(["document.documentElement.scrollWidth", "document.documentElement.scrollHeight"]);
|
|
@@ -818,10 +1445,146 @@ var Page = class Page {
|
|
|
818
1445
|
};
|
|
819
1446
|
}
|
|
820
1447
|
async callMethod(method, ...args) {
|
|
821
|
-
return
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
1448
|
+
return await this.callMethodWithOptions(method, {}, ...args);
|
|
1449
|
+
}
|
|
1450
|
+
async callMethodWithOptions(method, options = {}, ...args) {
|
|
1451
|
+
if (options.routeOnly || this.preferRoutePageFallback) return await this.callRouteMethod(method, args, options.timeout);
|
|
1452
|
+
try {
|
|
1453
|
+
return (await this.send("Page.callMethod", {
|
|
1454
|
+
method,
|
|
1455
|
+
args
|
|
1456
|
+
}, { timeout: options.timeout ?? PAGE_CALL_METHOD_PROTOCOL_TIMEOUT })).result;
|
|
1457
|
+
} catch (error) {
|
|
1458
|
+
if (options.fallback === false) throw error;
|
|
1459
|
+
if (!isRecoverablePageProtocolError(error, "Page.callMethod") && !isPageStackStaleError(error)) throw error;
|
|
1460
|
+
this.preferRoutePageFallback = true;
|
|
1461
|
+
}
|
|
1462
|
+
return await this.callRouteMethod(method, args, options.timeout);
|
|
1463
|
+
}
|
|
1464
|
+
async queryRouteElement(selector, options) {
|
|
1465
|
+
return (await this.queryRouteElements(selector, options))[0] ?? null;
|
|
1466
|
+
}
|
|
1467
|
+
async queryRouteElements(selector, options) {
|
|
1468
|
+
return (await this.renderedNodes(selector, {
|
|
1469
|
+
componentSelectors: options.componentSelectors,
|
|
1470
|
+
timeout: options.timeout ?? PAGE_QUERY_TIMEOUT
|
|
1471
|
+
})).map((node, index) => createRouteFallbackElement(this.connection, this.elementMap, this.id, selector, node, index));
|
|
1472
|
+
}
|
|
1473
|
+
async callRouteMethod(method, args, timeout = PAGE_CALL_METHOD_TIMEOUT) {
|
|
1474
|
+
let latestResult;
|
|
1475
|
+
for (let attempt = 1; attempt <= PAGE_CALL_METHOD_FALLBACK_RETRIES; attempt += 1) {
|
|
1476
|
+
try {
|
|
1477
|
+
const fallbackResult = (await this.connection.send("App.callFunction", {
|
|
1478
|
+
functionDeclaration: `async function (route, query, method, args) {
|
|
1479
|
+
var pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
1480
|
+
var normalizedRoute = String(route || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
1481
|
+
function methodResult(value) {
|
|
1482
|
+
return {
|
|
1483
|
+
__weappVitePageMethodFound: true,
|
|
1484
|
+
value: value
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
function matchesQuery(page, expectedQuery) {
|
|
1488
|
+
if (!expectedQuery || !Object.keys(expectedQuery).length) {
|
|
1489
|
+
return true;
|
|
1490
|
+
}
|
|
1491
|
+
var actualQuery = page && (page.options || page.query || {});
|
|
1492
|
+
return Object.keys(expectedQuery).every(function (key) {
|
|
1493
|
+
var actualValue = String(actualQuery[key] == null ? '' : actualQuery[key]);
|
|
1494
|
+
var expectedValue = String(expectedQuery[key]);
|
|
1495
|
+
var decodedActualValue = actualValue;
|
|
1496
|
+
try {
|
|
1497
|
+
decodedActualValue = decodeURIComponent(actualValue);
|
|
1498
|
+
}
|
|
1499
|
+
catch (_) {
|
|
1500
|
+
}
|
|
1501
|
+
return actualValue === expectedValue
|
|
1502
|
+
|| decodedActualValue === expectedValue
|
|
1503
|
+
|| actualValue === encodeURIComponent(expectedValue);
|
|
1504
|
+
});
|
|
1505
|
+
}
|
|
1506
|
+
for (var index = pages.length - 1; index >= 0; index -= 1) {
|
|
1507
|
+
var page = pages[index];
|
|
1508
|
+
var pageRoute = String(page.path || page.route || page.__route__ || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
1509
|
+
if (pageRoute === normalizedRoute && matchesQuery(page, query) && typeof page[method] === 'function') {
|
|
1510
|
+
return methodResult(await page[method].apply(page, args || []));
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
for (var fallbackIndex = pages.length - 1; fallbackIndex >= 0; fallbackIndex -= 1) {
|
|
1514
|
+
var fallbackPage = pages[fallbackIndex];
|
|
1515
|
+
if (matchesQuery(fallbackPage, query) && typeof fallbackPage[method] === 'function') {
|
|
1516
|
+
return methodResult(await fallbackPage[method].apply(fallbackPage, args || []));
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
return {
|
|
1520
|
+
__weappVitePageMethodFound: false
|
|
1521
|
+
};
|
|
1522
|
+
}`,
|
|
1523
|
+
args: [
|
|
1524
|
+
this.path,
|
|
1525
|
+
this.query,
|
|
1526
|
+
method,
|
|
1527
|
+
args
|
|
1528
|
+
]
|
|
1529
|
+
}, { timeout })).result;
|
|
1530
|
+
if (fallbackResult && typeof fallbackResult === "object" && fallbackResult.__weappVitePageMethodFound === true) return fallbackResult.value;
|
|
1531
|
+
latestResult = fallbackResult && typeof fallbackResult === "object" && fallbackResult.__weappVitePageMethodFound === false ? void 0 : fallbackResult;
|
|
1532
|
+
if (latestResult !== void 0 || attempt === PAGE_CALL_METHOD_FALLBACK_RETRIES) return latestResult;
|
|
1533
|
+
} catch (error) {
|
|
1534
|
+
if (!isProtocolTimeoutError(error, "App.callFunction") || attempt === PAGE_CALL_METHOD_FALLBACK_RETRIES) throw error;
|
|
1535
|
+
}
|
|
1536
|
+
await sleep$1(PAGE_CALL_METHOD_FALLBACK_RETRY_DELAY);
|
|
1537
|
+
}
|
|
1538
|
+
return latestResult;
|
|
1539
|
+
}
|
|
1540
|
+
async setRouteData(data) {
|
|
1541
|
+
for (let attempt = 1; attempt <= PAGE_CALL_METHOD_FALLBACK_RETRIES; attempt += 1) {
|
|
1542
|
+
try {
|
|
1543
|
+
await this.connection.send("App.callFunction", {
|
|
1544
|
+
functionDeclaration: `function (route, query, data) {
|
|
1545
|
+
var pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
1546
|
+
var normalizedRoute = String(route || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
1547
|
+
function matchesQuery(page, expectedQuery) {
|
|
1548
|
+
if (!expectedQuery || !Object.keys(expectedQuery).length) {
|
|
1549
|
+
return true;
|
|
1550
|
+
}
|
|
1551
|
+
var actualQuery = page && (page.options || page.query || {});
|
|
1552
|
+
return Object.keys(expectedQuery).every(function (key) {
|
|
1553
|
+
var actualValue = String(actualQuery[key] == null ? '' : actualQuery[key]);
|
|
1554
|
+
var expectedValue = String(expectedQuery[key]);
|
|
1555
|
+
var decodedActualValue = actualValue;
|
|
1556
|
+
try {
|
|
1557
|
+
decodedActualValue = decodeURIComponent(actualValue);
|
|
1558
|
+
}
|
|
1559
|
+
catch (_) {
|
|
1560
|
+
}
|
|
1561
|
+
return actualValue === expectedValue
|
|
1562
|
+
|| decodedActualValue === expectedValue
|
|
1563
|
+
|| actualValue === encodeURIComponent(expectedValue);
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1566
|
+
for (var index = pages.length - 1; index >= 0; index -= 1) {
|
|
1567
|
+
var page = pages[index];
|
|
1568
|
+
var pageRoute = String(page.path || page.route || page.__route__ || '').replace(/^\\/+/, '').replace(/\\/+$/g, '');
|
|
1569
|
+
if (pageRoute === normalizedRoute && matchesQuery(page, query) && typeof page.setData === 'function') {
|
|
1570
|
+
page.setData(data || {});
|
|
1571
|
+
return true;
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
return false;
|
|
1575
|
+
}`,
|
|
1576
|
+
args: [
|
|
1577
|
+
this.path,
|
|
1578
|
+
this.query,
|
|
1579
|
+
data
|
|
1580
|
+
]
|
|
1581
|
+
}, { timeout: PAGE_SET_DATA_TIMEOUT });
|
|
1582
|
+
return;
|
|
1583
|
+
} catch (error) {
|
|
1584
|
+
if (!isProtocolTimeoutError(error, "App.callFunction") || attempt === PAGE_CALL_METHOD_FALLBACK_RETRIES) throw error;
|
|
1585
|
+
}
|
|
1586
|
+
await sleep$1(PAGE_CALL_METHOD_FALLBACK_RETRY_DELAY);
|
|
1587
|
+
}
|
|
825
1588
|
}
|
|
826
1589
|
async scrollTop() {
|
|
827
1590
|
const bodyScrollTop = await this.windowProperty("document.body.scrollTop");
|
|
@@ -833,13 +1596,16 @@ var Page = class Page {
|
|
|
833
1596
|
const properties = (await this.send("Page.getWindowProperties", { names })).properties;
|
|
834
1597
|
return isStr(name) ? properties[0] : properties;
|
|
835
1598
|
}
|
|
836
|
-
async send(method, params = {}) {
|
|
1599
|
+
async send(method, params = {}, options) {
|
|
837
1600
|
params.pageId = this.id;
|
|
838
|
-
return await this.connection.send(method, params);
|
|
1601
|
+
return options ? await this.connection.send(method, params, options) : await this.connection.send(method, params);
|
|
839
1602
|
}
|
|
840
1603
|
static create(connection, options, pageMap) {
|
|
841
1604
|
const existing = pageMap.get(options.id);
|
|
842
|
-
if (existing)
|
|
1605
|
+
if (existing) {
|
|
1606
|
+
existing.updateFromOptions(options);
|
|
1607
|
+
return existing;
|
|
1608
|
+
}
|
|
843
1609
|
const page = new Page(connection, options);
|
|
844
1610
|
pageMap.set(options.id, page);
|
|
845
1611
|
return page;
|
|
@@ -850,7 +1616,7 @@ var Page = class Page {
|
|
|
850
1616
|
/**
|
|
851
1617
|
* @file 二维码与插件路径工具。
|
|
852
1618
|
*/
|
|
853
|
-
const regPluginId = /^plugin-private
|
|
1619
|
+
const regPluginId = /^(?:plugin-private:\/\/|__plugin__\/)([0-9a-zA-Z]+)\//;
|
|
854
1620
|
/** decodeQrCode 的方法封装。 */
|
|
855
1621
|
function decodeQrCode(qrCode) {
|
|
856
1622
|
return decodeQrCodeFromBase64(qrCode);
|
|
@@ -865,7 +1631,7 @@ function printQrCode(content) {
|
|
|
865
1631
|
/** isPluginPath 的方法封装。 */
|
|
866
1632
|
function isPluginPath(p) {
|
|
867
1633
|
if (typeof p !== "string") return false;
|
|
868
|
-
return startWith(p, "plugin-private://");
|
|
1634
|
+
return startWith(p, "plugin-private://") || startWith(p, "__plugin__/");
|
|
869
1635
|
}
|
|
870
1636
|
/** extractPluginId 的方法封装。 */
|
|
871
1637
|
function extractPluginId(p) {
|
|
@@ -882,6 +1648,10 @@ const CHANGE_ROUTE_CONTEXT_TIMEOUT = 12e3;
|
|
|
882
1648
|
const CHANGE_ROUTE_CALL_TIMEOUT = 12e3;
|
|
883
1649
|
const CHANGE_ROUTE_READY_TIMEOUT = 15e3;
|
|
884
1650
|
const CHANGE_ROUTE_POLL_DELAY = 500;
|
|
1651
|
+
const CHANGE_ROUTE_POLL_PROTOCOL_TIMEOUT = 2500;
|
|
1652
|
+
const CHANGE_ROUTE_APP_FUNCTION_TIMEOUT = 15e3;
|
|
1653
|
+
const CHANGE_ROUTE_APP_FUNCTION_RETRIES = 2;
|
|
1654
|
+
const CHANGE_ROUTE_APP_FUNCTION_RETRY_DELAY = 800;
|
|
885
1655
|
const APP_READY_TIMEOUT = 2e4;
|
|
886
1656
|
const APP_READY_PROBE_TIMEOUT = 3e3;
|
|
887
1657
|
const APP_READY_POLL_DELAY = 500;
|
|
@@ -919,6 +1689,17 @@ function isCurrentPageProtocolTimeout(error) {
|
|
|
919
1689
|
function isPageStackProtocolTimeout(error) {
|
|
920
1690
|
return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === "App.getPageStack";
|
|
921
1691
|
}
|
|
1692
|
+
function isCallFunctionProtocolTimeout(error) {
|
|
1693
|
+
return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === "App.callFunction";
|
|
1694
|
+
}
|
|
1695
|
+
function isPageMetaMissingError(error) {
|
|
1696
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1697
|
+
return message.includes("getPageMetaByWebviewId") && message.includes("rawPath") && message.includes("is null");
|
|
1698
|
+
}
|
|
1699
|
+
function isCurrentFrameTimedOutError(error) {
|
|
1700
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1701
|
+
return message.includes("unexpected current frame status timedout") || message.includes("[loader] unexpected current frame status timedout");
|
|
1702
|
+
}
|
|
922
1703
|
function isCallWxMethodProtocolTimeout(error) {
|
|
923
1704
|
return error instanceof Error && "code" in error && error.code === "DEVTOOLS_PROTOCOL_TIMEOUT" && "method" in error && error.method === "App.callWxMethod";
|
|
924
1705
|
}
|
|
@@ -928,11 +1709,44 @@ function isCaptureScreenshotRecoverableError(error) {
|
|
|
928
1709
|
return error.message.includes("fail to capture screenshot") || error.message.includes("App.captureScreenshot");
|
|
929
1710
|
}
|
|
930
1711
|
function isRouteContextProbeError(error) {
|
|
931
|
-
return isCurrentPageProtocolTimeout(error) || isPageStackProtocolTimeout(error);
|
|
1712
|
+
return isCurrentPageProtocolTimeout(error) || isPageStackProtocolTimeout(error) || isPageMetaMissingError(error) || isCurrentFrameTimedOutError(error);
|
|
1713
|
+
}
|
|
1714
|
+
function isRoutePollingRecoverableError(error) {
|
|
1715
|
+
return isRouteContextProbeError(error) || isCallFunctionProtocolTimeout(error) || isPageStackProtocolTimeout(error) || isPageMetaMissingError(error);
|
|
1716
|
+
}
|
|
1717
|
+
function resolveAppFunctionTimeout(timeout) {
|
|
1718
|
+
return Math.max(timeout ?? CHANGE_ROUTE_APP_FUNCTION_TIMEOUT, CHANGE_ROUTE_APP_FUNCTION_TIMEOUT);
|
|
932
1719
|
}
|
|
933
1720
|
function normalizeRoutePath(value) {
|
|
934
1721
|
return String(value ?? "").split("?", 1)[0].replace(/^\/+/, "").replace(/\/+$/, "");
|
|
935
1722
|
}
|
|
1723
|
+
function isPluginNavigationUrl(value) {
|
|
1724
|
+
return String(value ?? "").startsWith("plugin://");
|
|
1725
|
+
}
|
|
1726
|
+
function matchesRouteChange(options) {
|
|
1727
|
+
const normalizedCurrentPath = normalizeRoutePath(options.currentPath);
|
|
1728
|
+
if (!options.expectedRoute || normalizedCurrentPath === options.expectedRoute) return true;
|
|
1729
|
+
if (!isPluginNavigationUrl(options.requestedUrl) || !isPluginPath(options.currentPath)) return false;
|
|
1730
|
+
return normalizedCurrentPath !== normalizeRoutePath(options.previousPath);
|
|
1731
|
+
}
|
|
1732
|
+
function parseRouteQuery(value) {
|
|
1733
|
+
const queryText = String(value ?? "").split("?", 2)[1] ?? "";
|
|
1734
|
+
const query = {};
|
|
1735
|
+
if (!queryText) return query;
|
|
1736
|
+
for (const part of queryText.split("&")) {
|
|
1737
|
+
if (!part) continue;
|
|
1738
|
+
const [rawKey, rawValue = ""] = part.split("=", 2);
|
|
1739
|
+
if (!rawKey) continue;
|
|
1740
|
+
query[decodeURIComponent(rawKey)] = decodeURIComponent(rawValue);
|
|
1741
|
+
}
|
|
1742
|
+
return query;
|
|
1743
|
+
}
|
|
1744
|
+
function resolvePagePayloadId(page, fallbackId) {
|
|
1745
|
+
return page.pageId ?? page.__wxWebviewId__ ?? page.__webviewId__ ?? fallbackId;
|
|
1746
|
+
}
|
|
1747
|
+
function resolvePagePayloadPath(page) {
|
|
1748
|
+
return page.path ?? page.route ?? page.__route__ ?? "";
|
|
1749
|
+
}
|
|
936
1750
|
function logChangeRouteDebug(message) {
|
|
937
1751
|
if (!CHANGE_ROUTE_DEBUG_ENABLED) return;
|
|
938
1752
|
process.stdout.write(`[automator:changeRoute] ${message}\n`);
|
|
@@ -941,6 +1755,7 @@ function logChangeRouteDebug(message) {
|
|
|
941
1755
|
var MiniProgram = class extends EventEmitter {
|
|
942
1756
|
connection;
|
|
943
1757
|
appBindings = /* @__PURE__ */ new Map();
|
|
1758
|
+
logEnabled = false;
|
|
944
1759
|
pageMap = /* @__PURE__ */ new Map();
|
|
945
1760
|
nativeIns;
|
|
946
1761
|
constructor(connection) {
|
|
@@ -980,30 +1795,27 @@ var MiniProgram = class extends EventEmitter {
|
|
|
980
1795
|
const retries = options.retries ?? CURRENT_PAGE_RETRIES;
|
|
981
1796
|
const sendOptions = options.timeout ? { timeout: options.timeout } : void 0;
|
|
982
1797
|
for (let attempt = 1; attempt <= retries; attempt += 1) try {
|
|
983
|
-
const
|
|
984
|
-
return
|
|
985
|
-
id: pageId,
|
|
986
|
-
path,
|
|
987
|
-
query
|
|
988
|
-
}, this.pageMap);
|
|
1798
|
+
const page = await this.send("App.getCurrentPage", {}, sendOptions);
|
|
1799
|
+
return this.createPageFromPayload(page);
|
|
989
1800
|
} catch (error) {
|
|
990
1801
|
lastError = error;
|
|
991
|
-
if (!isCurrentPageProtocolTimeout(error)) throw error;
|
|
1802
|
+
if (!isCurrentPageProtocolTimeout(error) && !isPageMetaMissingError(error) && !isCurrentFrameTimedOutError(error)) throw error;
|
|
992
1803
|
if (attempt < retries) {
|
|
993
1804
|
await sleep(CURRENT_PAGE_RETRY_DELAY);
|
|
994
1805
|
continue;
|
|
995
1806
|
}
|
|
996
1807
|
}
|
|
997
|
-
if (isCurrentPageProtocolTimeout(lastError)) try {
|
|
1808
|
+
if (isCurrentPageProtocolTimeout(lastError) || isPageMetaMissingError(lastError) || isCurrentFrameTimedOutError(lastError)) try {
|
|
998
1809
|
const { pageStack } = await this.send("App.getPageStack", {}, sendOptions);
|
|
999
1810
|
const page = pageStack[pageStack.length - 1];
|
|
1000
|
-
if (page) return
|
|
1001
|
-
id: page.pageId,
|
|
1002
|
-
path: page.path,
|
|
1003
|
-
query: page.query
|
|
1004
|
-
}, this.pageMap);
|
|
1811
|
+
if (page) return this.createPageFromPayload(page, pageStack.length);
|
|
1005
1812
|
} catch (error) {
|
|
1006
|
-
if (!isPageStackProtocolTimeout(error)) throw error;
|
|
1813
|
+
if (!isPageStackProtocolTimeout(error) && !isPageMetaMissingError(error) && !isCurrentFrameTimedOutError(error)) throw error;
|
|
1814
|
+
}
|
|
1815
|
+
if ((options.appFunctionFallback ?? true) && (isCurrentPageProtocolTimeout(lastError) || isPageMetaMissingError(lastError) || isCurrentFrameTimedOutError(lastError))) {
|
|
1816
|
+
const pageStack = await this.readAppFunctionPageStack(resolveAppFunctionTimeout(sendOptions?.timeout));
|
|
1817
|
+
const page = pageStack[pageStack.length - 1];
|
|
1818
|
+
if (page) return page;
|
|
1007
1819
|
}
|
|
1008
1820
|
throw lastError;
|
|
1009
1821
|
}
|
|
@@ -1016,6 +1828,13 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1016
1828
|
args
|
|
1017
1829
|
})).result;
|
|
1018
1830
|
}
|
|
1831
|
+
async callWxMethodWithOptions(method, options = {}, ...args) {
|
|
1832
|
+
const sendOptions = options.timeout ? { timeout: options.timeout } : void 0;
|
|
1833
|
+
return (await this.send("App.callWxMethod", {
|
|
1834
|
+
method,
|
|
1835
|
+
args
|
|
1836
|
+
}, sendOptions)).result;
|
|
1837
|
+
}
|
|
1019
1838
|
async callWxMethodWithTimeout(method, timeout, ...args) {
|
|
1020
1839
|
return (await this.send("App.callWxMethod", {
|
|
1021
1840
|
method,
|
|
@@ -1069,10 +1888,14 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1069
1888
|
});
|
|
1070
1889
|
}
|
|
1071
1890
|
async evaluate(appFunction, ...args) {
|
|
1891
|
+
return await this.evaluateWithOptions(appFunction, {}, ...args);
|
|
1892
|
+
}
|
|
1893
|
+
async evaluateWithOptions(appFunction, options = {}, ...args) {
|
|
1894
|
+
const sendOptions = options.timeout ? { timeout: options.timeout } : void 0;
|
|
1072
1895
|
const { result } = await this.send("App.callFunction", {
|
|
1073
1896
|
functionDeclaration: appFunction.toString(),
|
|
1074
1897
|
args
|
|
1075
|
-
});
|
|
1898
|
+
}, sendOptions);
|
|
1076
1899
|
return result;
|
|
1077
1900
|
}
|
|
1078
1901
|
async pageScrollTo(scrollTop) {
|
|
@@ -1105,8 +1928,12 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1105
1928
|
disconnect() {
|
|
1106
1929
|
this.connection.dispose();
|
|
1107
1930
|
}
|
|
1931
|
+
async enableLog() {
|
|
1932
|
+
await this.send("App.enableLog");
|
|
1933
|
+
this.logEnabled = true;
|
|
1934
|
+
}
|
|
1108
1935
|
on(event, listener) {
|
|
1109
|
-
if (event === "console") this.
|
|
1936
|
+
if (event === "console" && !this.logEnabled) this.enableLog().catch(() => {});
|
|
1110
1937
|
super.on(event, listener);
|
|
1111
1938
|
return this;
|
|
1112
1939
|
}
|
|
@@ -1198,14 +2025,19 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1198
2025
|
async changeRoute(method, url) {
|
|
1199
2026
|
const currentPage = await this.resolveRouteContextPage();
|
|
1200
2027
|
logChangeRouteDebug(`start method=${method} url=${url ?? "<none>"} current=${currentPage?.path ?? "<none>"}`);
|
|
2028
|
+
let routeCommandSent = false;
|
|
1201
2029
|
try {
|
|
1202
2030
|
if (currentPage && isPluginPath(currentPage.path)) await this.callPluginWxMethod(extractPluginId(currentPage.path), method, { url });
|
|
1203
2031
|
else await this.callWxMethodWithTimeout(method, CHANGE_ROUTE_CALL_TIMEOUT, { url });
|
|
2032
|
+
routeCommandSent = true;
|
|
1204
2033
|
} catch (error) {
|
|
1205
|
-
if (isCallWxMethodProtocolTimeout(error) || isOperationTimeoutError(error, CHANGE_ROUTE_CALL_TIMEOUT)
|
|
1206
|
-
|
|
2034
|
+
if (isCallWxMethodProtocolTimeout(error) || isOperationTimeoutError(error, CHANGE_ROUTE_CALL_TIMEOUT) || isPageMetaMissingError(error)) {
|
|
2035
|
+
routeCommandSent = true;
|
|
2036
|
+
logChangeRouteDebug(`call-timeout method=${method} url=${url ?? "<none>"}`);
|
|
2037
|
+
} else throw error;
|
|
1207
2038
|
}
|
|
1208
2039
|
const expectedRoute = normalizeRoutePath(url);
|
|
2040
|
+
const expectedRouteQuery = parseRouteQuery(url);
|
|
1209
2041
|
const startedAt = Date.now();
|
|
1210
2042
|
let lastPage;
|
|
1211
2043
|
let lastError;
|
|
@@ -1214,7 +2046,12 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1214
2046
|
const page = await this.readRoutePollingCurrentPage();
|
|
1215
2047
|
lastPage = page;
|
|
1216
2048
|
logChangeRouteDebug(`poll method=${method} url=${url ?? "<none>"} current=${page?.path ?? "<none>"}`);
|
|
1217
|
-
if (
|
|
2049
|
+
if (matchesRouteChange({
|
|
2050
|
+
currentPath: page?.path,
|
|
2051
|
+
previousPath: currentPage?.path,
|
|
2052
|
+
requestedUrl: url,
|
|
2053
|
+
expectedRoute
|
|
2054
|
+
})) {
|
|
1218
2055
|
logChangeRouteDebug(`ready method=${method} url=${url ?? "<none>"} current=${page?.path ?? "<none>"}`);
|
|
1219
2056
|
return page;
|
|
1220
2057
|
}
|
|
@@ -1228,7 +2065,12 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1228
2065
|
if (stackTop) {
|
|
1229
2066
|
lastPage = stackTop;
|
|
1230
2067
|
logChangeRouteDebug(`stack method=${method} url=${url ?? "<none>"} current=${stackTop.path}`);
|
|
1231
|
-
if (
|
|
2068
|
+
if (matchesRouteChange({
|
|
2069
|
+
currentPath: stackTop.path,
|
|
2070
|
+
previousPath: currentPage?.path,
|
|
2071
|
+
requestedUrl: url,
|
|
2072
|
+
expectedRoute
|
|
2073
|
+
})) {
|
|
1232
2074
|
logChangeRouteDebug(`stack-ready method=${method} url=${url ?? "<none>"} current=${stackTop.path}`);
|
|
1233
2075
|
return stackTop;
|
|
1234
2076
|
}
|
|
@@ -1236,7 +2078,7 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1236
2078
|
} catch (error) {
|
|
1237
2079
|
lastError = error;
|
|
1238
2080
|
logChangeRouteDebug(`stack-error method=${method} url=${url ?? "<none>"} error=${error instanceof Error ? error.message : String(error)}`);
|
|
1239
|
-
if (isOperationTimeoutError(error, CHANGE_ROUTE_CONTEXT_TIMEOUT)) {
|
|
2081
|
+
if (isOperationTimeoutError(error, CHANGE_ROUTE_CONTEXT_TIMEOUT) || isRoutePollingRecoverableError(error)) {
|
|
1240
2082
|
await sleep(CHANGE_ROUTE_POLL_DELAY);
|
|
1241
2083
|
continue;
|
|
1242
2084
|
}
|
|
@@ -1248,11 +2090,23 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1248
2090
|
throw new Error(`Timed out waiting route ${expectedRoute || "<current>"} after ${method}; current page: ${lastPage.path}`);
|
|
1249
2091
|
}
|
|
1250
2092
|
logChangeRouteDebug(`timeout method=${method} url=${url ?? "<none>"} current=<none> error=${lastError instanceof Error ? lastError.message : String(lastError)}`);
|
|
2093
|
+
if (isRoutePollingRecoverableError(lastError)) {
|
|
2094
|
+
if (routeCommandSent && expectedRoute) return this.createPageFromPayload({
|
|
2095
|
+
pageId: 1,
|
|
2096
|
+
path: `/${expectedRoute}`,
|
|
2097
|
+
query: expectedRouteQuery
|
|
2098
|
+
});
|
|
2099
|
+
throw new Error(`Timed out waiting route ${expectedRoute || "<current>"} after ${method}; last recoverable error: ${lastError instanceof Error ? lastError.message : String(lastError)}`);
|
|
2100
|
+
}
|
|
1251
2101
|
throw lastError instanceof Error ? lastError : /* @__PURE__ */ new Error(`Timed out waiting route ${expectedRoute || "<current>"} after ${method}`);
|
|
1252
2102
|
}
|
|
1253
2103
|
async resolveRouteContextPage() {
|
|
1254
|
-
const currentPageTask = this.currentPage(
|
|
1255
|
-
|
|
2104
|
+
const currentPageTask = this.currentPage({
|
|
2105
|
+
appFunctionFallback: false,
|
|
2106
|
+
retries: 1,
|
|
2107
|
+
timeout: CHANGE_ROUTE_POLL_PROTOCOL_TIMEOUT
|
|
2108
|
+
}).catch((error) => {
|
|
2109
|
+
if (isRoutePollingRecoverableError(error)) return;
|
|
1256
2110
|
throw error;
|
|
1257
2111
|
});
|
|
1258
2112
|
const timeoutTask = sleep(CHANGE_ROUTE_CONTEXT_TIMEOUT).then(() => void 0);
|
|
@@ -1263,22 +2117,51 @@ var MiniProgram = class extends EventEmitter {
|
|
|
1263
2117
|
}
|
|
1264
2118
|
}
|
|
1265
2119
|
async readRoutePollingCurrentPage() {
|
|
1266
|
-
const
|
|
2120
|
+
const page = await this.send("App.getCurrentPage", {}, { timeout: CHANGE_ROUTE_POLL_PROTOCOL_TIMEOUT });
|
|
2121
|
+
return this.createPageFromPayload(page);
|
|
2122
|
+
}
|
|
2123
|
+
async readRoutePollingPageStack() {
|
|
2124
|
+
try {
|
|
2125
|
+
const { pageStack } = await this.send("App.getPageStack", {}, { timeout: CHANGE_ROUTE_POLL_PROTOCOL_TIMEOUT });
|
|
2126
|
+
return this.createPagesFromPayloads(pageStack);
|
|
2127
|
+
} catch (error) {
|
|
2128
|
+
if (!isPageStackProtocolTimeout(error) && !isPageMetaMissingError(error)) throw error;
|
|
2129
|
+
throw error;
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
createPageFromPayload(page, fallbackId = 1) {
|
|
1267
2133
|
return Page.create(this.connection, {
|
|
1268
|
-
id:
|
|
1269
|
-
path,
|
|
1270
|
-
query
|
|
2134
|
+
id: resolvePagePayloadId(page, fallbackId),
|
|
2135
|
+
path: resolvePagePayloadPath(page),
|
|
2136
|
+
query: page.query ?? page.options ?? {}
|
|
1271
2137
|
}, this.pageMap);
|
|
1272
2138
|
}
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
2139
|
+
createPagesFromPayloads(pageStack) {
|
|
2140
|
+
return pageStack.map((page, index) => this.createPageFromPayload(page, index + 1));
|
|
2141
|
+
}
|
|
2142
|
+
async readAppFunctionPageStack(timeout = CHANGE_ROUTE_APP_FUNCTION_TIMEOUT, retries = CHANGE_ROUTE_APP_FUNCTION_RETRIES) {
|
|
2143
|
+
let lastError;
|
|
2144
|
+
for (let attempt = 1; attempt <= retries; attempt += 1) try {
|
|
2145
|
+
const { result } = await this.send("App.callFunction", {
|
|
2146
|
+
functionDeclaration: `function () {
|
|
2147
|
+
var pages = typeof getCurrentPages === 'function' ? getCurrentPages() : [];
|
|
2148
|
+
return pages.map(function (page, index) {
|
|
2149
|
+
return {
|
|
2150
|
+
pageId: page.pageId || page.__wxWebviewId__ || page.__webviewId__ || index + 1,
|
|
2151
|
+
path: page.path || page.route || page.__route__ || '',
|
|
2152
|
+
query: page.query || page.options || {}
|
|
2153
|
+
};
|
|
2154
|
+
});
|
|
2155
|
+
}`,
|
|
2156
|
+
args: []
|
|
2157
|
+
}, { timeout });
|
|
2158
|
+
return this.createPagesFromPayloads(Array.isArray(result) ? result : []);
|
|
2159
|
+
} catch (error) {
|
|
2160
|
+
lastError = error;
|
|
2161
|
+
if (!isCallFunctionProtocolTimeout(error) || attempt >= retries) throw error;
|
|
2162
|
+
await sleep(CHANGE_ROUTE_APP_FUNCTION_RETRY_DELAY);
|
|
2163
|
+
}
|
|
2164
|
+
throw lastError;
|
|
1282
2165
|
}
|
|
1283
2166
|
async send(method, params = {}, options) {
|
|
1284
2167
|
return options ? await this.connection.send(method, params, options) : await this.connection.send(method, params);
|
|
@@ -1676,7 +2559,8 @@ async function launch(options = {}) {
|
|
|
1676
2559
|
}
|
|
1677
2560
|
async function connect(options) {
|
|
1678
2561
|
if (typeof options.wsEndpoint !== "string") throw new TypeError("wsEndpoint is required for smartapp runtime connection.");
|
|
1679
|
-
|
|
2562
|
+
const miniProgram = await connectMiniProgram(options.wsEndpoint);
|
|
2563
|
+
return new SmartappDevice("devtools", DEFAULT_CONNECT_TYPE, "devtools-usb", { miniProgram });
|
|
1680
2564
|
}
|
|
1681
2565
|
async function devices(deviceType, _connectType = DEFAULT_CONNECT_TYPE) {
|
|
1682
2566
|
const resolvedDeviceType = resolveDeviceType(deviceType);
|
|
@@ -1878,7 +2762,10 @@ var Launcher = class {
|
|
|
1878
2762
|
await waitUntil(async () => {
|
|
1879
2763
|
try {
|
|
1880
2764
|
if (processError) return true;
|
|
1881
|
-
const candidate = await this.connectTool({
|
|
2765
|
+
const candidate = await this.connectTool({
|
|
2766
|
+
timeout: 3e3,
|
|
2767
|
+
wsEndpoint: `ws://127.0.0.1:${port}`
|
|
2768
|
+
});
|
|
1882
2769
|
try {
|
|
1883
2770
|
await candidate.checkVersion();
|
|
1884
2771
|
if (typeof candidate.waitForAppReady === "function") await candidate.waitForAppReady(timeout);
|
|
@@ -1930,7 +2817,7 @@ var Launcher = class {
|
|
|
1930
2817
|
}
|
|
1931
2818
|
async connectTool(options) {
|
|
1932
2819
|
try {
|
|
1933
|
-
return new MiniProgram(await Connection.create(options.wsEndpoint));
|
|
2820
|
+
return new MiniProgram(await Connection.create(options.wsEndpoint, options.timeout));
|
|
1934
2821
|
} catch {
|
|
1935
2822
|
throw new Error(`Failed connecting to ${options.wsEndpoint}, check if target project window is opened with automation enabled`);
|
|
1936
2823
|
}
|