fix: render patch panel wiring as long table
This commit is contained in:
@@ -200,6 +200,17 @@ test("source/default smoke covers #278 sidebar collapse static contract", () =>
|
||||
assert.equal(report.checks.find((check) => check.id === "feedback-278-sidebar-collapse-contract")?.status, "pass");
|
||||
});
|
||||
|
||||
test("source/default smoke covers #276 two-column wiring long-table contract", () => {
|
||||
const report = runDevCloudWorkbenchStaticSmoke();
|
||||
const check = report.checks.find((item) => item.id === "feedback-276-wiring-long-table");
|
||||
assert.equal(check?.status, "pass");
|
||||
assert.deepEqual(
|
||||
check.evidence.filter((item) => ["res_boxsimu_1", "res_boxsimu_2", "DO1 对 DI1"].includes(item)),
|
||||
["res_boxsimu_1", "res_boxsimu_2", "DO1 对 DI1"]
|
||||
);
|
||||
assert.equal(check.evidence.includes("legacy 8-column table forbidden"), true);
|
||||
});
|
||||
|
||||
test("live workbench identity passes only when runtime commit or image tag matches current source", () => {
|
||||
assert.equal(
|
||||
classifyLiveDeploymentIdentity(sourceIdentity, {
|
||||
@@ -503,11 +514,18 @@ test("layout smoke verifies desktop and mobile sidebar collapse geometry", async
|
||||
assert.equal(desktopCollapsed.toggle.text, "展开资源树");
|
||||
assert.equal(desktopCollapsed.collapsedWidthGain, true);
|
||||
assert.equal(desktopCollapsed.keyTargetsReachable, true);
|
||||
assert.equal(desktopCollapsed.wiring.longTableOk, true);
|
||||
assert.equal(desktopCollapsed.wiring.noHorizontalScroll, true);
|
||||
assert.equal(desktopCollapsed.wiring.headers.length, 2);
|
||||
assert.deepEqual(desktopCollapsed.wiring.legacyHeaderHits, []);
|
||||
assert.equal(desktopCollapsed.wiring.horizontalScroll.panelScrollWidth <= desktopCollapsed.wiring.horizontalScroll.panelClientWidth + 2, true);
|
||||
|
||||
const mobileCollapsed = report.checks.find((check) => check.id === "layout-mobile-collapsed")?.observations;
|
||||
assert.equal(mobileCollapsed.explorerCollapsed, true);
|
||||
assert.equal(mobileCollapsed.defaultCollapsedMobile, true);
|
||||
assert.equal(mobileCollapsed.keyTargetsReachable, true);
|
||||
assert.equal(mobileCollapsed.wiring.longTableOk, true);
|
||||
assert.equal(mobileCollapsed.wiring.noHorizontalScroll, true);
|
||||
|
||||
const desktopExpanded = report.checks.find((check) => check.id === "layout-desktop-expanded")?.observations;
|
||||
assert.equal(desktopExpanded.failures.length, 0);
|
||||
|
||||
@@ -102,7 +102,8 @@ const helpRouteAliases = Object.freeze(["/help"]);
|
||||
|
||||
const incompletePrimaryNavLabels = Object.freeze(["台", "证", "诊", "帮"]);
|
||||
|
||||
const requiredWiringColumns = Object.freeze([
|
||||
const requiredWiringLongTableHeaders = Object.freeze(["res_boxsimu_1", "res_boxsimu_2"]);
|
||||
const forbiddenLegacyWiringColumns = Object.freeze([
|
||||
"源设备",
|
||||
"源端口",
|
||||
"接线盘",
|
||||
@@ -112,6 +113,7 @@ const requiredWiringColumns = Object.freeze([
|
||||
"证据来源",
|
||||
"轨迹/证据"
|
||||
]);
|
||||
const requiredWiringSummaryTerms = Object.freeze(["hwlab-patch-panel", "状态", "证据来源", "轨迹/证据"]);
|
||||
|
||||
const requiredTrustedRecordTerms = Object.freeze([
|
||||
"Code Agent 对话记录",
|
||||
@@ -367,9 +369,15 @@ function runStaticSmoke() {
|
||||
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 轨迹/证据 columns.", {
|
||||
addCheck(checks, blockers, "feedback-276-wiring-long-table", wiringTableContract(files.html, files.styles, files.app), "Patch-panel wiring panel is a two-column long table: device headers first, IO mapping rows after, and metadata moved to Chinese summary/detail text.", {
|
||||
blocker: "contract_blocker",
|
||||
evidence: requiredWiringColumns
|
||||
evidence: [
|
||||
...requiredWiringLongTableHeaders,
|
||||
"DO1 对 DI1",
|
||||
"data-wiring-layout=\"two-column-long-table\"",
|
||||
"legacy 8-column table forbidden",
|
||||
...requiredWiringSummaryTerms
|
||||
]
|
||||
});
|
||||
|
||||
addCheck(checks, blockers, "trusted-record-groups", trustedRecordGroups(files), "Trusted Records panel groups Code Agent, wiring/operation, audit, and evidence summaries with source labels and live-failure fallback.", {
|
||||
@@ -1032,9 +1040,9 @@ export async function runDevCloudWorkbenchLayoutSmoke(args = {}) {
|
||||
evidenceLevel: useLiveUrl ? blockers.length === 0 ? "DEV-LIVE-LAYOUT" : "BLOCKED" : "SOURCE",
|
||||
devLive: false,
|
||||
summary: useLiveUrl
|
||||
? "Live browser layout smoke verifies workbench layout, hit targets, overflow, and /gate usability only; it is not M3 hardware acceptance."
|
||||
: "Static local browser layout smoke verifies workbench layout, hit targets, overflow, and /gate usability only; deployment still requires DEV live verification.",
|
||||
refs: ["pikasTech/HWLAB#273", "pikasTech/HWLAB#278", "pikasTech/HWLAB#287", "pikasTech/HWLAB#288", "pikasTech/HWLAB#99", "pikasTech/HWLAB#227"],
|
||||
? "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"],
|
||||
viewports: layoutViewports.map(({ id, width, height }) => ({ id, width, height })),
|
||||
checks,
|
||||
blockers,
|
||||
@@ -1192,7 +1200,8 @@ function baseReport({
|
||||
"pikasTech/HWLAB#131",
|
||||
"pikasTech/HWLAB#143",
|
||||
"pikasTech/HWLAB#164",
|
||||
"pikasTech/HWLAB#224"
|
||||
"pikasTech/HWLAB#224",
|
||||
"pikasTech/HWLAB#276"
|
||||
],
|
||||
mode,
|
||||
url,
|
||||
@@ -1609,8 +1618,7 @@ function defaultWorkspaceIsSanitized({ html, app }) {
|
||||
functionBody(app, "codeAgentControlSummary"),
|
||||
functionBody(app, "codeAgentBlockedSummary"),
|
||||
functionBody(app, "codeAgentAvailabilitySummary"),
|
||||
functionBody(app, "failureMessage"),
|
||||
functionBody(app, "renderWiringList")
|
||||
functionBody(app, "failureMessage")
|
||||
].join("\n");
|
||||
return (
|
||||
defaultHomepageForbiddenTerms.every((term) => !textHasForbiddenTerm(defaultShellText, term)) &&
|
||||
@@ -1694,9 +1702,31 @@ function helpRouteAliasesAreServed(app, artifactPublisher, buildScript, distCont
|
||||
);
|
||||
}
|
||||
|
||||
function wiringTableContract(html) {
|
||||
function wiringTableContract(html, styles = "", app = "") {
|
||||
const wiringPanel = html.match(/<section\b[^>]*\bdata-side-panel=["']wiring["'][\s\S]*?<\/section>/u)?.[0] ?? "";
|
||||
return requiredWiringColumns.every((column) => wiringPanel.includes(`<th>${column}</th>`));
|
||||
const headerCount = (wiringPanel.match(/<th\b/gu) ?? []).length;
|
||||
const bodyRow = wiringPanel.match(/<tr\b[^>]*\bdata-wiring-row=["']io["'][\s\S]*?<\/tr>/u)?.[0] ?? "";
|
||||
const bodyCellCount = (bodyRow.match(/<td\b/gu) ?? []).length;
|
||||
const renderWiringBody = functionBody(app, "renderWiringList");
|
||||
return (
|
||||
/data-wiring-layout=["']two-column-long-table["']/u.test(wiringPanel) &&
|
||||
/class=["'][^"']*\bwiring-long-table\b/u.test(wiringPanel) &&
|
||||
headerCount === 2 &&
|
||||
bodyCellCount === 2 &&
|
||||
requiredWiringLongTableHeaders.every((header) => wiringPanel.includes(header)) &&
|
||||
["DO1", "DI1"].every((port) => wiringPanel.includes(port)) &&
|
||||
requiredWiringSummaryTerms.every((term) => wiringPanel.includes(term)) &&
|
||||
forbiddenLegacyWiringColumns.every((column) => !wiringPanel.includes(`<th>${column}</th>`)) &&
|
||||
/id=["']wiring-summary["']/u.test(wiringPanel) &&
|
||||
/overflow-x:\s*hidden/u.test(styles.match(/\.wiring-table-wrap\s*\{[\s\S]*?\}/u)?.[0] ?? "") &&
|
||||
!/\.wiring-table\s*\{[\s\S]*?min-width:\s*9\d\dpx/u.test(styles) &&
|
||||
!/min-width:\s*980px/u.test(styles) &&
|
||||
/table-layout:\s*fixed/u.test(styles.match(/\.wiring-long-table\s*\{[\s\S]*?\}/u)?.[0] ?? "") &&
|
||||
/M3_TRUSTED_ROUTE\.fromResourceId/u.test(renderWiringBody) &&
|
||||
/M3_TRUSTED_ROUTE\.toResourceId/u.test(renderWiringBody) &&
|
||||
/M3_TRUSTED_ROUTE\.patchPanelServiceId/u.test(renderWiringBody) &&
|
||||
!/tr\.append\(cell\(M3_TRUSTED_ROUTE\.fromResourceId/u.test(renderWiringBody)
|
||||
);
|
||||
}
|
||||
|
||||
function hardwareStatusStructureContract({ html, app, styles }) {
|
||||
@@ -2488,10 +2518,20 @@ async function inspectLiveDom(url, options = {}) {
|
||||
),
|
||||
defaultBackstageHidden: !/(Gate|诊断|验收|BLOCKED|M0-M5|执行轨迹)/u.test(document.querySelector(".center-workspace")?.innerText ?? ""),
|
||||
gateRouteAvailable: [...document.querySelectorAll("[data-route='gate']")].some((button) => button.textContent?.trim() === "内部复核"),
|
||||
wiringHeaders: [...document.querySelectorAll(".wiring-table thead th")].map((cell) => cell.textContent?.trim() ?? ""),
|
||||
wiringLayout: document.querySelector(".wiring-table-wrap")?.getAttribute("data-wiring-layout") ?? "",
|
||||
wiringHeaderDevices: [
|
||||
document.querySelector("#wiring-source-device")?.textContent?.trim() ?? "",
|
||||
document.querySelector("#wiring-target-device")?.textContent?.trim() ?? ""
|
||||
],
|
||||
wiringHeaderCount: document.querySelectorAll(".wiring-table thead th").length,
|
||||
legacyWiringHeaders: [...document.querySelectorAll(".wiring-table thead th")].map((cell) => cell.textContent?.trim() ?? "").filter((text) =>
|
||||
["源设备", "源端口", "接线盘", "目标设备", "目标端口", "状态", "证据来源", "轨迹/证据"].includes(text)
|
||||
),
|
||||
m3WiringRows: [...document.querySelectorAll("#wiring-body tr")].map((row) =>
|
||||
[...row.querySelectorAll("td")].map((cell) => cell.textContent?.replace(/\s+/gu, " ").trim() ?? "")
|
||||
),
|
||||
wiringBodyCellCounts: [...document.querySelectorAll("#wiring-body tr")].map((row) => row.querySelectorAll("td").length),
|
||||
wiringSummaryText: document.querySelector("#wiring-summary")?.textContent?.replace(/\s+/gu, " ").trim() ?? "",
|
||||
coreControlsVisible: {
|
||||
commandInput: visible("#command-input"),
|
||||
commandSend: visible("#command-send"),
|
||||
@@ -2520,14 +2560,20 @@ async function inspectLiveDom(url, options = {}) {
|
||||
dom.navLabelsPresent &&
|
||||
dom.defaultBackstageHidden &&
|
||||
dom.gateRouteAvailable &&
|
||||
requiredWiringColumns.every((column) => dom.wiringHeaders.includes(column)) &&
|
||||
dom.wiringLayout === "two-column-long-table" &&
|
||||
dom.wiringHeaderCount === 2 &&
|
||||
dom.legacyWiringHeaders.length === 0 &&
|
||||
requiredWiringLongTableHeaders.every((header) => dom.wiringHeaderDevices.includes(header)) &&
|
||||
dom.wiringBodyCellCounts.every((count) => count === 2) &&
|
||||
dom.m3WiringRows.some((row) =>
|
||||
row.includes("res_boxsimu_1") &&
|
||||
row.includes("DO1") &&
|
||||
row.includes("hwlab-patch-panel") &&
|
||||
row.includes("res_boxsimu_2") &&
|
||||
row.includes("DI1")
|
||||
row.length === 2 &&
|
||||
row[0].includes("DO1") &&
|
||||
row[0].includes("hwlab-patch-panel") &&
|
||||
row[1].includes("DI1") &&
|
||||
row[1].includes("证据来源") &&
|
||||
row[1].includes("轨迹/证据")
|
||||
) &&
|
||||
requiredWiringSummaryTerms.every((term) => dom.wiringSummaryText.includes(term)) &&
|
||||
(postGuard ? postGuard.attempts.length === 0 : true) &&
|
||||
Object.values(dom.coreControlsVisible).every(Boolean);
|
||||
return {
|
||||
@@ -2539,6 +2585,9 @@ async function inspectLiveDom(url, options = {}) {
|
||||
`htmlOverflow=${dom.htmlOverflow}`,
|
||||
`firstViewportForbidden=${dom.firstViewportForbiddenPresent.join(",") || "none"}`,
|
||||
`gateRouteAvailable=${dom.gateRouteAvailable}`,
|
||||
`wiringLayout=${dom.wiringLayout}`,
|
||||
`wiringHeaderDevices=${dom.wiringHeaderDevices.join("|")}`,
|
||||
`wiringBodyCellCounts=${dom.wiringBodyCellCounts.join("|")}`,
|
||||
`m3WiringRows=${dom.m3WiringRows.length}`,
|
||||
...(postGuard ? [`codeAgentPostAttempts=${postGuard.attempts.length}`] : [])
|
||||
],
|
||||
@@ -4004,6 +4053,7 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) {
|
||||
[".hardware-status", ".side-workspace", "hardware status vs side workspace"],
|
||||
["#command-form", ".right-sidebar", "Code Agent command form vs right sidebar"]
|
||||
];
|
||||
const wiringLegacyHeaders = ["源设备", "源端口", "接线盘", "目标设备", "目标端口", "状态", "证据来源", "轨迹/证据"];
|
||||
const drawerSelectorLabels = [
|
||||
[".quick-actions button", "资源树快捷操作"],
|
||||
["#resource-tree summary", "资源树分组"],
|
||||
@@ -4309,6 +4359,75 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) {
|
||||
const overflowOk = overflowChecks.every((check) => check.ok);
|
||||
const sidePanelScroll = await scrollableProbe("#panel-control");
|
||||
const sidePanelOverflowUsable = sidePanelScroll.exists && (sidePanelScroll.scrolls || sidePanelScroll.overflowY !== "hidden");
|
||||
const wiringTab = document.querySelector("#tab-wiring");
|
||||
if (wiringTab?.getAttribute("aria-selected") !== "true") {
|
||||
wiringTab?.click();
|
||||
await new Promise((resolve) => requestAnimationFrame(resolve));
|
||||
}
|
||||
const wiringPanel = document.querySelector("#panel-wiring");
|
||||
const wiringWrap = document.querySelector(".wiring-table-wrap");
|
||||
const wiringTable = document.querySelector(".wiring-long-table");
|
||||
const wiringHeaders = [...document.querySelectorAll(".wiring-table thead th")].map((cell) => cell.textContent?.replace(/\s+/gu, " ").trim() ?? "");
|
||||
const wiringRows = [...document.querySelectorAll("#wiring-body tr")].map((row) =>
|
||||
[...row.querySelectorAll("td")].map((cell) => cell.textContent?.replace(/\s+/gu, " ").trim() ?? "")
|
||||
);
|
||||
const wiringLegacyHeaderHits = wiringHeaders.filter((header) => wiringLegacyHeaders.includes(header));
|
||||
const wiringHorizontalScroll = {
|
||||
panelClientWidth: wiringPanel?.clientWidth ?? 0,
|
||||
panelScrollWidth: wiringPanel?.scrollWidth ?? 0,
|
||||
wrapClientWidth: wiringWrap?.clientWidth ?? 0,
|
||||
wrapScrollWidth: wiringWrap?.scrollWidth ?? 0,
|
||||
tableClientWidth: wiringTable?.clientWidth ?? 0,
|
||||
tableScrollWidth: wiringTable?.scrollWidth ?? 0,
|
||||
panelOverflowX: wiringPanel ? getComputedStyle(wiringPanel).overflowX : "missing",
|
||||
wrapOverflowX: wiringWrap ? getComputedStyle(wiringWrap).overflowX : "missing"
|
||||
};
|
||||
const wiringNoHorizontalScroll =
|
||||
Boolean(wiringPanel && wiringWrap && wiringTable) &&
|
||||
wiringHorizontalScroll.panelScrollWidth <= wiringHorizontalScroll.panelClientWidth + 2 &&
|
||||
wiringHorizontalScroll.wrapScrollWidth <= wiringHorizontalScroll.wrapClientWidth + 2;
|
||||
const wiringLongTableOk =
|
||||
wiringWrap?.getAttribute("data-wiring-layout") === "two-column-long-table" &&
|
||||
wiringHeaders.length === 2 &&
|
||||
wiringHeaders.includes("res_boxsimu_1 互连设备 A") &&
|
||||
wiringHeaders.includes("res_boxsimu_2 互连设备 B") &&
|
||||
wiringLegacyHeaderHits.length === 0 &&
|
||||
wiringRows.some((row) =>
|
||||
row.length === 2 &&
|
||||
row[0].includes("DO1") &&
|
||||
row[0].includes("hwlab-patch-panel") &&
|
||||
row[1].includes("DI1") &&
|
||||
row[1].includes("证据来源") &&
|
||||
row[1].includes("轨迹/证据")
|
||||
);
|
||||
if (!wiringLongTableOk) {
|
||||
failures.push({
|
||||
failureType: "blocked/skip",
|
||||
selector: "#panel-wiring .wiring-long-table",
|
||||
viewport,
|
||||
summary: "#276 wiring panel is not the required two-column long table with device headers and DO1/DI1 row details.",
|
||||
wiring: {
|
||||
headers: wiringHeaders,
|
||||
legacyHeaderHits: wiringLegacyHeaderHits,
|
||||
rows: wiringRows,
|
||||
layout: wiringWrap?.getAttribute("data-wiring-layout") ?? null
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!wiringNoHorizontalScroll) {
|
||||
failures.push({
|
||||
failureType: "overflow",
|
||||
selector: "#panel-wiring",
|
||||
viewport,
|
||||
summary: "#276 wiring panel exposes internal horizontal scroll or clipped table width.",
|
||||
wiringHorizontalScroll
|
||||
});
|
||||
}
|
||||
const controlTab = document.querySelector("#tab-control");
|
||||
if (controlTab?.getAttribute("aria-selected") !== "true") {
|
||||
controlTab?.click();
|
||||
await new Promise((resolve) => requestAnimationFrame(resolve));
|
||||
}
|
||||
const toggle = {
|
||||
text: toggleElement?.textContent?.replace(/\s+/gu, " ").trim() ?? "",
|
||||
ariaLabel: toggleElement?.getAttribute("aria-label") ?? "",
|
||||
@@ -4469,10 +4588,14 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) {
|
||||
drawerReachable &&
|
||||
defaultCollapsedMobile &&
|
||||
sidePanelOverflowUsable;
|
||||
const passWithWiring =
|
||||
pass &&
|
||||
wiringLongTableOk &&
|
||||
wiringNoHorizontalScroll;
|
||||
return {
|
||||
mode,
|
||||
viewport,
|
||||
pass,
|
||||
pass: passWithWiring,
|
||||
explorerCollapsed,
|
||||
explorerVisible,
|
||||
toggle,
|
||||
@@ -4492,6 +4615,14 @@ async function inspectLayoutState(page, { mode, viewport, compareTo }) {
|
||||
blockedDrawerTargets,
|
||||
sidePanelScroll,
|
||||
sidePanelOverflowUsable,
|
||||
wiring: {
|
||||
longTableOk: wiringLongTableOk,
|
||||
noHorizontalScroll: wiringNoHorizontalScroll,
|
||||
headers: wiringHeaders,
|
||||
legacyHeaderHits: wiringLegacyHeaderHits,
|
||||
rows: wiringRows,
|
||||
horizontalScroll: wiringHorizontalScroll
|
||||
},
|
||||
semanticOverlapChecks,
|
||||
overflowChecks,
|
||||
defaultCollapsedMobile,
|
||||
|
||||
@@ -2053,22 +2053,34 @@ function assertDevCloudWorkbenchDomObservations(dom, label) {
|
||||
assert.equal(dom.codeAgentPostGuard.blockedPath, "/v1/agent/chat", `${label}.codeAgentPostGuard.blockedPath`);
|
||||
assert.equal(dom.codeAgentPostGuard.attemptedCount, 0, `${label}.codeAgentPostGuard.attemptedCount`);
|
||||
}
|
||||
assertStringArray(dom.wiringHeaders, `${label}.wiringHeaders`, { minLength: 8 });
|
||||
for (const column of ["源设备", "源端口", "接线盘", "目标设备", "目标端口", "状态", "证据来源", "trace/evidence"]) {
|
||||
assert.ok(dom.wiringHeaders.includes(column), `${label}.wiringHeaders missing ${column}`);
|
||||
assert.equal(dom.wiringLayout, "two-column-long-table", `${label}.wiringLayout`);
|
||||
assertStringArray(dom.wiringHeaderDevices, `${label}.wiringHeaderDevices`, { minLength: 2 });
|
||||
assert.equal(dom.wiringHeaderDevices.includes("res_boxsimu_1"), true, `${label}.wiringHeaderDevices missing res_boxsimu_1`);
|
||||
assert.equal(dom.wiringHeaderDevices.includes("res_boxsimu_2"), true, `${label}.wiringHeaderDevices missing res_boxsimu_2`);
|
||||
assert.equal(dom.wiringHeaderCount, 2, `${label}.wiringHeaderCount`);
|
||||
assertStringArray(dom.legacyWiringHeaders, `${label}.legacyWiringHeaders`);
|
||||
assert.equal(dom.legacyWiringHeaders.length, 0, `${label}.legacyWiringHeaders must not restore legacy wide columns`);
|
||||
assertArray(dom.wiringBodyCellCounts, `${label}.wiringBodyCellCounts`);
|
||||
for (const count of dom.wiringBodyCellCounts) {
|
||||
assert.equal(count, 2, `${label}.wiringBodyCellCounts must stay two-column`);
|
||||
}
|
||||
assertArray(dom.m3WiringRows, `${label}.m3WiringRows`);
|
||||
assert.ok(
|
||||
dom.m3WiringRows.some((row) =>
|
||||
Array.isArray(row) &&
|
||||
row.includes("res_boxsimu_1") &&
|
||||
row.includes("DO1") &&
|
||||
row.includes("hwlab-patch-panel") &&
|
||||
row.includes("res_boxsimu_2") &&
|
||||
row.includes("DI1")
|
||||
row.length === 2 &&
|
||||
row[0].includes("DO1") &&
|
||||
row[0].includes("hwlab-patch-panel") &&
|
||||
row[1].includes("DI1") &&
|
||||
row[1].includes("证据来源") &&
|
||||
row[1].includes("轨迹/证据")
|
||||
),
|
||||
`${label}.m3WiringRows missing required M3 route`
|
||||
);
|
||||
assert.match(dom.wiringSummaryText, /hwlab-patch-panel/u, `${label}.wiringSummaryText missing patch-panel`);
|
||||
assert.match(dom.wiringSummaryText, /状态/u, `${label}.wiringSummaryText missing status`);
|
||||
assert.match(dom.wiringSummaryText, /证据来源/u, `${label}.wiringSummaryText missing evidence source`);
|
||||
assert.match(dom.wiringSummaryText, /轨迹\/证据/u, `${label}.wiringSummaryText missing trace/evidence`);
|
||||
assertObject(dom.coreControlsVisible, `${label}.coreControlsVisible`);
|
||||
for (const control of ["commandInput", "commandSend", "agentChatStatus", "conversationList", "hardwareList", "wiringTab", "recordsTab"]) {
|
||||
assert.equal(dom.coreControlsVisible[control], true, `${label}.coreControlsVisible.${control}`);
|
||||
|
||||
Reference in New Issue
Block a user