Skip to content

Commit 3f60214

Browse files
committed
tests
1 parent 9eed74c commit 3f60214

File tree

6 files changed

+157
-0
lines changed

6 files changed

+157
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from 'react'
2+
3+
export default function RootLayout({ children }: LayoutProps<'/'>) {
4+
return (
5+
<html>
6+
<head></head>
7+
<body>{children}</body>
8+
</html>
9+
)
10+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Link from 'next/link'
2+
3+
export default function Page() {
4+
return (
5+
<main>
6+
<h1>Home</h1>
7+
<Link href="/with-loading" prefetch={false}>
8+
Go to /with-loading (no prefetch)
9+
</Link>
10+
</main>
11+
)
12+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Loading() {
2+
return <div id="loading-component">Loading...</div>
3+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { connection } from 'next/server'
2+
import { setTimeout } from 'timers/promises'
3+
4+
export default async function Page() {
5+
await connection()
6+
await setTimeout(1000)
7+
return (
8+
<main>
9+
<h1>Delayed page</h1>
10+
<p id="page-component">This is a dynamic page with a loading boundary.</p>
11+
</main>
12+
)
13+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/** @type {import('next').NextConfig} */
2+
module.exports = {
3+
experimental: {
4+
clientSegmentCache: true,
5+
clientParamParsing: true,
6+
},
7+
productionBrowserSourceMaps: true,
8+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { nextTestSetup } from 'e2e-utils'
2+
import { retry } from 'next-test-utils'
3+
import * as Playwright from 'playwright'
4+
5+
describe('navigating without a prefetch', () => {
6+
const { next } = nextTestSetup({
7+
files: __dirname,
8+
})
9+
10+
it('can show a loading boundary from the dynamic response', async () => {
11+
let page: Playwright.Page
12+
const browser = await next.browser('/', {
13+
beforePageLoad(_page) {
14+
page = _page
15+
},
16+
})
17+
const navigationTracker = trackMpaNavs(page)
18+
19+
// Navigate to a dynamic page with a `loading.tsx` without a prefetch.
20+
await browser.elementByCss('a[href="/with-loading"]').click()
21+
22+
// The loading state should stream in and be displayed.
23+
await retry(async () => {
24+
expect(
25+
await browser
26+
.elementByCss('#loading-component', { state: 'visible' })
27+
.text()
28+
).toContain('Loading...')
29+
})
30+
31+
// Later, the page should be displayed as well.
32+
await retry(async () => {
33+
expect(
34+
await browser
35+
.elementByCss('#page-component', { state: 'visible' })
36+
.text()
37+
).toContain('This is a dynamic page with a loading boundary.')
38+
})
39+
40+
// As a sanity check, we shouldn't MPA-nav.
41+
expect(navigationTracker.didMpaNavigate()).toBe(false)
42+
})
43+
44+
it('can handle failing RSC requests', async () => {
45+
let page: Playwright.Page
46+
const browser = await next.browser('/', {
47+
beforePageLoad(_page) {
48+
page = _page
49+
},
50+
})
51+
const navigationTracker = trackMpaNavs(page)
52+
53+
await page.route(
54+
'**/with-loading**',
55+
async (route) => {
56+
// await route.abort()
57+
await route.fulfill({
58+
status: 500,
59+
body: 'Oops, the server exploded a bit',
60+
contentType: 'text/plain',
61+
})
62+
},
63+
// only block the first request.
64+
{ times: 1 }
65+
)
66+
67+
console.log('clicking link...')
68+
// Navigate to a dynamic page with a `loading.tsx` without a prefetch.
69+
await browser.elementByCss('a[href="/with-loading"]').click()
70+
71+
// We made the RSC request fail, which should trigger a MPA navigation.
72+
await retry(
73+
() => {
74+
expect(navigationTracker.didMpaNavigate()).toBe(true)
75+
},
76+
undefined,
77+
50,
78+
'wait for MPA navigation'
79+
)
80+
81+
// The loading state should stream in and be displayed.
82+
await retry(async () => {
83+
expect(
84+
await browser
85+
.elementByCss('#loading-component', { state: 'visible' })
86+
.text()
87+
).toContain('Loading...')
88+
})
89+
90+
// Later, the page should be displayed as well.
91+
await retry(async () => {
92+
expect(
93+
await browser
94+
.elementByCss('#page-component', { state: 'visible' })
95+
.text()
96+
).toContain('This is a dynamic page with a loading boundary.')
97+
})
98+
})
99+
})
100+
101+
function trackMpaNavs(page: Playwright.Page) {
102+
let didMpaNavigate = false
103+
page.on('framenavigated', () => {
104+
didMpaNavigate = true
105+
})
106+
return {
107+
didMpaNavigate() {
108+
return didMpaNavigate
109+
},
110+
}
111+
}

0 commit comments

Comments
 (0)