test: guard resource explorer removal
This commit is contained in:
@@ -157,6 +157,55 @@ const helpRouteAliases = Object.freeze(["/help"]);
|
||||
|
||||
const incompletePrimaryNavLabels = Object.freeze(["台", "证", "诊", "帮"]);
|
||||
|
||||
const removedResourceExplorerSourceTerms = Object.freeze([
|
||||
"resource-explorer",
|
||||
"explorer-toggle",
|
||||
"explorer-resize",
|
||||
"resource-tree",
|
||||
"explorer-capabilities",
|
||||
"capability-count",
|
||||
"tree-count",
|
||||
"data-focus-command",
|
||||
"quick-actions",
|
||||
"tree-panel",
|
||||
"explorer-collapsed",
|
||||
"--explorer-width",
|
||||
"--explorer-min-width",
|
||||
"--explorer-max-width"
|
||||
]);
|
||||
|
||||
const removedResourceExplorerDomSelectors = Object.freeze([
|
||||
"aside#resource-explorer",
|
||||
"#resource-explorer",
|
||||
"#explorer-toggle",
|
||||
"#explorer-resize",
|
||||
"#resource-tree",
|
||||
".resource-tree",
|
||||
"#explorer-capabilities",
|
||||
".explorer-capabilities",
|
||||
"#capability-count",
|
||||
"#tree-count",
|
||||
"[data-focus-command]",
|
||||
".quick-actions",
|
||||
".tree-panel",
|
||||
".explorer-collapsed"
|
||||
]);
|
||||
|
||||
const removedResourceExplorerCopyTerms = Object.freeze([
|
||||
"资源浏览与硬件资源树",
|
||||
"资源浏览",
|
||||
"硬件资源树",
|
||||
"只读工作区",
|
||||
"常用能力",
|
||||
"收起资源树",
|
||||
"展开资源树",
|
||||
"拖拽调整左侧资源树宽度",
|
||||
"资源查看",
|
||||
"查看接线",
|
||||
"查看状态",
|
||||
"编写任务"
|
||||
]);
|
||||
|
||||
const requiredWiringLongTableHeaders = Object.freeze(["res_boxsimu_1", "res_boxsimu_2"]);
|
||||
const forbiddenLegacyWiringColumns = Object.freeze([
|
||||
"源设备",
|
||||
@@ -507,7 +556,7 @@ function runStaticSmoke() {
|
||||
"aside#resource-explorer absent",
|
||||
"#explorer-resize absent",
|
||||
"resource tree / quick actions / capability cards absent",
|
||||
"right side keeps a 560-740px M3 status workspace boundary through --right-width"
|
||||
"right side keeps a 560-760px M3 status workspace boundary through --right-width"
|
||||
]
|
||||
});
|
||||
|
||||
@@ -1052,6 +1101,12 @@ export async function runDevCloudWorkbenchLayoutSmoke(args = {}) {
|
||||
summary: "Mobile 390x844 default layout has no resource drawer and preserves Agent input plus M3 tabs/controls.",
|
||||
observations: mobile.default
|
||||
},
|
||||
{
|
||||
id: "layout-feedback-352-resource-explorer-removed",
|
||||
status: allViewportCoverage(viewportResults, "resourceExplorerRemovalGuard") ? "pass" : "blocked",
|
||||
summary: "#352 default workbench has no aside#resource-explorer, #explorer-resize, resource tree/capability copy, or reclaimed left panel across desktop and mobile.",
|
||||
observations: summarizeResourceExplorerRemovalCoverage(viewportResults)
|
||||
},
|
||||
{
|
||||
id: "layout-right-sidebar-resize-desktop",
|
||||
status: desktop.rightResize.pass ? "pass" : "blocked",
|
||||
@@ -1177,7 +1232,7 @@ export async function runDevCloudWorkbenchLayoutSmoke(args = {}) {
|
||||
summary: useLiveUrl
|
||||
? "Live browser layout smoke verifies workbench layout, hit targets, overflow, /gate usability, and the two-column wiring panel only; it is not M3 hardware acceptance."
|
||||
: "Static local browser layout smoke verifies workbench layout, hit targets, overflow, /gate usability, and the two-column wiring panel only; deployment still requires DEV live verification.",
|
||||
refs: ["pikasTech/HWLAB#273", "pikasTech/HWLAB#276", "pikasTech/HWLAB#278", "pikasTech/HWLAB#287", "pikasTech/HWLAB#288", "pikasTech/HWLAB#99", "pikasTech/HWLAB#227"],
|
||||
refs: ["pikasTech/HWLAB#273", "pikasTech/HWLAB#276", "pikasTech/HWLAB#278", "pikasTech/HWLAB#287", "pikasTech/HWLAB#288", "pikasTech/HWLAB#352", "pikasTech/HWLAB#99", "pikasTech/HWLAB#227"],
|
||||
viewports: layoutViewports.map(({ id, width, height }) => ({ id, width, height })),
|
||||
checks,
|
||||
blockers,
|
||||
@@ -1351,7 +1406,7 @@ function layoutSourceContract() {
|
||||
"docs/reference/cloud-workbench.md",
|
||||
"docs/reference/code-agent-chat-readiness.md"
|
||||
],
|
||||
summary: "Cloud Workbench layout smoke protects the #99 workbench route, #227 visible M3 control area, Code Agent input, right hardware/trusted-record containers, /gate current route, and outer-scroll lock without claiming hardware acceptance."
|
||||
summary: "Cloud Workbench layout smoke protects the #99 workbench route, #227 visible M3 control area, #352 resource-explorer removal, Code Agent input, right hardware/trusted-record containers, /gate current route, and outer-scroll lock without claiming hardware acceptance."
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2157,34 +2212,8 @@ function hasMobileWorkbenchLayoutContract({ html, app, styles }) {
|
||||
|
||||
function hasResourceExplorerRemovalContract({ html, app, styles }) {
|
||||
const source = `${html}\n${app}\n${styles}`;
|
||||
const removedSelectorsAbsent = [
|
||||
"resource-explorer",
|
||||
"explorer-toggle",
|
||||
"explorer-resize",
|
||||
"resource-tree",
|
||||
"explorer-capabilities",
|
||||
"capability-count",
|
||||
"tree-count",
|
||||
"data-focus-command",
|
||||
"quick-actions",
|
||||
"tree-panel",
|
||||
"explorer-collapsed",
|
||||
"--explorer-width",
|
||||
"--explorer-min-width",
|
||||
"--explorer-max-width"
|
||||
].every((term) => !source.includes(term));
|
||||
const removedTextAbsent = [
|
||||
"资源浏览与硬件资源树",
|
||||
"只读工作区",
|
||||
"常用能力",
|
||||
"收起资源树",
|
||||
"展开资源树",
|
||||
"拖拽调整左侧资源树宽度",
|
||||
"资源查看",
|
||||
"查看接线",
|
||||
"查看状态",
|
||||
"编写任务"
|
||||
].every((term) => !source.includes(term));
|
||||
const removedSelectorsAbsent = removedResourceExplorerSourceTerms.every((term) => !source.includes(term));
|
||||
const removedTextAbsent = removedResourceExplorerCopyTerms.every((term) => !source.includes(term));
|
||||
return (
|
||||
removedSelectorsAbsent &&
|
||||
removedTextAbsent &&
|
||||
@@ -5778,7 +5807,7 @@ async function inspectRightSidebarResizeDisabled(page, { viewport }) {
|
||||
}
|
||||
|
||||
async function inspectLayoutState(page, { mode, viewport, compareTo }) {
|
||||
return page.evaluate(async ({ mode, viewport, compareTo }) => {
|
||||
return page.evaluate(async ({ mode, viewport, compareTo, resourceExplorerGuard }) => {
|
||||
const failures = [];
|
||||
const skip = [];
|
||||
const selectorLabels = [
|
||||
@@ -5968,6 +5997,21 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) {
|
||||
scrolls: element.scrollHeight > element.clientHeight ? element.scrollTop > before : true
|
||||
};
|
||||
};
|
||||
const visibleTextForElement = (root) => {
|
||||
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
||||
const parts = [];
|
||||
for (let node = walker.nextNode(); node; node = walker.nextNode()) {
|
||||
const parent = node.parentElement;
|
||||
if (!parent || parent.closest("[hidden], script, style, noscript")) continue;
|
||||
const style = getComputedStyle(parent);
|
||||
if (style.display === "none" || style.visibility === "hidden") continue;
|
||||
const box = parent.getBoundingClientRect();
|
||||
if (box.width <= 0 || box.height <= 0) continue;
|
||||
const text = node.textContent?.replace(/\s+/gu, " ").trim();
|
||||
if (text) parts.push(text);
|
||||
}
|
||||
return parts.join(" ").replace(/\s+/gu, " ").trim();
|
||||
};
|
||||
|
||||
window.scrollTo(0, 240);
|
||||
document.documentElement.scrollTop = 240;
|
||||
@@ -6252,23 +6296,22 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) {
|
||||
await new Promise((resolve) => requestAnimationFrame(resolve));
|
||||
}
|
||||
const removedSelectorStates = Object.fromEntries(
|
||||
[
|
||||
["#resource-explorer", "resourceExplorer"],
|
||||
["#explorer-resize", "explorerResize"],
|
||||
["#explorer-toggle", "explorerToggle"],
|
||||
["#resource-tree", "resourceTree"],
|
||||
[".quick-actions", "quickActions"]
|
||||
].map(([selector, key]) => [key, document.querySelector(selector) === null])
|
||||
resourceExplorerGuard.domSelectors.map((selector) => [selector, document.querySelector(selector) === null])
|
||||
);
|
||||
const removedSelectorsAbsent = Object.values(removedSelectorStates).every(Boolean);
|
||||
const visibleWorkbenchText = visibleTextForElement(document.body);
|
||||
const removedVisibleCopyHits = resourceExplorerGuard.copyTerms.filter((term) => visibleWorkbenchText.includes(term));
|
||||
const removedVisibleCopyAbsent = removedVisibleCopyHits.length === 0;
|
||||
const resourceExplorerRemovalGuard = removedSelectorsAbsent && removedVisibleCopyAbsent;
|
||||
const keyTargetsReachable = blockedKeyTargets.length === 0;
|
||||
if (!removedSelectorsAbsent) {
|
||||
if (!resourceExplorerRemovalGuard) {
|
||||
failures.push({
|
||||
failureType: "blocked/skip",
|
||||
selector: "#resource-explorer",
|
||||
selector: "#resource-explorer,#explorer-resize",
|
||||
viewport,
|
||||
summary: "Removed resource explorer selectors are still present in the default workbench DOM.",
|
||||
removedSelectorStates
|
||||
summary: "Removed resource explorer DOM or legacy copy returned in the default workbench.",
|
||||
removedSelectorStates,
|
||||
removedVisibleCopyHits
|
||||
});
|
||||
}
|
||||
if (!rootScrollLocked) {
|
||||
@@ -6324,7 +6367,7 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) {
|
||||
Object.values(noHorizontalOverflow).every(Boolean) &&
|
||||
rightWidthTarget &&
|
||||
keyTargetsReachable &&
|
||||
removedSelectorsAbsent &&
|
||||
resourceExplorerRemovalGuard &&
|
||||
sidePanelOverflowUsable;
|
||||
const passWithWiring =
|
||||
pass &&
|
||||
@@ -6339,6 +6382,9 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) {
|
||||
pass: passWithWiring,
|
||||
removedSelectorStates,
|
||||
removedSelectorsAbsent,
|
||||
removedVisibleCopyAbsent,
|
||||
removedVisibleCopyHits,
|
||||
resourceExplorerRemovalGuard,
|
||||
rootScrollLocked,
|
||||
rootAfterScrollAttempt,
|
||||
boxes,
|
||||
@@ -6383,7 +6429,15 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) {
|
||||
skip,
|
||||
failures
|
||||
};
|
||||
}, { mode, viewport, compareTo });
|
||||
}, {
|
||||
mode,
|
||||
viewport,
|
||||
compareTo,
|
||||
resourceExplorerGuard: {
|
||||
domSelectors: [...removedResourceExplorerDomSelectors],
|
||||
copyTerms: [...removedResourceExplorerCopyTerms]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function inspectGateLayoutState(page, { mode, viewport }) {
|
||||
@@ -6644,6 +6698,44 @@ function allViewportCoverage(viewportResults, fieldName) {
|
||||
);
|
||||
}
|
||||
|
||||
function summarizeResourceExplorerRemovalCoverage(viewportResults) {
|
||||
const coverageEntries = Object.entries(viewportResults).map(([id, result]) => {
|
||||
const observation = result.default;
|
||||
return [
|
||||
id,
|
||||
{
|
||||
viewport: observation?.viewport ?? null,
|
||||
covered: Boolean(observation?.resourceExplorerRemovalGuard),
|
||||
removedSelectorsAbsent: observation?.removedSelectorsAbsent === true,
|
||||
removedVisibleCopyAbsent: observation?.removedVisibleCopyAbsent === true,
|
||||
removedVisibleCopyHits: observation?.removedVisibleCopyHits ?? [],
|
||||
removedSelectorStates: observation?.removedSelectorStates ?? {}
|
||||
}
|
||||
];
|
||||
});
|
||||
const coverage = Object.fromEntries(coverageEntries);
|
||||
const failures = coverageEntries
|
||||
.filter(([, item]) => !item.covered)
|
||||
.map(([id, item]) => ({
|
||||
checkId: "layout-feedback-352-resource-explorer-removed",
|
||||
viewport: item.viewport,
|
||||
selector: "#resource-explorer,#explorer-resize",
|
||||
failureType: "blocked/skip",
|
||||
summary: `#352 resource explorer removal guard failed in ${id} viewport.`,
|
||||
removedSelectorsAbsent: item.removedSelectorsAbsent,
|
||||
removedVisibleCopyAbsent: item.removedVisibleCopyAbsent,
|
||||
removedVisibleCopyHits: item.removedVisibleCopyHits,
|
||||
removedSelectorStates: item.removedSelectorStates
|
||||
}));
|
||||
return {
|
||||
status: failures.length === 0 ? "pass" : "blocked",
|
||||
forbiddenSelectors: [...removedResourceExplorerDomSelectors],
|
||||
forbiddenCopy: [...removedResourceExplorerCopyTerms],
|
||||
coverage,
|
||||
failures
|
||||
};
|
||||
}
|
||||
|
||||
function summarizeCoverageGap(viewportResults, issueKey) {
|
||||
const fieldName = {
|
||||
issue288: "issue288SingleTableReady",
|
||||
|
||||
Reference in New Issue
Block a user