fix: restore scrolling and validator enforcement
ForgeFlow quality gate / quality (push) Canceled after 0s
ForgeFlow quality gate / quality (push) Canceled after 0s
This commit is contained in:
@@ -60,6 +60,24 @@ async function assertSurface(page) {
|
||||
expect(audit.headings.length).toBeGreaterThan(0);
|
||||
}
|
||||
|
||||
async function assertScrollableWhenOverflowing(page, selector) {
|
||||
const target = page.locator(selector);
|
||||
await expect(target).toBeVisible();
|
||||
await expect(target).toHaveCSS("overflow-y", /auto|scroll/);
|
||||
let metrics;
|
||||
await expect.poll(async () => {
|
||||
metrics = await target.evaluate((element) => ({
|
||||
connected: element.isConnected,
|
||||
clientHeight: element.clientHeight,
|
||||
scrollHeight: element.scrollHeight,
|
||||
}));
|
||||
return metrics.connected && metrics.clientHeight > 0;
|
||||
}).toBe(true);
|
||||
if (metrics.scrollHeight > metrics.clientHeight + 1) {
|
||||
await target.evaluate((element) => { element.scrollTop = element.scrollHeight; });
|
||||
await expect.poll(() => target.evaluate((element) => element.scrollTop)).toBeGreaterThan(0);
|
||||
}
|
||||
}
|
||||
test("shell, overview, repositories and settings remain responsive and accessible", async ({ page }, testInfo) => {
|
||||
await assertSurface(page);
|
||||
for (const view of ["overview", "deployments", "settings"]) {
|
||||
@@ -86,13 +104,28 @@ test("repository changes, Git tools and Git Validator complete their primary flo
|
||||
}
|
||||
await page.locator('[data-action="repo-tab"][data-tab="validator"]').click();
|
||||
await expect(page.locator(".validator-score")).toBeVisible();
|
||||
await assertScrollableWhenOverflowing(page, ".validator-page");
|
||||
await expect(page.locator("#validator-policy")).toBeVisible();
|
||||
await page.locator("#validator-policy").selectOption("production");
|
||||
await expect(page.locator(".validator-hero")).toContainText(/Production policy/i);
|
||||
await expect(page.locator(".validator-hero")).toContainText(/review required/i);
|
||||
await page.keyboard.press("Tab");
|
||||
await expect(page.locator(":focus")).toBeVisible();
|
||||
});
|
||||
|
||||
test("every long application surface retains a working vertical scroll owner", async ({ page }) => {
|
||||
for (const view of ["overview", "deployments", "diagnostics", "settings"]) {
|
||||
await page.locator(`.nav-button[data-view="${view}"]`).click();
|
||||
await assertScrollableWhenOverflowing(page, ".main-canvas");
|
||||
}
|
||||
await page.locator('[data-action="select-repo"]').first().click();
|
||||
for (const tab of ["history", "deployments", "gittools", "validator", "settings"]) {
|
||||
await page.locator(`[data-action="repo-tab"][data-tab="${tab}"]`).click();
|
||||
const scrollRoot = page.locator(".repo-content > .tab-page, .repo-content > .validator-page");
|
||||
if (await scrollRoot.count())
|
||||
await assertScrollableWhenOverflowing(page, ".repo-content > .tab-page, .repo-content > .validator-page");
|
||||
}
|
||||
});
|
||||
test("deployment inventory supports dense workloads without ambiguous blank cards", async ({ page }) => {
|
||||
await page.locator('.nav-button[data-action="navigate"][data-view="deployments"]').click();
|
||||
await expect(page.locator(".deploy-card, .server-inventory-panel .tool-row").first()).toBeVisible();
|
||||
|
||||
@@ -23,6 +23,20 @@ test("Git Validator policies enforce score, blockers and enabled checks", () =>
|
||||
assert.equal(governed.checks[0].blocking, true);
|
||||
});
|
||||
|
||||
test("built-in policies enforce their declared blocking severities", () => {
|
||||
const finding = [{ id: "readme", status: "warning", category: "Documentation", weight: 5 }];
|
||||
assert.equal(applyPolicy(finding, { id: "minimal" }, []).checks[0].blocking, false);
|
||||
for (const id of ["standard", "strict", "production"])
|
||||
assert.equal(applyPolicy(finding, { id }, []).checks[0].blocking, true, `${id} must block active warnings`);
|
||||
});
|
||||
|
||||
test("documented suppressions remove active blockers", () => {
|
||||
const now = new Date("2026-07-01T00:00:00.000Z");
|
||||
const suppression = validateSuppression({ checkId: "readme", reason: "Tracked remediation work", author: "Jens", expiresAt: "2026-07-08T00:00:00.000Z", evidence: "ticket:FF-7" }, normalizePolicy({ id: "standard" }), now);
|
||||
const check = applyPolicy([{ id: "readme", status: "warning", category: "Documentation", weight: 5 }], { id: "standard" }, [suppression], now).checks[0];
|
||||
assert.equal(check.suppressed, true);
|
||||
assert.equal(check.blocking, false);
|
||||
});
|
||||
test("suppressions require accountable evidence and reactivate after expiry", () => {
|
||||
const now = new Date("2026-07-01T00:00:00.000Z");
|
||||
const suppression = validateSuppression({ checkId: "signed-tags", reason: "Tracked under release hardening", author: "Jens", ticket: "FF-42", expiresAt: "2026-07-08T00:00:00.000Z", scope: "repository", evidence: "sha:abc" }, normalizePolicy({ id: "standard" }), now);
|
||||
|
||||
@@ -100,6 +100,24 @@ test("Git Validator recognizes remote aliases and secret-shaped tracked paths",
|
||||
assert.equal(isSensitiveTrackedPath(".env.example"), false);
|
||||
});
|
||||
|
||||
test("Git Validator rejects stale or forged repair requests", async () => {
|
||||
const validator = new GitValidatorService({ git: new GitService() });
|
||||
validator.scan = async () => ({
|
||||
checks: [{ id: "local-safety", fixAction: "configure-local-safety", status: "warning" }],
|
||||
});
|
||||
assert.equal(
|
||||
(await validator.resolveRepairCheck({}, { id: "local-safety", fixAction: "configure-local-safety" })).id,
|
||||
"local-safety",
|
||||
);
|
||||
await assert.rejects(
|
||||
validator.resolveRepairCheck({}, { id: "local-safety", fixAction: "align-origin" }),
|
||||
/stale/i,
|
||||
);
|
||||
await assert.rejects(
|
||||
validator.resolveRepairCheck({}, { id: "resolved-check", fixAction: "align-origin" }),
|
||||
/resolved|no longer repairable/i,
|
||||
);
|
||||
});
|
||||
test("Git Validator reports reproducibility, CI and editor hygiene and creates reviewable defaults", async (t) => {
|
||||
const root = await mkdtemp(path.join(os.tmpdir(), "forgeflow-hygiene-"));
|
||||
t.after(() => rm(root, { recursive: true, force: true }));
|
||||
|
||||
Reference in New Issue
Block a user