|
|
|
@@ -64,6 +64,7 @@ const diagnosticsRequiredTerms = Object.freeze([
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const gateRouteAliases = Object.freeze(["/gate", "/diagnostics/gate"]);
|
|
|
|
|
const helpRouteAliases = Object.freeze(["/help"]);
|
|
|
|
|
|
|
|
|
|
const incompletePrimaryNavLabels = Object.freeze(["台", "证", "诊", "帮"]);
|
|
|
|
|
|
|
|
|
@@ -253,6 +254,11 @@ function runStaticSmoke() {
|
|
|
|
|
evidence: gateRouteAliases
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
addCheck(checks, blockers, "direct-help-route-alias", helpRouteAliasesAreServed(files.app, artifactPublisher, buildScript, distContractScript), "/help is a direct user-facing help alias and does not become the default route.", {
|
|
|
|
|
blocker: "runtime_blocker",
|
|
|
|
|
evidence: [...helpRouteAliases, "routeFromLocation final fallback is workspace"]
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
addCheck(checks, blockers, "feedback-120-wiring-table", wiringTableContract(files.html), "Patch-panel wiring panel is a table with source, target, status, evidence source, and trace/evidence columns.", {
|
|
|
|
|
blocker: "contract_blocker",
|
|
|
|
|
evidence: requiredWiringColumns
|
|
|
|
@@ -966,6 +972,19 @@ function gateRouteAliasesAreServed(app, artifactPublisher, buildScript, distCont
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function helpRouteAliasesAreServed(app, artifactPublisher, buildScript, distContractScript) {
|
|
|
|
|
const routeBody = functionBody(app, "routeFromLocation");
|
|
|
|
|
return (
|
|
|
|
|
/helpPathnames\(\)\.has/u.test(routeBody) &&
|
|
|
|
|
helpRouteAliases.every((route) => app.includes(`"${route}"`)) &&
|
|
|
|
|
helpRouteAliases.every((route) => artifactPublisher.includes(`routePath === "${route}"`)) &&
|
|
|
|
|
/buildCloudWebDist/u.test(buildScript) &&
|
|
|
|
|
/help\/index\.html/u.test(distContractScript) &&
|
|
|
|
|
/return "help"/u.test(routeBody) &&
|
|
|
|
|
finalRouteFallback(app) === "workspace"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function wiringTableContract(html) {
|
|
|
|
|
const wiringPanel = html.match(/<section\b[^>]*\bdata-side-panel=["']wiring["'][\s\S]*?<\/section>/u)?.[0] ?? "";
|
|
|
|
|
return requiredWiringColumns.every((column) => wiringPanel.includes(`<th>${column}</th>`));
|
|
|
|
@@ -1321,7 +1340,7 @@ function inspectHelpRoute(html, app) {
|
|
|
|
|
/data-route=["']help["']/u.test(html) ||
|
|
|
|
|
/data-view=["']help["']/u.test(html) ||
|
|
|
|
|
/#help\b/u.test(html + app) ||
|
|
|
|
|
/pathname[\s\S]{0,160}\/help/u.test(app);
|
|
|
|
|
/pathname[\s\S]{0,220}\/help/u.test(app);
|
|
|
|
|
const finalFallback = finalRouteFallback(app);
|
|
|
|
|
const helpViewHidden = helpViewTag ? /\bhidden\b/u.test(helpViewTag) : false;
|
|
|
|
|
return {
|
|
|
|
@@ -1983,6 +2002,12 @@ export async function runDevCloudWorkbenchMobileSmoke() {
|
|
|
|
|
await page.click('[data-route="help"]');
|
|
|
|
|
await page.waitForFunction(() => document.querySelector("#help-content")?.dataset.helpState === "ready", null, { timeout: 8000 });
|
|
|
|
|
const help = await inspectHelpMarkdownRoute(page);
|
|
|
|
|
await page.goto(new URL("/#/help", server.url).toString(), { waitUntil: "networkidle", timeout: 15000 });
|
|
|
|
|
await page.waitForFunction(() => document.querySelector("#help-content")?.dataset.helpState === "ready", null, { timeout: 8000 });
|
|
|
|
|
const slashHashHelp = await inspectHelpMarkdownRoute(page);
|
|
|
|
|
await page.goto(new URL("/help", server.url).toString(), { waitUntil: "networkidle", timeout: 15000 });
|
|
|
|
|
await page.waitForFunction(() => document.querySelector("#help-content")?.dataset.helpState === "ready", null, { timeout: 8000 });
|
|
|
|
|
const directHelp = await inspectHelpMarkdownRoute(page);
|
|
|
|
|
await page.click('[data-route="workspace"]');
|
|
|
|
|
await page.waitForFunction(() => document.querySelector('[data-view="workspace"]')?.hidden === false, null, { timeout: 8000 });
|
|
|
|
|
await page.click("#explorer-toggle");
|
|
|
|
@@ -2018,10 +2043,22 @@ export async function runDevCloudWorkbenchMobileSmoke() {
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: "mobile-help-markdown-route",
|
|
|
|
|
status: help.nonDefaultMarkdownHelp && help.termsPresent ? "pass" : "blocked",
|
|
|
|
|
summary: "Help opens as a non-default internal route rendered from help.md by the vendored Markdown renderer.",
|
|
|
|
|
status: help.nonDefaultMarkdownHelp && help.routeIsHashHelp && help.termsPresent ? "pass" : "blocked",
|
|
|
|
|
summary: "Help opens from the rail as a non-default hash route rendered from help.md by the vendored Markdown renderer.",
|
|
|
|
|
observations: help
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: "mobile-slash-hash-help-route",
|
|
|
|
|
status: slashHashHelp.nonDefaultMarkdownHelp && slashHashHelp.routeIsSlashHashHelp && slashHashHelp.termsPresent ? "pass" : "blocked",
|
|
|
|
|
summary: "Direct #/help opens the user-facing help view.",
|
|
|
|
|
observations: slashHashHelp
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: "mobile-direct-help-route",
|
|
|
|
|
status: directHelp.nonDefaultMarkdownHelp && directHelp.routeIsDirectHelp && directHelp.termsPresent ? "pass" : "blocked",
|
|
|
|
|
summary: "Direct /help opens the user-facing help view instead of raw API 404 JSON.",
|
|
|
|
|
observations: directHelp
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: "mobile-default-hit-test",
|
|
|
|
|
status: closed.primaryControlsReachable ? "pass" : "blocked",
|
|
|
|
@@ -2109,7 +2146,7 @@ async function startStaticWebServer(options = {}) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let pathname = decodeURIComponent(url.pathname);
|
|
|
|
|
if (pathname === "/" || pathname === "/workbench" || pathname === "/gate" || pathname === "/diagnostics/gate") {
|
|
|
|
|
if (pathname === "/" || pathname === "/workbench" || pathname === "/gate" || pathname === "/diagnostics/gate" || pathname === "/help") {
|
|
|
|
|
pathname = "/index.html";
|
|
|
|
|
}
|
|
|
|
|
const filePath = path.resolve(webRoot, pathname.replace(/^\/+/, ""));
|
|
|
|
@@ -2490,6 +2527,7 @@ async function inspectHelpMarkdownRoute(page) {
|
|
|
|
|
document.body.scrollHeight <= document.body.clientHeight + 2;
|
|
|
|
|
return {
|
|
|
|
|
hash: window.location.hash,
|
|
|
|
|
pathname: window.location.pathname,
|
|
|
|
|
helpState: helpContent?.dataset.helpState ?? null,
|
|
|
|
|
workspaceHidden: workspace ? workspace.hidden : null,
|
|
|
|
|
gateHidden: gate ? gate.hidden : null,
|
|
|
|
@@ -2504,8 +2542,11 @@ async function inspectHelpMarkdownRoute(page) {
|
|
|
|
|
helpPanelScrolls: Boolean(helpScroll && helpScroll.scrollHeight > helpScroll.clientHeight && helpScroll.after > helpScroll.before),
|
|
|
|
|
rootStillLocked,
|
|
|
|
|
helpScroll,
|
|
|
|
|
routeIsHashHelp: window.location.hash === "#help",
|
|
|
|
|
routeIsSlashHashHelp: window.location.hash === "#/help",
|
|
|
|
|
routeIsDirectHelp: (window.location.pathname.replace(/\/+$/, "") || "/") === "/help",
|
|
|
|
|
nonDefaultMarkdownHelp:
|
|
|
|
|
window.location.hash === "#help" &&
|
|
|
|
|
(window.location.hash === "#help" || window.location.hash === "#/help" || (window.location.pathname.replace(/\/+$/, "") || "/") === "/help") &&
|
|
|
|
|
workspace?.hidden === true &&
|
|
|
|
|
gate?.hidden === true &&
|
|
|
|
|
help?.hidden === false &&
|
|
|
|
|