From 984cf6691a3e1f2b4d756fc76a4efd0296e2906c Mon Sep 17 00:00:00 2001 From: Gaurav Jadhav Date: Wed, 2 Sep 2026 19:28:39 +0530 Subject: [PATCH 1/3] test(web): position the estimator strip test from the gauge, not the card CI's tablet-768 project failed the mobile-summary test: parking the inputs card 80px under the header leaves the gauge mostly visible on a 768x1024 viewport, so the strip rightly stays hidden. Scroll so the gauge is a fifth visible instead, which holds on phones and tablets alike. --- apps/web/tests/e2e/impact-estimator.spec.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/web/tests/e2e/impact-estimator.spec.ts b/apps/web/tests/e2e/impact-estimator.spec.ts index 5c73e16a..ebf7ec1d 100644 --- a/apps/web/tests/e2e/impact-estimator.spec.ts +++ b/apps/web/tests/e2e/impact-estimator.spec.ts @@ -69,11 +69,16 @@ test.describe("impact estimator mobile summary @phase-web-impact-estimator", () const strip = page.locator('button[aria-label^="Jump to your results"]'); await expect(strip).toHaveAttribute("aria-hidden", "true"); - // Park the inputs card just under the header: the sliders are usable and - // the gauge sits below the fold on every phone viewport. + // Scroll so the gauge is only a fifth visible at the bottom edge: the inputs + // card is on screen and the readout is not, on phones and tablets alike. A + // fixed offset from the card top would not do: at 768px the card is short + // enough that the gauge is already mostly visible, and the strip rightly + // stays hidden. await page.evaluate(() => { - const card = document.querySelector('[data-section="ImpactSimulator"] .lg\\:sticky'); - if (card) window.scrollTo({ top: card.getBoundingClientRect().top + window.scrollY - 80, behavior: "instant" }); + const gauge = document.querySelector('[data-section="ImpactSimulator"] svg[role="img"]'); + if (!gauge) return; + const r = gauge.getBoundingClientRect(); + window.scrollTo({ top: r.top + window.scrollY - window.innerHeight + r.height * 0.2, behavior: "instant" }); }); await expect(strip).toHaveAttribute("aria-hidden", "false"); await expect(strip).toHaveAttribute("aria-label", /High runtime complexity, burden 260, 7,800 hours/); From a2b3875707370bf3963517c20a62c03e92d23bcc Mon Sep 17 00:00:00 2001 From: Gaurav Jadhav Date: Wed, 2 Sep 2026 19:47:23 +0530 Subject: [PATCH 2/3] test(web): wait for hydration before clicking the estimator's copy-link The copy test flaked once in CI on laptop-1024: the click landed before React attached the handler. Assert the URL-driven slider value first, which only appears after hydration. --- apps/web/tests/e2e/impact-estimator.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/web/tests/e2e/impact-estimator.spec.ts b/apps/web/tests/e2e/impact-estimator.spec.ts index ebf7ec1d..5a798ae1 100644 --- a/apps/web/tests/e2e/impact-estimator.spec.ts +++ b/apps/web/tests/e2e/impact-estimator.spec.ts @@ -51,6 +51,9 @@ test.describe("impact estimator copy link @phase-web-impact-estimator", () => { test.skip(browserName !== "chromium", "clipboard permissions are only grantable in Chromium"); await context.grantPermissions(["clipboard-read", "clipboard-write"]); await page.goto(`${ROUTE}?images=60&team=15&remediation=Quarterly&release=Monthly`); + // The slider only reads 60 once the page has hydrated and adopted the URL; + // clicking before that lands on a button with no handler yet. + await expect(page.getByRole("slider", { name: "Production images" })).toHaveValue("60"); const button = page.getByRole("button", { name: "Copy link to results" }); await button.click(); From 3c80a9467e027a2712b3a9e98671eda291bc26a4 Mon Sep 17 00:00:00 2001 From: Gaurav Jadhav Date: Wed, 2 Sep 2026 19:49:52 +0530 Subject: [PATCH 3/3] fix(web): align the Solutions panel's group rows and divider Columns 1 and 2 were independent stacks, so once Capability had three items its divider and Compliance sat lower than By role's divider and By industry. The four groups now share one two-column grid: Capability beside By role, a single divider across both, Compliance beside By industry. --- .../components/nav/panels/PanelSolutions.tsx | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/apps/web/src/components/nav/panels/PanelSolutions.tsx b/apps/web/src/components/nav/panels/PanelSolutions.tsx index 041bfc44..f17f2291 100644 --- a/apps/web/src/components/nav/panels/PanelSolutions.tsx +++ b/apps/web/src/components/nav/panels/PanelSolutions.tsx @@ -59,29 +59,16 @@ export function PanelSolutions({ item }: Props) { atmosphere={ATMOSPHERE} >
- {/* Col 1: Capability stacked above Compliance */} -
+ {/* Cols 1 and 2 share one grid so the two rows of groups line up: + Capability beside By role, one divider across both, then + Compliance beside By industry. Two independent stacks drifted as + soon as the groups had different item counts. */} +
{capability && } - {compliance && ( - <> -
- - - )} -
- - {/* Col 2: By Role stacked above By Industry, on the same divider - grammar as Col 1. Col 2 held a single two-item group and ran short - against Col 1's five, so the second group lands where the panel - already had vertical room. */} -
{byRole && } - {byIndustry && ( - <> -
- - - )} +
+ {compliance && } + {byIndustry && }
{/* Col 3: FIPS featured tile */}