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:
@@ -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: [] };
|
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, {
|
addCheck(checks, blockers, "live-code-agent-browser-journey", journey.status, journey.summary, {
|
||||||
blocker: journey.status === "pass" ? null : "runtime_blocker",
|
blocker: journey.status === "pass" ? null : "runtime_blocker",
|
||||||
@@ -1467,7 +1483,7 @@ async function inspectLiveDom(url) {
|
|||||||
browser = await chromium.launch({ headless: true });
|
browser = await chromium.launch({ headless: true });
|
||||||
const page = await browser.newPage({ viewport: { width: 1366, height: 768 } });
|
const page = await browser.newPage({ viewport: { width: 1366, height: 768 } });
|
||||||
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 8000 });
|
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 workspace = document.querySelector('[data-view="workspace"]');
|
||||||
const gate = document.querySelector('[data-view="gate"]');
|
const gate = document.querySelector('[data-view="gate"]');
|
||||||
const help = document.querySelector('[data-view="help"]');
|
const help = document.querySelector('[data-view="help"]');
|
||||||
@@ -1482,6 +1498,15 @@ async function inspectLiveDom(url) {
|
|||||||
const box = element.getBoundingClientRect();
|
const box = element.getBoundingClientRect();
|
||||||
return style.visibility !== "hidden" && style.display !== "none" && box.width > 0 && box.height > 0;
|
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 {
|
return {
|
||||||
title: document.title,
|
title: document.title,
|
||||||
bodyOverflow: bodyStyle.overflow,
|
bodyOverflow: bodyStyle.overflow,
|
||||||
@@ -1491,6 +1516,7 @@ async function inspectLiveDom(url) {
|
|||||||
helpHidden: help ? help.hidden : null,
|
helpHidden: help ? help.hidden : null,
|
||||||
diagnosticsHidden: diagnostics ? diagnostics.hidden : null,
|
diagnosticsHidden: diagnostics ? diagnostics.hidden : null,
|
||||||
outerScrollLocked: document.documentElement.scrollHeight <= document.documentElement.clientHeight + 2,
|
outerScrollLocked: document.documentElement.scrollHeight <= document.documentElement.clientHeight + 2,
|
||||||
|
rootAfterScrollAttempt,
|
||||||
labelsPresent: ["硬件资源", "Agent 对话", "工作清单", "可信记录", "使用说明"].every((label) => text.includes(label)),
|
labelsPresent: ["硬件资源", "Agent 对话", "工作清单", "可信记录", "使用说明"].every((label) => text.includes(label)),
|
||||||
coreControlsVisible: {
|
coreControlsVisible: {
|
||||||
commandInput: visible("#command-input"),
|
commandInput: visible("#command-input"),
|
||||||
@@ -1512,6 +1538,9 @@ async function inspectLiveDom(url) {
|
|||||||
(dom.helpHidden === true || dom.helpHidden === null) &&
|
(dom.helpHidden === true || dom.helpHidden === null) &&
|
||||||
(dom.diagnosticsHidden === true || dom.diagnosticsHidden === null) &&
|
(dom.diagnosticsHidden === true || dom.diagnosticsHidden === null) &&
|
||||||
dom.outerScrollLocked &&
|
dom.outerScrollLocked &&
|
||||||
|
dom.rootAfterScrollAttempt.windowScrollY === 0 &&
|
||||||
|
dom.rootAfterScrollAttempt.htmlScrollTop === 0 &&
|
||||||
|
dom.rootAfterScrollAttempt.bodyScrollTop === 0 &&
|
||||||
dom.labelsPresent &&
|
dom.labelsPresent &&
|
||||||
Object.values(dom.coreControlsVisible).every(Boolean);
|
Object.values(dom.coreControlsVisible).every(Boolean);
|
||||||
return {
|
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) {
|
async function inspectLiveUserJourney(url) {
|
||||||
let chromium;
|
let chromium;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -60,21 +60,27 @@ const requiredTrustedRecordTerms = Object.freeze([
|
|||||||
]);
|
]);
|
||||||
const workbenchSmoke = runDevCloudWorkbenchStaticSmoke();
|
const workbenchSmoke = runDevCloudWorkbenchStaticSmoke();
|
||||||
const helpSmokeCheck = workbenchSmoke.checks.find((check) => check.id === "help-md-contract");
|
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 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 conversationUxSmokeCheck = workbenchSmoke.checks.find((check) => check.id === "code-agent-conversation-ux-states");
|
||||||
const mobileWorkbenchSmoke = await runDevCloudWorkbenchMobileSmoke();
|
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();
|
const localAgentFixtureSmoke = await runDevCloudWorkbenchLocalAgentFixtureSmoke();
|
||||||
|
|
||||||
assert.equal(workbenchSmoke.status, "pass", JSON.stringify(workbenchSmoke.blockers, null, 2));
|
assert.equal(workbenchSmoke.status, "pass", JSON.stringify(workbenchSmoke.blockers, null, 2));
|
||||||
assert.equal(workbenchSmoke.evidenceLevel, "SOURCE");
|
assert.equal(workbenchSmoke.evidenceLevel, "SOURCE");
|
||||||
assert.equal(workbenchSmoke.devLive, false);
|
assert.equal(workbenchSmoke.devLive, false);
|
||||||
assert.equal(helpSmokeCheck?.status, "pass", "PR #114 help Markdown route must be present and ready");
|
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(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(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.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.notEqual(mobileWorkbenchSmoke.status, "blocked", JSON.stringify(mobileWorkbenchSmoke.blockers, null, 2));
|
||||||
assert.equal(mobileWorkbenchSmoke.evidenceLevel, "SOURCE");
|
assert.equal(mobileWorkbenchSmoke.evidenceLevel, "SOURCE");
|
||||||
assert.equal(mobileWorkbenchSmoke.devLive, false);
|
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.status, "pass", JSON.stringify(localAgentFixtureSmoke.blockers, null, 2));
|
||||||
assert.equal(localAgentFixtureSmoke.evidenceLevel, "SOURCE");
|
assert.equal(localAgentFixtureSmoke.evidenceLevel, "SOURCE");
|
||||||
assert.equal(localAgentFixtureSmoke.devLive, false);
|
assert.equal(localAgentFixtureSmoke.devLive, false);
|
||||||
|
|||||||
Reference in New Issue
Block a user