test(record): cover providers fields and iteration
This commit is contained in:
@@ -0,0 +1,190 @@
|
|||||||
|
// @vitest-environment jsdom
|
||||||
|
|
||||||
|
import type { ReactNode } from "react"
|
||||||
|
import { cleanup, render, screen } from "@testing-library/react"
|
||||||
|
import { afterEach, describe, expect, it } from "vitest"
|
||||||
|
|
||||||
|
import {
|
||||||
|
OptionalRecordProvider,
|
||||||
|
RecordProvider,
|
||||||
|
RecordsIterator,
|
||||||
|
useFieldValue,
|
||||||
|
useRecord,
|
||||||
|
} from "@workspace/record"
|
||||||
|
|
||||||
|
interface Book {
|
||||||
|
author: {
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
id: number
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(cleanup)
|
||||||
|
|
||||||
|
function RecordProbe({ record }: { record?: Book }) {
|
||||||
|
const current = useRecord<Book>({ record })
|
||||||
|
return <span>{current?.title ?? "No record"}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
function FieldProbe() {
|
||||||
|
const author = useFieldValue<Book, "author.name">({
|
||||||
|
defaultValue: "Anonymous",
|
||||||
|
source: "author.name",
|
||||||
|
})
|
||||||
|
return <span>{author}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
function PrimitiveProbe<TRecord extends boolean | number | string>() {
|
||||||
|
const record = useRecord<TRecord>()
|
||||||
|
return <span>{String(record)}</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
function Wrapper({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<RecordProvider<Book>
|
||||||
|
value={{ author: { name: "Ursula Le Guin" }, id: 1, title: "Earthsea" }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</RecordProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("record context", () => {
|
||||||
|
it("reads context records and prefers an explicit override", () => {
|
||||||
|
render(
|
||||||
|
<Wrapper>
|
||||||
|
<RecordProbe />
|
||||||
|
<RecordProbe
|
||||||
|
record={{
|
||||||
|
author: { name: "Octavia Butler" },
|
||||||
|
id: 2,
|
||||||
|
title: "Parable of the Sower",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Wrapper>
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(screen.getByText("Earthsea")).toBeTruthy()
|
||||||
|
expect(screen.getByText("Parable of the Sower")).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("keeps the parent context when the optional record is undefined", () => {
|
||||||
|
render(
|
||||||
|
<Wrapper>
|
||||||
|
<OptionalRecordProvider value={undefined}>
|
||||||
|
<RecordProbe />
|
||||||
|
</OptionalRecordProvider>
|
||||||
|
</Wrapper>
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(screen.getByText("Earthsea")).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("accepts every non-nullish value as a record", () => {
|
||||||
|
render(
|
||||||
|
<>
|
||||||
|
<RecordProvider value={0}>
|
||||||
|
<PrimitiveProbe<number> />
|
||||||
|
</RecordProvider>
|
||||||
|
<RecordProvider value="draft">
|
||||||
|
<PrimitiveProbe<string> />
|
||||||
|
</RecordProvider>
|
||||||
|
<RecordProvider value>
|
||||||
|
<OptionalRecordProvider value={false}>
|
||||||
|
<PrimitiveProbe<boolean> />
|
||||||
|
</OptionalRecordProvider>
|
||||||
|
</RecordProvider>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(screen.getByText("0")).toBeTruthy()
|
||||||
|
expect(screen.getByText("draft")).toBeTruthy()
|
||||||
|
expect(screen.getByText("false")).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("reads nested field values and applies a default without a record", () => {
|
||||||
|
const { rerender } = render(
|
||||||
|
<Wrapper>
|
||||||
|
<FieldProbe />
|
||||||
|
</Wrapper>
|
||||||
|
)
|
||||||
|
expect(screen.getByText("Ursula Le Guin")).toBeTruthy()
|
||||||
|
|
||||||
|
rerender(<FieldProbe />)
|
||||||
|
expect(screen.getByText("Anonymous")).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("RecordsIterator", () => {
|
||||||
|
const books: Book[] = [
|
||||||
|
{ author: { name: "N. K. Jemisin" }, id: 1, title: "The Fifth Season" },
|
||||||
|
{ author: { name: "Ted Chiang" }, id: 2, title: "Exhalation" },
|
||||||
|
]
|
||||||
|
|
||||||
|
it("provides each record to shared children", () => {
|
||||||
|
render(
|
||||||
|
<RecordsIterator data={books}>
|
||||||
|
<RecordProbe />
|
||||||
|
</RecordsIterator>
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(screen.getByText("The Fifth Season")).toBeTruthy()
|
||||||
|
expect(screen.getByText("Exhalation")).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("supports iterator functions and custom record keys", () => {
|
||||||
|
render(
|
||||||
|
<RecordsIterator
|
||||||
|
data={books.map(({ id: _id, ...book }) => book)}
|
||||||
|
iterator={(book, index) => (
|
||||||
|
<span>
|
||||||
|
{index + 1}. {book.title}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
recordKey={(book) => book.title}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(screen.getByText("1. The Fifth Season")).toBeTruthy()
|
||||||
|
expect(screen.getByText("2. Exhalation")).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("iterates primitive records", () => {
|
||||||
|
render(
|
||||||
|
<RecordsIterator data={["draft", "published"]}>
|
||||||
|
<PrimitiveProbe<string> />
|
||||||
|
</RecordsIterator>
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(screen.getByText("draft")).toBeTruthy()
|
||||||
|
expect(screen.getByText("published")).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders separators between records", () => {
|
||||||
|
render(
|
||||||
|
<div data-testid="book-list">
|
||||||
|
<RecordsIterator
|
||||||
|
data={books}
|
||||||
|
iterator={(book) => <span>{book.title}</span>}
|
||||||
|
separator={(index) => <span>|{index}|</span>}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(screen.getByTestId("book-list").textContent).toBe(
|
||||||
|
"The Fifth Season|1|Exhalation"
|
||||||
|
)
|
||||||
|
expect(screen.getAllByText("|1|")).toHaveLength(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders nothing for missing data or content", () => {
|
||||||
|
const { container, rerender } = render(
|
||||||
|
<RecordsIterator data={undefined} iterator={() => <span>unused</span>} />
|
||||||
|
)
|
||||||
|
expect(container.childElementCount).toBe(0)
|
||||||
|
|
||||||
|
rerender(<RecordsIterator data={books} />)
|
||||||
|
expect(container.childElementCount).toBe(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user