修改未完成

This commit is contained in:
rain
2026-07-29 18:15:59 +08:00
parent 6fbcf21024
commit 8c2355a52c
59 changed files with 7995 additions and 1118 deletions
+134
View File
@@ -0,0 +1,134 @@
"use strict";
const assert = require("assert");
const fs = require("fs");
const cdpPort = process.env.CDP_PORT || "9222";
const requestedRoute = process.env.MUMU_ROUTE || "";
const getTargets = async () => (await fetch(`http://127.0.0.1:${cdpPort}/json/list`)).json();
const sleep = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
const latestRouteTarget = (targets, routePrefix = "pages/") => targets
.filter((candidate) => candidate.type === "page" && candidate.title.startsWith(routePrefix))
.sort((left, right) => {
const leftIndex = Number(left.title.match(/\[(\d+)\]$/)?.[1] || 0);
const rightIndex = Number(right.title.match(/\[(\d+)\]$/)?.[1] || 0);
return rightIndex - leftIndex;
})[0];
const connect = async (target) => {
const socket = new WebSocket(target.webSocketDebuggerUrl);
await new Promise((resolve, reject) => {
socket.addEventListener("open", resolve, { once: true });
socket.addEventListener("error", reject, { once: true });
});
let id = 0;
const pending = new Map();
socket.addEventListener("message", (event) => {
const message = JSON.parse(event.data);
const request = pending.get(message.id);
if (!request) return;
pending.delete(message.id);
message.error ? request.reject(new Error(message.error.message)) : request.resolve(message.result);
});
const send = (method, params = {}) => new Promise((resolve, reject) => {
id += 1;
const requestId = id;
pending.set(requestId, { resolve, reject });
socket.send(JSON.stringify({ id: requestId, method, params }));
});
return { socket, send };
};
const run = async () => {
const configuredRoutes = JSON.parse(fs.readFileSync("pages.json", "utf8")).pages.map((page) => page.path);
const routes = requestedRoute ? [requestedRoute] : configuredRoutes;
assert.ok(routes.every((route) => configuredRoutes.includes(route)), "requested route is not configured in pages.json");
const failures = [];
let previousRoute = "";
for (const route of routes) {
await sleep(previousRoute === "pages/auth/a01-entry" ? 1600 : 350);
const activeTarget = latestRouteTarget(await getTargets());
if (!activeTarget) {
failures.push(`${route}: no active Uni page WebView`);
continue;
}
const active = await connect(activeTarget);
try {
void active.send("Runtime.evaluate", {
expression: `uni.reLaunch({ url: ${JSON.stringify(`/${route}`)} })`,
returnByValue: true,
}).catch(() => {});
} finally {
active.socket.close();
}
const deadline = Date.now() + 5000;
let routedTarget = null;
while (!routedTarget && Date.now() < deadline) {
routedTarget = latestRouteTarget(await getTargets(), `${route}[`);
if (!routedTarget) await sleep(100);
}
if (!routedTarget) {
await sleep(500);
const retryTarget = latestRouteTarget(await getTargets());
if (retryTarget) {
const retry = await connect(retryTarget);
try {
void retry.send("Runtime.evaluate", {
expression: `uni.reLaunch({ url: ${JSON.stringify(`/${route}`)} })`,
returnByValue: true,
}).catch(() => {});
} finally {
retry.socket.close();
}
const retryDeadline = Date.now() + 5000;
while (!routedTarget && Date.now() < retryDeadline) {
routedTarget = latestRouteTarget(await getTargets(), `${route}[`);
if (!routedTarget) await sleep(100);
}
}
}
if (!routedTarget) {
failures.push(`${route}: native route did not open`);
continue;
}
const routed = await connect(routedTarget);
const exceptions = [];
routed.socket.addEventListener("message", (event) => {
const message = JSON.parse(event.data);
if (message.method === "Runtime.exceptionThrown") exceptions.push(message.params.exceptionDetails.text);
});
try {
await routed.send("Runtime.enable");
let page = null;
while (Date.now() < deadline) {
const result = await routed.send("Runtime.evaluate", {
expression: "JSON.stringify({ textLength: document.body?.innerText?.trim().length || 0, loading: [...document.querySelectorAll('.app-loading, .uni-loading, .loading-spinner')].some((element) => { const style = getComputedStyle(element); const rect = element.getBoundingClientRect(); return style.display !== 'none' && style.visibility !== 'hidden' && Number(style.opacity || 1) > 0 && rect.width > 0 && rect.height > 0; }) })",
returnByValue: true,
});
page = JSON.parse(result.result?.value || "{}");
if (page.textLength > 0 && !page.loading) break;
await sleep(100);
}
if (!page?.textLength || page.loading) {
failures.push(`${route}: page did not reach a stable rendered state`);
} else if (exceptions.length) {
failures.push(`${route}: ${exceptions.join("; ")}`);
} else {
process.stdout.write(`PASS ${route}\n`);
}
} finally {
routed.socket.close();
}
previousRoute = route;
}
if (failures.length) throw new Error(`MuMu native route audit failures:\n${failures.map((failure) => `- ${failure}`).join("\n")}`);
process.stdout.write(`MUMU-NATIVE-ROUTE-RUNTIME-SMOKE PASS routes=${routes.length}\n`);
};
run().catch((error) => {
process.stderr.write(`${error.stack || error.message}\n`);
process.exit(1);
});