test: tighten workbench scroll and help smoke

Host closeout: reviewed diff, runner validation, and clean merge state. This is SOURCE/local browser smoke hardening for workbench scroll/help behavior only; no deploy, no secret access, and no M3/M4/M5 acceptance claim.
This commit is contained in:
Lyon
2026-05-23 10:25:39 +08:00
committed by GitHub
2 changed files with 81 additions and 1 deletions
+75 -1
View File
@@ -451,6 +451,22 @@ async function runLiveSmoke(args) {
});
}
const help = http.ok ? await inspectLiveHelpRoute(args.url) : { status: "skip", summary: "Browser Markdown help check skipped because HTTP fetch failed.", evidence: [] };
addCheck(checks, blockers, "live-help-markdown-route", help.status, help.summary, {
blocker: help.status === "pass" ? null : "runtime_blocker",
evidence: help.evidence,
observations: help.observations
});
if (help.status === "skip") {
blockers.push({
type: "observability_blocker",
scope: "live-help-markdown-route",
status: "open",
summary: help.summary
});
}
const journey = http.ok ? await inspectLiveUserJourney(args.url) : { status: "skip", summary: "Browser Code Agent journey skipped because HTTP fetch failed.", evidence: [] };
addCheck(checks, blockers, "live-code-agent-browser-journey", journey.status, journey.summary, {
blocker: journey.status === "pass" ? null : "runtime_blocker",
@@ -1467,7 +1483,7 @@ async function inspectLiveDom(url) {
browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1366, height: 768 } });
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 8000 });
const dom = await page.evaluate(() => {
const dom = await page.evaluate(async () => {
const workspace = document.querySelector('[data-view="workspace"]');
const gate = document.querySelector('[data-view="gate"]');
const help = document.querySelector('[data-view="help"]');
@@ -1482,6 +1498,15 @@ async function inspectLiveDom(url) {
const box = element.getBoundingClientRect();
return style.visibility !== "hidden" && style.display !== "none" && box.width > 0 && box.height > 0;
};
window.scrollTo(0, 240);
document.documentElement.scrollTop = 240;
document.body.scrollTop = 240;
await new Promise((resolve) => requestAnimationFrame(resolve));
const rootAfterScrollAttempt = {
windowScrollY: window.scrollY,
htmlScrollTop: document.documentElement.scrollTop,
bodyScrollTop: document.body.scrollTop
};
return {
title: document.title,
bodyOverflow: bodyStyle.overflow,
@@ -1491,6 +1516,7 @@ async function inspectLiveDom(url) {
helpHidden: help ? help.hidden : null,
diagnosticsHidden: diagnostics ? diagnostics.hidden : null,
outerScrollLocked: document.documentElement.scrollHeight <= document.documentElement.clientHeight + 2,
rootAfterScrollAttempt,
labelsPresent: ["硬件资源", "Agent 对话", "工作清单", "可信记录", "使用说明"].every((label) => text.includes(label)),
coreControlsVisible: {
commandInput: visible("#command-input"),
@@ -1512,6 +1538,9 @@ async function inspectLiveDom(url) {
(dom.helpHidden === true || dom.helpHidden === null) &&
(dom.diagnosticsHidden === true || dom.diagnosticsHidden === null) &&
dom.outerScrollLocked &&
dom.rootAfterScrollAttempt.windowScrollY === 0 &&
dom.rootAfterScrollAttempt.htmlScrollTop === 0 &&
dom.rootAfterScrollAttempt.bodyScrollTop === 0 &&
dom.labelsPresent &&
Object.values(dom.coreControlsVisible).every(Boolean);
return {
@@ -1531,6 +1560,51 @@ async function inspectLiveDom(url) {
}
}
async function inspectLiveHelpRoute(url) {
let chromium;
try {
({ chromium } = await import("playwright"));
} catch (error) {
return {
status: "skip",
summary: `Browser Markdown help check skipped because Playwright is unavailable: ${error.message}`,
evidence: ["playwright import failed"]
};
}
let browser;
try {
browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1366, height: 768 } });
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 12000 });
await page.locator('[data-route="help"]').click();
await page.waitForFunction(() => document.querySelector("#help-content")?.dataset.helpState === "ready", null, { timeout: 8000 });
const help = await inspectHelpMarkdownRoute(page);
const pass = help.nonDefaultMarkdownHelp && help.termsPresent;
return {
status: pass ? "pass" : "blocked",
summary: pass
? "Desktop browser help route remains non-default, markdown-rendered, and scrollable."
: "Desktop browser help route did not satisfy the markdown workbench contract.",
evidence: [
`hash=${help.hash ?? "unknown"}`,
`heading=${help.heading ?? "unknown"}`,
`rootStillLocked=${help.rootStillLocked}`,
`helpPanelScrolls=${help.helpPanelScrolls}`
],
observations: help
};
} catch (error) {
return {
status: "blocked",
summary: `Desktop browser help route failed: ${error.message}`,
evidence: ["browser navigation or markdown render failed"]
};
} finally {
if (browser) await browser.close();
}
}
async function inspectLiveUserJourney(url) {
let chromium;
try {
+6
View File
@@ -60,21 +60,27 @@ const requiredTrustedRecordTerms = Object.freeze([
]);
const workbenchSmoke = runDevCloudWorkbenchStaticSmoke();
const helpSmokeCheck = workbenchSmoke.checks.find((check) => check.id === "help-md-contract");
const outerScrollSmokeCheck = workbenchSmoke.checks.find((check) => check.id === "outer-scroll-contract");
const mobileLayoutSmokeCheck = workbenchSmoke.checks.find((check) => check.id === "mobile-workbench-layout-contract");
const conversationUxSmokeCheck = workbenchSmoke.checks.find((check) => check.id === "code-agent-conversation-ux-states");
const mobileWorkbenchSmoke = await runDevCloudWorkbenchMobileSmoke();
const mobileOuterScrollSmokeCheck = mobileWorkbenchSmoke.checks.find((check) => check.id === "mobile-outer-scroll-lock");
const mobileHelpSmokeCheck = mobileWorkbenchSmoke.checks.find((check) => check.id === "mobile-help-markdown-route");
const localAgentFixtureSmoke = await runDevCloudWorkbenchLocalAgentFixtureSmoke();
assert.equal(workbenchSmoke.status, "pass", JSON.stringify(workbenchSmoke.blockers, null, 2));
assert.equal(workbenchSmoke.evidenceLevel, "SOURCE");
assert.equal(workbenchSmoke.devLive, false);
assert.equal(helpSmokeCheck?.status, "pass", "PR #114 help Markdown route must be present and ready");
assert.equal(outerScrollSmokeCheck?.status, "pass", "desktop workbench shell must lock outer page scrolling");
assert.equal(mobileLayoutSmokeCheck?.status, "pass", "mobile 390x844 workbench layout contract must be present");
assert.equal(conversationUxSmokeCheck?.status, "pass", "Code Agent conversation UX states must remain distinct");
assert.equal(workbenchSmoke.help.status, "pass", "smoke report must not leave #114 help contract pending");
assert.notEqual(mobileWorkbenchSmoke.status, "blocked", JSON.stringify(mobileWorkbenchSmoke.blockers, null, 2));
assert.equal(mobileWorkbenchSmoke.evidenceLevel, "SOURCE");
assert.equal(mobileWorkbenchSmoke.devLive, false);
assert.equal(mobileOuterScrollSmokeCheck?.status, "pass", "mobile smoke must prove outer page scroll remains locked");
assert.equal(mobileHelpSmokeCheck?.status, "pass", "mobile help route must remain non-default Markdown content");
assert.equal(localAgentFixtureSmoke.status, "pass", JSON.stringify(localAgentFixtureSmoke.blockers, null, 2));
assert.equal(localAgentFixtureSmoke.evidenceLevel, "SOURCE");
assert.equal(localAgentFixtureSmoke.devLive, false);