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