diff --git a/ui/src/e2e/cron-remove.e2e.test.ts b/ui/src/e2e/cron-remove.e2e.test.ts index f2d49f8008a6..9e734902b43b 100644 --- a/ui/src/e2e/cron-remove.e2e.test.ts +++ b/ui/src/e2e/cron-remove.e2e.test.ts @@ -63,7 +63,11 @@ suite.define(() => { expect(response?.status()).toBe(200); const row = page.locator(`[data-test-id="cron-row-${job.id}"]`); await row.waitFor({ state: "visible", timeout: 10_000 }); - await row.locator(".cron-table__name-text").click(); + expect(await page.locator(".cron-table__head").getAttribute("role")).toBeNull(); + expect(await row.getAttribute("role")).toBeNull(); + const openTask = row.getByRole("button", { name: /Nightly digest/ }); + await openTask.focus(); + await page.keyboard.press("Enter"); const detail = page.locator('.cron-page[data-panel-mode="job"]'); await detail.waitFor({ state: "visible" }); diff --git a/ui/src/pages/cron/view.test.ts b/ui/src/pages/cron/view.test.ts index fed8803ff32b..2323d70f4e04 100644 --- a/ui/src/pages/cron/view.test.ts +++ b/ui/src/pages/cron/view.test.ts @@ -116,7 +116,22 @@ describe("cron view list pane", () => { expect(onJobsFiltersReset).toHaveBeenCalledTimes(1); }); - it("renders table rows with schedule and status cells and selects on click", () => { + it("does not expose table rows without complete table semantics", () => { + const container = renderView({ jobs: [createJob("job-1")] }); + + for (const row of container.querySelectorAll('[role="row"]')) { + expect(row.closest('[role="table"], [role="grid"], [role="treegrid"]')).not.toBeNull(); + expect( + Array.from(row.children).every((child) => + child.matches( + '[role="cell"], [role="gridcell"], [role="columnheader"], [role="rowheader"]', + ), + ), + ).toBe(true); + } + }); + + it("renders table rows with independent native buttons for opening tasks", () => { const onSelectJob = vi.fn(); const job = createJob("job-1", { trigger: { script: "json({ fire: true })" }, @@ -134,6 +149,7 @@ describe("cron view list pane", () => { const rows = Array.from(container.querySelectorAll(".cron-table__row")); expect(rows).toHaveLength(3); + expect(rows[0]?.getAttribute("role")).toBeNull(); expect(rows[0]?.textContent).toContain("Cron 0 9 * * *"); expect(rows[1]?.classList.contains("cron-table__row--paused")).toBe(true); expect(rows[1]?.textContent).toContain("Paused"); @@ -150,7 +166,7 @@ describe("cron view list pane", () => { "Trigger configured", ); - (rows[1] as HTMLElement).click(); + getElement(rows[1] as Element, ".cron-table__name", HTMLButtonElement).click(); expect(onSelectJob).toHaveBeenCalledWith(paused); }); diff --git a/ui/src/pages/cron/view.ts b/ui/src/pages/cron/view.ts index 5f3cb7b80067..1bad08ad1c1a 100644 --- a/ui/src/pages/cron/view.ts +++ b/ui/src/pages/cron/view.ts @@ -728,7 +728,7 @@ function renderJobsFilterPopover(props: CronProps, active: boolean) { function renderJobsTable(props: CronProps, hasAnyJobsFilters: boolean) { return html`