diff --git a/e2e/visual.spec.ts b/e2e/visual.spec.ts index e78b826..3dde5cf 100644 --- a/e2e/visual.spec.ts +++ b/e2e/visual.spec.ts @@ -82,3 +82,31 @@ test("empty results", async ({ page }) => { timeout: DATASET_READY_TIMEOUT_MS, }); }); + +test("hovered row", async ({ page }) => { + await page.goto("/"); + await expect(page.getByRole("table")).toBeVisible({ + timeout: DATASET_READY_TIMEOUT_MS, + }); + + const row = page.locator("tbody tr").first(); + const background = () => + row.evaluate((el) => getComputedStyle(el).backgroundColor); + const resting = await background(); + + await row.hover(); + const hovered = await background(); + expect(hovered).not.toBe(resting); + + // The archive Chromatic replays carries the DOM, never the pointer, so a + // :hover rule paints in none of it. Writing the colour the rule just produced + // onto the row puts it somewhere the archive reaches. Read from the rendered + // page rather than restated here, so a token change moves the snapshot and a + // deleted rule fails the assertion above before this line runs. Set through + // the CSSOM because the shell's style-src forbids a style attribute. + await row.evaluate((el, color) => { + el.style.backgroundColor = color; + }, hovered); + await page.mouse.move(0, 0); + await expect.poll(background).toBe(hovered); +}); diff --git a/src/components/DataTable/DataTable.module.scss b/src/components/DataTable/DataTable.module.scss index f2f5868..5ffe765 100644 --- a/src/components/DataTable/DataTable.module.scss +++ b/src/components/DataTable/DataTable.module.scss @@ -48,6 +48,10 @@ font-variant-numeric: tabular-nums; } + tbody tr:hover { + background-color: var(--color-surface-hover); + } + tbody tr:last-child td { border-bottom: none; // last in row needs no border otherwise it will have thicker border due to the parent container border }