Skip to content

Commit 9f8990b

Browse files
authored
test(router-core): assert sequential asset projection (#8152)
1 parent a5a5bac commit 9f8990b

1 file changed

Lines changed: 121 additions & 0 deletions

File tree

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { createMemoryHistory } from '@tanstack/history'
2+
import { describe, expect, test, vi } from 'vitest'
3+
import { BaseRootRoute, BaseRoute } from '../src'
4+
import { createTestRouter, loadServerResponse } from './routerTestUtils'
5+
import type { AnyRouteMatch } from '../src'
6+
7+
type AssetContext = {
8+
matches: Array<AnyRouteMatch>
9+
match: AnyRouteMatch
10+
}
11+
12+
function setup(isServer = false) {
13+
const parentHead = vi.fn((_context: AssetContext) => ({
14+
meta: [{ title: 'Parent' }],
15+
}))
16+
const parentScripts = vi.fn((_context: AssetContext) => [
17+
{ children: 'window.parent = true' },
18+
])
19+
const childHead = vi.fn(({ matches, match }: AssetContext) => {
20+
const parentMatch = matches[match.index - 1]
21+
const parentTitle = (parentMatch?.meta as Array<{ title?: string }>)[0]
22+
?.title
23+
return { meta: [{ title: `${parentTitle} | Child` }] }
24+
})
25+
const childScripts = vi.fn(({ matches, match }: AssetContext) => {
26+
const parentMatch = matches[match.index - 1]
27+
const parentScript = (
28+
parentMatch?.scripts as Array<{ children?: string }> | undefined
29+
)?.[0]?.children
30+
return [{ children: `${parentScript}; window.child = true` }]
31+
})
32+
const rootRoute = new BaseRootRoute({})
33+
const parentRoute = new BaseRoute({
34+
getParentRoute: () => rootRoute,
35+
path: '/parent',
36+
head: parentHead,
37+
scripts: parentScripts,
38+
})
39+
const childRoute = new BaseRoute({
40+
getParentRoute: () => parentRoute,
41+
path: '/child',
42+
head: childHead,
43+
scripts: childScripts,
44+
})
45+
const router = createTestRouter({
46+
routeTree: rootRoute.addChildren([parentRoute.addChildren([childRoute])]),
47+
history: createMemoryHistory({ initialEntries: ['/parent/child'] }),
48+
isServer,
49+
})
50+
51+
return {
52+
parentHead,
53+
parentScripts,
54+
childHead,
55+
childScripts,
56+
parentRoute,
57+
childRoute,
58+
router,
59+
}
60+
}
61+
62+
function expectSequentialProjection(result: ReturnType<typeof setup>): void {
63+
expect(result.parentHead).toHaveBeenCalledTimes(1)
64+
expect(result.parentScripts).toHaveBeenCalledTimes(1)
65+
expect(result.childHead).toHaveBeenCalledTimes(1)
66+
expect(result.childScripts).toHaveBeenCalledTimes(1)
67+
68+
const childHeadContext = result.childHead.mock.calls[0]![0]
69+
expect(childHeadContext.match.routeId).toBe(result.childRoute.id)
70+
expect(
71+
childHeadContext.matches[childHeadContext.match.index - 1],
72+
).toMatchObject({
73+
routeId: result.parentRoute.id,
74+
meta: [{ title: 'Parent' }],
75+
})
76+
77+
const childScriptsContext = result.childScripts.mock.calls[0]![0]
78+
expect(childScriptsContext.match.routeId).toBe(result.childRoute.id)
79+
expect(
80+
childScriptsContext.matches[childScriptsContext.match.index - 1],
81+
).toMatchObject({
82+
routeId: result.parentRoute.id,
83+
scripts: [{ children: 'window.parent = true' }],
84+
})
85+
86+
expect(
87+
result.router.state.matches.find(
88+
(match) => match.routeId === result.parentRoute.id,
89+
),
90+
).toMatchObject({
91+
meta: [{ title: 'Parent' }],
92+
scripts: [{ children: 'window.parent = true' }],
93+
})
94+
expect(
95+
result.router.state.matches.find(
96+
(match) => match.routeId === result.childRoute.id,
97+
),
98+
).toMatchObject({
99+
meta: [{ title: 'Parent | Child' }],
100+
scripts: [{ children: 'window.parent = true; window.child = true' }],
101+
})
102+
}
103+
104+
describe('asset projection order', () => {
105+
test('client calls head and scripts sequentially from parent to child', async () => {
106+
const result = setup()
107+
108+
await result.router.load()
109+
110+
expectSequentialProjection(result)
111+
})
112+
113+
test('server calls head and scripts sequentially from parent to child', async () => {
114+
const result = setup(true)
115+
116+
const response = await loadServerResponse(result.router, '/parent/child')
117+
118+
expect(response.status).toBe(200)
119+
expectSequentialProjection(result)
120+
})
121+
})

0 commit comments

Comments
 (0)