The findings of the Debian host (OS packages and applications found in the root filesystem) and of the container images in the cluster were mixed in one flat table. They are now two prominent categories: a card each with its own severity split and target count, acting as the primary selector, and a table that adapts to the selection. Host findings show the package source reported by the scanner (debian, gobinary, node-pkg …) instead of the target, container findings show the image. Backend: findings carry the scanner's package source, the list endpoint takes ?scope=host|container, and the targets endpoint reports each target with its category and open count. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
62 lines
2.3 KiB
TypeScript
62 lines
2.3 KiB
TypeScript
import { test, expect, type Page } from '@playwright/test'
|
|
|
|
// Wide content (tables) must scroll inside its own container; the page itself must never
|
|
// scroll horizontally, otherwise the header and the tiles get cut off.
|
|
const PAGES = [
|
|
'/',
|
|
'/updates',
|
|
'/cluster',
|
|
'/vulnerabilities',
|
|
'/backups',
|
|
'/jobs',
|
|
'/users',
|
|
'/settings',
|
|
]
|
|
|
|
async function login(page: Page) {
|
|
await page.goto('/login')
|
|
await page.getByLabel('Email').fill('admin@example.com')
|
|
await page.getByLabel('Password').fill('admin-password-123')
|
|
await page.getByRole('button', { name: 'Sign in' }).click()
|
|
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible()
|
|
}
|
|
|
|
const pageOverflow = (page: Page) =>
|
|
page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth)
|
|
|
|
test('no page scrolls horizontally, with data and on a narrow window', async ({ page }) => {
|
|
await page.setViewportSize({ width: 1280, height: 800 })
|
|
await login(page)
|
|
|
|
// fill the app with the data that makes the tables wide
|
|
await page.goto('/updates')
|
|
await page.getByRole('button', { name: 'Refresh inventory' }).click()
|
|
await expect(page.getByTestId('os-name')).toContainText('Debian', { timeout: 15_000 })
|
|
await page.goto('/vulnerabilities')
|
|
await page.getByRole('button', { name: 'Scan now' }).click()
|
|
await expect(page.getByTestId('scope-host-critical')).not.toHaveText('0', { timeout: 20_000 })
|
|
|
|
for (const width of [1440, 1280, 1024, 900]) {
|
|
await page.setViewportSize({ width, height: 800 })
|
|
for (const path of PAGES) {
|
|
await page.goto(path)
|
|
await expect(page.getByRole('heading').first()).toBeVisible()
|
|
expect(await pageOverflow(page), `${path} at ${width}px scrolls horizontally`).toBe(0)
|
|
}
|
|
}
|
|
})
|
|
|
|
test('the findings table scrolls inside its own container', async ({ page }) => {
|
|
await page.setViewportSize({ width: 900, height: 800 })
|
|
await login(page)
|
|
await page.goto('/vulnerabilities')
|
|
await page.getByRole('button', { name: 'Scan now' }).click()
|
|
await expect(page.getByTestId('scope-host-critical')).not.toHaveText('0', { timeout: 20_000 })
|
|
|
|
expect(await pageOverflow(page)).toBe(0)
|
|
const scrollable = await page
|
|
.getByTestId('findings-scroll')
|
|
.evaluate((el) => el.scrollWidth > el.clientWidth && getComputedStyle(el).overflowX === 'auto')
|
|
expect(scrollable).toBe(true)
|
|
})
|