Skip to content

Commit e03a060

Browse files
kevin-dpclaude
andcommitted
Add React test for includes: child collection subscription via useLiveQuery
Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent 8205b2c commit e03a060

1 file changed

Lines changed: 108 additions & 0 deletions

File tree

packages/react-db/tests/useLiveQuery.test.tsx

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2481,4 +2481,112 @@ describe(`Query Collections`, () => {
24812481
})
24822482
})
24832483
})
2484+
2485+
describe(`includes subqueries`, () => {
2486+
type Project = {
2487+
id: string
2488+
name: string
2489+
}
2490+
2491+
type ProjectIssue = {
2492+
id: string
2493+
title: string
2494+
projectId: string
2495+
}
2496+
2497+
const sampleProjects: Array<Project> = [
2498+
{ id: `p1`, name: `Alpha` },
2499+
{ id: `p2`, name: `Beta` },
2500+
]
2501+
2502+
const sampleProjectIssues: Array<ProjectIssue> = [
2503+
{ id: `i1`, title: `Bug in Alpha`, projectId: `p1` },
2504+
{ id: `i2`, title: `Feature for Alpha`, projectId: `p1` },
2505+
{ id: `i3`, title: `Bug in Beta`, projectId: `p2` },
2506+
]
2507+
2508+
it(`should render includes results and reactively update child collections`, async () => {
2509+
const projectsCollection = createCollection(
2510+
mockSyncCollectionOptions<Project>({
2511+
id: `includes-react-projects`,
2512+
getKey: (p) => p.id,
2513+
initialData: sampleProjects,
2514+
}),
2515+
)
2516+
2517+
const issuesCollection = createCollection(
2518+
mockSyncCollectionOptions<ProjectIssue>({
2519+
id: `includes-react-issues`,
2520+
getKey: (i) => i.id,
2521+
initialData: sampleProjectIssues,
2522+
}),
2523+
)
2524+
2525+
// Parent hook: runs includes query that produces child Collections
2526+
const { result: parentResult } = renderHook(() =>
2527+
useLiveQuery((q) =>
2528+
q.from({ p: projectsCollection }).select(({ p }) => ({
2529+
id: p.id,
2530+
name: p.name,
2531+
issues: q
2532+
.from({ i: issuesCollection })
2533+
.where(({ i }) => eq(i.projectId, p.id))
2534+
.select(({ i }) => ({
2535+
id: i.id,
2536+
title: i.title,
2537+
})),
2538+
})),
2539+
),
2540+
)
2541+
2542+
// Wait for parent to be ready
2543+
await waitFor(() => {
2544+
expect(parentResult.current.data).toHaveLength(2)
2545+
})
2546+
2547+
const alphaProject = parentResult.current.data.find(
2548+
(p: any) => p.id === `p1`,
2549+
)!
2550+
expect(alphaProject.name).toBe(`Alpha`)
2551+
2552+
// Child hook: subscribes to the child Collection from the parent row,
2553+
// simulating a subcomponent using useLiveQuery(project.issues)
2554+
const { result: childResult } = renderHook(() =>
2555+
useLiveQuery((alphaProject as any).issues),
2556+
)
2557+
2558+
await waitFor(() => {
2559+
expect(childResult.current.data).toHaveLength(2)
2560+
})
2561+
2562+
expect(childResult.current.data).toEqual(
2563+
expect.arrayContaining([
2564+
expect.objectContaining({ id: `i1`, title: `Bug in Alpha` }),
2565+
expect.objectContaining({ id: `i2`, title: `Feature for Alpha` }),
2566+
]),
2567+
)
2568+
2569+
// Add a new issue to Alpha — the child hook should reactively update
2570+
act(() => {
2571+
issuesCollection.utils.begin()
2572+
issuesCollection.utils.write({
2573+
type: `insert`,
2574+
value: { id: `i4`, title: `New Alpha issue`, projectId: `p1` },
2575+
})
2576+
issuesCollection.utils.commit()
2577+
})
2578+
2579+
await waitFor(() => {
2580+
expect(childResult.current.data).toHaveLength(3)
2581+
})
2582+
2583+
expect(childResult.current.data).toEqual(
2584+
expect.arrayContaining([
2585+
expect.objectContaining({ id: `i1`, title: `Bug in Alpha` }),
2586+
expect.objectContaining({ id: `i2`, title: `Feature for Alpha` }),
2587+
expect.objectContaining({ id: `i4`, title: `New Alpha issue` }),
2588+
]),
2589+
)
2590+
})
2591+
})
24842592
})

0 commit comments

Comments
 (0)