diff --git a/app/components/RefetchIntervalPicker.tsx b/app/components/RefetchIntervalPicker.tsx index 451901c98..ba4512b7e 100644 --- a/app/components/RefetchIntervalPicker.tsx +++ b/app/components/RefetchIntervalPicker.tsx @@ -51,6 +51,8 @@ export function useIntervalPicker({ enabled, isLoading, fn, className }: Props)
diff --git a/app/pages/SiloUtilizationPage.tsx b/app/pages/SiloUtilizationPage.tsx index 0dc7e8ca1..a2a78b957 100644 --- a/app/pages/SiloUtilizationPage.tsx +++ b/app/pages/SiloUtilizationPage.tsx @@ -102,7 +102,8 @@ export default function SiloUtilizationPage() { { { await page.clock.setFixedTime(new Date('2025-10-23T12:34:56.000Z')) - // TODO: revert to default viewport once we've confirmed no visual regressions - // from the grid layout change. The tall viewport forces all content to render - // without scrolling, so fullPage screenshots are comparable between the old - // contained-scroll layout and the new document-scroll layout. - await page.setViewportSize({ width: 1280, height: 3100 }) + // seed Math.random so mock data (e.g. metrics charts) is deterministic + await page.addInitScript(() => { + let seed = 0x12345678 + Math.random = () => { + seed |= 0 + seed = (seed + 0x6d2b79f5) | 0 + let t = Math.imul(seed ^ (seed >>> 15), 1 | seed) + t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t + return ((t ^ (t >>> 14)) >>> 0) / 4294967296 + } + }) }) const fullPage = { fullPage: true } @@ -53,7 +59,6 @@ const pages = [ heading: 'Silo image', exact: true, }, - { name: 'silo utilization', url: '/utilization', heading: 'Utilization' }, { name: 'silo access', url: '/access', heading: 'Silo Access' }, // Project - Instances @@ -136,11 +141,6 @@ const pages = [ // System - Utilization { name: 'system utilization', url: '/system/utilization', heading: 'Utilization' }, - { - name: 'system utilization metrics tab', - url: '/system/utilization?tab=metrics', - heading: 'Utilization', - }, // System - Networking { name: 'system ip pools', url: '/system/networking/ip-pools', heading: 'IP Pools' }, @@ -231,4 +231,29 @@ test.describe('Visual Regression', { tag: '@visual' }, () => { await page.waitForLoadState('networkidle') await expect(page).toHaveScreenshot('command-menu.png', fullPage) }) + + // Utilization pages render charts and include the refetch interval picker — + // wait for the chart, then mask the refresh button so the spinner state + // doesn't cause flaky diffs. + test('silo utilization', async ({ page }) => { + await page.goto('/utilization', { waitUntil: 'networkidle' }) + await expect(page.getByRole('heading', { name: 'Utilization' })).toBeVisible() + await expect(page.locator('.recharts-curve').first()).toBeVisible() + await expect(page).toHaveScreenshot('silo-utilization.png', { + fullPage: true, + mask: [page.getByTestId('refetch-interval-refresh')], + maskColor: '#0b0e14', + }) + }) + + test('system utilization metrics tab', async ({ page }) => { + await page.goto('/system/utilization?tab=metrics', { waitUntil: 'networkidle' }) + await expect(page.getByRole('heading', { name: 'Utilization' })).toBeVisible() + await expect(page.locator('.recharts-curve').first()).toBeVisible() + await expect(page).toHaveScreenshot('system-utilization-metrics-tab.png', { + fullPage: true, + mask: [page.getByTestId('refetch-interval-refresh')], + maskColor: '#0b0e14', + }) + }) })