feat(web): per-record apply checkboxes with select-all; prune opt-in
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,16 +1,34 @@
|
||||
import { render, screen } from "@testing-library/react"
|
||||
import userEvent from "@testing-library/user-event"
|
||||
import { DiffView } from "./DiffView"
|
||||
import type { ChangesetResponse } from "@/api/types"
|
||||
|
||||
const cs: ChangesetResponse = {
|
||||
updates: [{ kind: "update", type: "A", name: "www.example.com.", desired: ["1.1.1.1"], actual: ["9.9.9.9"], readOnly: false }],
|
||||
prunes: [{ kind: "delete", type: "A", name: "old.example.com.", actual: ["2.2.2.2"], readOnly: false }],
|
||||
readOnly: [{ kind: "update", type: "NS", name: "example.com.", desired: ["ns1."], actual: ["ns2."], readOnly: true }],
|
||||
updates: [{ key: "A www.example.com.", kind: "update", type: "A", name: "www.example.com.", desired: ["1.1.1.1"], actual: ["9.9.9.9"], readOnly: false }],
|
||||
prunes: [{ key: "A old.example.com.", kind: "delete", type: "A", name: "old.example.com.", actual: ["2.2.2.2"], readOnly: false }],
|
||||
readOnly: [{ key: "NS example.com.", kind: "update", type: "NS", name: "example.com.", desired: ["ns1."], actual: ["ns2."], readOnly: true }],
|
||||
inSyncCount: 3,
|
||||
}
|
||||
|
||||
function noop() { /* unused in most tests */ }
|
||||
|
||||
function renderDiff(overrides: Partial<Parameters<typeof DiffView>[0]> = {}) {
|
||||
return render(
|
||||
<DiffView
|
||||
changeset={cs}
|
||||
selectedUpdates={new Set(["A www.example.com."])}
|
||||
selectedPrunes={new Set()}
|
||||
onToggleUpdate={noop}
|
||||
onTogglePrune={noop}
|
||||
onToggleAllUpdates={noop}
|
||||
onToggleAllPrunes={noop}
|
||||
{...overrides}
|
||||
/>,
|
||||
)
|
||||
}
|
||||
|
||||
test("renders all sections with counts", () => {
|
||||
render(<DiffView changeset={cs} />)
|
||||
renderDiff()
|
||||
expect(screen.getByText(/www\.example\.com\./)).toBeInTheDocument()
|
||||
expect(screen.getByText(/old\.example\.com\./)).toBeInTheDocument()
|
||||
// Anchored (vs. the brief's bare /example\.com\./) — "www.example.com." and
|
||||
@@ -23,7 +41,7 @@ test("renders all sections with counts", () => {
|
||||
})
|
||||
|
||||
test("marks read-only records", () => {
|
||||
render(<DiffView changeset={cs} />)
|
||||
renderDiff()
|
||||
expect(screen.getByText(/NS/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
@@ -35,6 +53,7 @@ test("renders a very long unbreakable value (DKIM key) without crashing", () =>
|
||||
const csWithDkim: ChangesetResponse = {
|
||||
updates: [
|
||||
{
|
||||
key: "TXT default._domainkey.example.com.",
|
||||
kind: "update",
|
||||
type: "TXT",
|
||||
name: "default._domainkey.example.com.",
|
||||
@@ -47,7 +66,7 @@ test("renders a very long unbreakable value (DKIM key) without crashing", () =>
|
||||
readOnly: [],
|
||||
inSyncCount: 0,
|
||||
}
|
||||
render(<DiffView changeset={csWithDkim} />)
|
||||
renderDiff({ changeset: csWithDkim, selectedUpdates: new Set() })
|
||||
expect(screen.getByText(new RegExp(longValue))).toBeInTheDocument()
|
||||
})
|
||||
|
||||
@@ -60,7 +79,55 @@ test("does not crash when changeset fields are null", () => {
|
||||
readOnly: null,
|
||||
inSyncCount: 5,
|
||||
} as unknown as ChangesetResponse
|
||||
render(<DiffView changeset={nullish} />)
|
||||
renderDiff({ changeset: nullish, selectedUpdates: new Set() })
|
||||
expect(screen.getByText(/5/)).toBeInTheDocument()
|
||||
expect(screen.getByText(/in sync/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
test("renders a checkbox for update and prune rows but not for read-only rows", () => {
|
||||
renderDiff()
|
||||
// 2 select-all (update + prune headers) + 2 row checkboxes (one update, one prune).
|
||||
// Read-only section contributes none: no select-all, no row checkbox.
|
||||
const checkboxes = screen.getAllByRole("checkbox")
|
||||
expect(checkboxes).toHaveLength(4)
|
||||
|
||||
const updateRowCheckbox = screen.getByRole("checkbox", { name: /www\.example\.com\./ })
|
||||
expect(updateRowCheckbox).toBeInTheDocument()
|
||||
const pruneRowCheckbox = screen.getByRole("checkbox", { name: /old\.example\.com\./ })
|
||||
expect(pruneRowCheckbox).toBeInTheDocument()
|
||||
|
||||
expect(screen.queryByRole("checkbox", { name: /example\.com\..*NS|NS.*example\.com\./ })).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
test("clicking an update row checkbox calls onToggleUpdate with the record key", async () => {
|
||||
const onToggleUpdate = vi.fn()
|
||||
const user = userEvent.setup()
|
||||
renderDiff({ onToggleUpdate })
|
||||
|
||||
await user.click(screen.getByRole("checkbox", { name: /www\.example\.com\./ }))
|
||||
expect(onToggleUpdate).toHaveBeenCalledWith("A www.example.com.")
|
||||
})
|
||||
|
||||
test("clicking a prune row checkbox calls onTogglePrune with the record key", async () => {
|
||||
const onTogglePrune = vi.fn()
|
||||
const user = userEvent.setup()
|
||||
renderDiff({ onTogglePrune })
|
||||
|
||||
await user.click(screen.getByRole("checkbox", { name: /old\.example\.com\./ }))
|
||||
expect(onTogglePrune).toHaveBeenCalledWith("A old.example.com.")
|
||||
})
|
||||
|
||||
test("select-all header checkbox is checked when all rows in the section are selected", () => {
|
||||
renderDiff({ selectedUpdates: new Set(["A www.example.com."]) })
|
||||
const selectAll = screen.getByRole("checkbox", { name: /выбрать все.*updates/i })
|
||||
expect(selectAll).toHaveAttribute("aria-checked", "true")
|
||||
})
|
||||
|
||||
test("select-all header checkbox calls onToggleAllUpdates(true) when clicked while none selected", async () => {
|
||||
const onToggleAllUpdates = vi.fn()
|
||||
const user = userEvent.setup()
|
||||
renderDiff({ selectedUpdates: new Set(), onToggleAllUpdates })
|
||||
|
||||
await user.click(screen.getByRole("checkbox", { name: /выбрать все.*updates/i }))
|
||||
expect(onToggleAllUpdates).toHaveBeenCalledWith(true)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user