fix(web-probe): 适配持续连接页面截图

This commit is contained in:
pikastech
2026-07-21 10:44:19 +02:00
parent e5d3749079
commit 8e9bca49fc
6 changed files with 23 additions and 2 deletions
+1
View File
@@ -129,6 +129,7 @@ description: UniDesk Web 开发与受控浏览器验证技能。用户提到 Web
- 再用 `web-probe screenshot` 从 owning YAML 选择的固定公网入口打开该 session 深链,观察用户可见的消息、终态和语义化错误;
- 不把 WebProbe 的硬编码 DOM selector、长等待、临时 Playwright 脚本或探针自身超时作为 Workbench 业务终态的唯一门禁;探针异常时保留其作为工具证据,并以 CLI 终态和截图继续归因;
- CLI 必须走同一产品 dispatcher 和身份语义,禁止以 direct manager、snapshot、result polling 或其他第二业务路径替代。
- 一次性截图默认按 `domcontentloaded` 导航,持续 SSE 页面不得改用 `networkidle`;完整边界见 [references/web-probe.md](references/web-probe.md)。
- Native 阶段采用短反馈循环:
- 修改后先执行最小语法检查和目标功能验证;
- 使用 `web-probe` 从 YAML 选择的固定 HTTPS 或公网 HTTP 入口验证真实 DOM、交互、布局和截图;custom/local 仅记录为 preflight,不能宣称 L1 通过;
@@ -4,6 +4,10 @@
- 交互流程使用 `observe start``observe command``observe collect``observe analyze`
- `run``script` 只用于有界探测和 smoke
- 收尾证据引用 observer id、command id、artifact/report SHA、screenshot SHA 和关键有界字段。
- 一次性截图的导航完成条件:
- `web-probe screenshot` 默认使用 `domcontentloaded`,适用于持续 SSE、WebSocket 和长轮询页面;
- 只有页面能够稳定进入网络静默时,才显式传 `--wait-until networkidle`
- 需要业务 DOM 或交互判定时继续使用 typed readiness 或 observer,不能把导航完成当作业务通过。
- L1 native Web 公网 readiness
- 使用 `bun scripts/cli.ts web-probe native-readiness --node <node> --lane <lane> --profile <profile>`
- 固定 HTTPS origin 来自 lane 的 `nativeDevelopment.publicExposure`,页面与判据来自 `nativeReadinessProfiles`
+2
View File
@@ -182,12 +182,14 @@ export function hwlabNodeWebProbeScreenshotHelp(): Record<string, unknown> {
"--path": "附加到 semantic origin 的绝对路径;与 --url 互斥。",
"--url": "custom/local 一次性 URL,必须包含完整路径;与 --origin、--path 互斥。",
"--viewport": "截图视口,默认 1440x900。",
"--wait-until": "导航完成条件,默认 domcontentloaded;静态页面可显式选择 networkidle。",
"--selector": "等待指定 selector 后再截图。",
"--full-page|--no-full-page": "选择整页或当前视口截图。",
},
notes: [
"使用 --url 时不要再传 --pathcustom/local URL 已包含完整路径。",
"internal/public/native 运行面必须通过 owning YAML 的 --origin 选择,禁止用手写 URL 或 IP 替代。",
"持续 SSE、WebSocket 或长轮询页面使用默认 domcontentloadednetworkidle 只用于能够稳定进入网络静默的页面。",
"该命令只采集证据,不修改浏览器能力、资源门禁或运行面。",
],
mutation: false,
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
import { test } from "bun:test";
import { hwlabNodeWebProbeHelp, hwlabNodeWebProbeScreenshotHelp } from "../hwlab-node-help";
import { parseNodeWebProbeOptions } from "./web-probe";
test("web-probe help promotes reusable Workbench debug and product Trace commands", () => {
const help = hwlabNodeWebProbeHelp();
@@ -21,5 +22,18 @@ test("web-probe screenshot scoped help explains semantic, custom and local URL u
assert.match(usage, /--url 'https:\/\/custom\.example\/workbench'/u);
assert.match(usage, /--url 'http:\/\/127\.0\.0\.1:4173\/workbench'/u);
assert.match(notes, /--url.* --path/u);
assert.match(notes, / SSE.*domcontentloaded/u);
assert.equal(help.mutation, false);
});
test("web-probe screenshot defaults to DOM readiness and keeps network idle explicit", () => {
const defaults = parseNodeWebProbeOptions(["screenshot", "--node", "NC01", "--lane", "v03", "--origin", "native"]);
assert.equal(defaults.action, "screenshot");
if (defaults.action !== "screenshot") throw new Error("expected screenshot options");
assert.equal(defaults.waitUntil, "domcontentloaded");
const explicit = parseNodeWebProbeOptions(["screenshot", "--node", "NC01", "--lane", "v03", "--origin", "native", "--wait-until", "networkidle"]);
assert.equal(explicit.action, "screenshot");
if (explicit.action !== "screenshot") throw new Error("expected screenshot options");
assert.equal(explicit.waitUntil, "networkidle");
});
+1 -1
View File
@@ -1105,7 +1105,7 @@ const screenshotPath = process.env.UNIDESK_WEB_PROBE_SCREENSHOT_PATH;
const width = Number(process.env.UNIDESK_WEB_PROBE_SCREENSHOT_WIDTH || 1440);
const height = Number(process.env.UNIDESK_WEB_PROBE_SCREENSHOT_HEIGHT || 900);
const timeout = Number(process.env.UNIDESK_WEB_PROBE_SCREENSHOT_TIMEOUT_MS || 30000);
const waitUntil = process.env.UNIDESK_WEB_PROBE_SCREENSHOT_WAIT_UNTIL || "networkidle";
const waitUntil = process.env.UNIDESK_WEB_PROBE_SCREENSHOT_WAIT_UNTIL || "domcontentloaded";
const fullPage = process.env.UNIDESK_WEB_PROBE_SCREENSHOT_FULL_PAGE === "1";
const selector = process.env.UNIDESK_WEB_PROBE_SCREENSHOT_SELECTOR || "";
const executablePath = process.env.UNIDESK_WEB_PROBE_SCREENSHOT_EXECUTABLE_PATH || "";
+1 -1
View File
@@ -2296,7 +2296,7 @@ export function parseNodeWebProbeOptions(args: string[]): NodeWebProbeOptions {
localDir: optionValue(args, "--local-dir") ?? "/tmp",
name: parseWebProbeScreenshotName(optionValue(args, "--name") ?? `web-probe-${node.toLowerCase()}-${lane}.png`),
timeoutMs,
waitUntil: parseWebProbeScreenshotWaitUntil(optionValue(args, "--wait-until") ?? "networkidle"),
waitUntil: parseWebProbeScreenshotWaitUntil(optionValue(args, "--wait-until") ?? "domcontentloaded"),
fullPage: args.includes("--full-page") && !args.includes("--no-full-page"),
selector: optionValue(args, "--selector") ?? null,
keepRemote: args.includes("--keep-remote"),