豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit 8970167

Browse files
committed
Add export fallback optimization coverage
1 parent 67b5c54 commit 8970167

File tree

1 file changed

+215
-0
lines changed

1 file changed

+215
-0
lines changed
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
import { createReadStream } from 'fs'
2+
import http from 'http'
3+
import { join } from 'path'
4+
import { createNext, isNextDeploy, isNextDev, NextInstance } from 'e2e-utils'
5+
import express from 'express'
6+
import { findPort, retry, stopApp } from 'next-test-utils'
7+
import webdriver from 'next-webdriver'
8+
import type * as Playwright from 'playwright'
9+
import { createRouterAct } from 'router-act'
10+
11+
async function buildAndStartOutputExportServer(next: NextInstance) {
12+
await next.build()
13+
14+
const port = await findPort()
15+
const app = express()
16+
const server = http.createServer(app)
17+
const outDir = join(next.testDir, 'out')
18+
const fallbackHtml = join(outDir, '_fallback.html')
19+
const requests: string[] = []
20+
21+
app.use((req, _res, nextMiddleware) => {
22+
requests.push(req.url)
23+
nextMiddleware()
24+
})
25+
app.use(
26+
express.static(outDir, {
27+
extensions: ['html'],
28+
redirect: false,
29+
})
30+
)
31+
app.use((_req, res) => {
32+
createReadStream(fallbackHtml).pipe(res)
33+
})
34+
35+
await new Promise<void>((resolve) => server.listen(port, resolve))
36+
37+
return {
38+
port,
39+
stopOrKill: () => stopApp(server),
40+
getRequests: () => [...requests],
41+
clearRequests: () => {
42+
requests.length = 0
43+
},
44+
}
45+
}
46+
47+
if (isNextDeploy) {
48+
describe.skip('app dir - output export dynamic route optimizations with Cache Components', () => {})
49+
} else {
50+
const describeProduction = isNextDev ? describe.skip : describe
51+
52+
describeProduction(
53+
'app dir - output export dynamic route optimizations with Cache Components',
54+
() => {
55+
let next: NextInstance
56+
let port: number
57+
let stopOrKill: (() => Promise<void>) | undefined
58+
let getRequests: () => string[]
59+
let clearRequests: () => void
60+
61+
beforeAll(async () => {
62+
next = await createNext({
63+
files: join(
64+
__dirname,
65+
'..',
66+
'fixtures',
67+
'dynamic-fallback-cache-components'
68+
),
69+
skipStart: true,
70+
disableAutoSkewProtection: true,
71+
})
72+
;({ port, stopOrKill, getRequests, clearRequests } =
73+
await buildAndStartOutputExportServer(next))
74+
})
75+
76+
afterAll(async () => {
77+
if (stopOrKill) {
78+
await stopOrKill()
79+
}
80+
await next.destroy()
81+
})
82+
83+
it('prefetches fallback payloads for unknown-param links before navigation', async () => {
84+
let act!: ReturnType<typeof createRouterAct>
85+
const browser = await webdriver(port, '/isolated/', {
86+
beforePageLoad(page: Playwright.Page) {
87+
act = createRouterAct(page)
88+
},
89+
})
90+
91+
try {
92+
await retry(async () => {
93+
expect(await browser.elementByCss('h1').text()).toBe('Isolated')
94+
})
95+
96+
await act(async () => {
97+
const toggle = await browser.elementByCss(
98+
'input[data-link-accordion="/isolated/third"]'
99+
)
100+
await toggle.click()
101+
})
102+
103+
clearRequests()
104+
105+
await browser
106+
.elementByCss('a[data-accordion-link="/isolated/third"]')
107+
.click()
108+
109+
await retry(async () => {
110+
expect(await browser.elementByCss('h1').text()).toBe('third')
111+
})
112+
113+
const clickRequests = getRequests()
114+
expect(
115+
clickRequests.some((requestPath) =>
116+
requestPath.startsWith('/isolated/__fallback.meta.json')
117+
)
118+
).toBe(false)
119+
expect(
120+
clickRequests.some((requestPath) =>
121+
requestPath.startsWith('/isolated/__fallback/index.txt')
122+
)
123+
).toBe(false)
124+
expect(
125+
clickRequests.some((requestPath) =>
126+
requestPath.startsWith('/isolated/third/index.txt')
127+
)
128+
).toBe(false)
129+
expect(
130+
clickRequests.some((requestPath) =>
131+
requestPath.startsWith('/isolated/third/__next.')
132+
)
133+
).toBe(false)
134+
} finally {
135+
await browser.close()
136+
}
137+
})
138+
139+
it('dedupes fallback artifact prefetches across sibling unknown-param links', async () => {
140+
let act!: ReturnType<typeof createRouterAct>
141+
const browser = await webdriver(port, '/isolated/', {
142+
beforePageLoad(page: Playwright.Page) {
143+
act = createRouterAct(page)
144+
},
145+
})
146+
147+
try {
148+
await retry(async () => {
149+
expect(await browser.elementByCss('h1').text()).toBe('Isolated')
150+
})
151+
152+
clearRequests()
153+
154+
await act(async () => {
155+
await browser
156+
.elementByCss('input[data-link-accordion="/isolated/third"]')
157+
.click()
158+
await browser
159+
.elementByCss('input[data-link-accordion="/isolated/fourth"]')
160+
.click()
161+
})
162+
163+
const prefetchRequests = getRequests().filter((requestPath) =>
164+
requestPath.startsWith('/isolated/__fallback/index.txt')
165+
)
166+
167+
expect(prefetchRequests).toHaveLength(1)
168+
} finally {
169+
await browser.close()
170+
}
171+
})
172+
173+
it('loads nested fallback routes without concrete retries or extra probes', async () => {
174+
clearRequests()
175+
const browser = await webdriver(port, '/org/umbrella/chat/thread-789/')
176+
177+
try {
178+
await retry(async () => {
179+
expect(await browser.elementByCss('#org-name').text()).toBe(
180+
'Org umbrella'
181+
)
182+
expect(await browser.elementByCss('h1').text()).toBe(
183+
'umbrella:thread-789'
184+
)
185+
})
186+
187+
const requests = getRequests()
188+
189+
expect(
190+
requests.some((requestPath) =>
191+
requestPath.startsWith('/org/umbrella/chat/thread-789/?_rsc=')
192+
)
193+
).toBe(false)
194+
expect(
195+
requests.some((requestPath) =>
196+
requestPath.startsWith('/org/__fallback.meta.json')
197+
)
198+
).toBe(false)
199+
expect(
200+
requests.some((requestPath) =>
201+
requestPath.startsWith('/org/__fallback.txt')
202+
)
203+
).toBe(false)
204+
expect(
205+
requests.filter((requestPath) =>
206+
requestPath.startsWith('/org/__fallback/index.txt')
207+
)
208+
).toHaveLength(1)
209+
} finally {
210+
await browser.close()
211+
}
212+
})
213+
}
214+
)
215+
}

0 commit comments

Comments
 (0)