Skip to content

Commit b25ee4a

Browse files
committed
test: expand middleware + json data e2e tests
1 parent 1f8ae92 commit b25ee4a

18 files changed

+460
-13
lines changed

tests/e2e/edge-middleware.test.ts

Lines changed: 135 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import { nextVersionSatisfies } from '../utils/next-version-helpers.mjs'
33
import { test } from '../utils/playwright-helpers.js'
44
import { getImageSize } from 'next/dist/server/image-optimizer.js'
55

6+
type ExtendedWindow = Window & {
7+
didReload?: boolean
8+
}
9+
610
test('Runs edge middleware', async ({ page, middleware }) => {
711
await page.goto(`${middleware.url}/test/redirect`)
812

@@ -53,21 +57,139 @@ test('it should render OpenGraph image meta tag correctly', async ({ page, middl
5357
expect([size.width, size.height]).toEqual([1200, 630])
5458
})
5559

56-
test('json data rewrite works', async ({ middlewarePages }) => {
57-
const response = await fetch(`${middlewarePages.url}/_next/data/build-id/sha.json`, {
58-
headers: {
59-
'x-nextjs-data': '1',
60+
test.describe('json data', () => {
61+
const testConfigs = [
62+
{
63+
describeLabel: 'NextResponse.next() -> getServerSideProps page',
64+
selector: 'NextResponse.next()#getServerSideProps',
65+
jsonPathMatcher: '/link/next-getserversideprops.json',
66+
},
67+
{
68+
describeLabel: 'NextResponse.next() -> getStaticProps page',
69+
selector: 'NextResponse.next()#getStaticProps',
70+
jsonPathMatcher: '/link/next-getstaticprops.json',
71+
},
72+
{
73+
describeLabel: 'NextResponse.next() -> fully static page',
74+
selector: 'NextResponse.next()#fullyStatic',
75+
jsonPathMatcher: '/link/next-fullystatic.json',
76+
},
77+
{
78+
describeLabel: 'NextResponse.rewrite() -> getServerSideProps page',
79+
selector: 'NextResponse.rewrite()#getServerSideProps',
80+
jsonPathMatcher: '/link/rewrite-me-getserversideprops.json',
6081
},
82+
{
83+
describeLabel: 'NextResponse.rewrite() -> getStaticProps page',
84+
selector: 'NextResponse.rewrite()#getStaticProps',
85+
jsonPathMatcher: '/link/rewrite-me-getstaticprops.json',
86+
},
87+
{
88+
describeLabel: 'NextResponse.rewrite() -> fully static page',
89+
selector: 'NextResponse.rewrite()#fullyStatic',
90+
jsonPathMatcher: '/link/rewrite-me-fullystatic.json',
91+
},
92+
]
93+
test.describe('no 18n', () => {
94+
for (const testConfig of testConfigs) {
95+
test.describe(testConfig.describeLabel, () => {
96+
test('json data fetch', async ({ middlewarePages, page }) => {
97+
const dataFetchPromise = new Promise<Response>((resolve) => {
98+
page.on('response', (response) => {
99+
if (response.url().includes(testConfig.jsonPathMatcher)) {
100+
resolve(response)
101+
}
102+
})
103+
})
104+
105+
await page.goto(`${middlewarePages.url}/link`)
106+
107+
await page.hover(`[data-link="${testConfig.selector}"]`)
108+
109+
const dataResponse = await dataFetchPromise
110+
111+
expect(dataResponse.ok()).toBe(true)
112+
})
113+
114+
test('navigation', async ({ middlewarePages, page }) => {
115+
await page.goto(`${middlewarePages.url}/link`)
116+
117+
await page.evaluate(() => {
118+
// set some value to window to check later if browser did reload and lost this state
119+
;(window as ExtendedWindow).didReload = false
120+
})
121+
122+
await page.click(`[data-link="${testConfig.selector}"]`)
123+
124+
// wait for page to be rendered
125+
await page.waitForSelector(`[data-page="${testConfig.selector}"]`)
126+
127+
// check if browser navigation worked by checking if state was preserved
128+
const browserNavigationWorked =
129+
(await page.evaluate(() => {
130+
return (window as ExtendedWindow).didReload
131+
})) === false
132+
133+
// we expect client navigation to work without browser reload
134+
expect(browserNavigationWorked).toBe(true)
135+
})
136+
})
137+
}
138+
})
139+
test.describe('with 18n', () => {
140+
for (const testConfig of testConfigs) {
141+
test.describe(testConfig.describeLabel, () => {
142+
for (const { localeLabel, pageWithLinksPathname } of [
143+
{ localeLabel: 'implicit default locale', pageWithLinksPathname: '/link' },
144+
{ localeLabel: 'explicit default locale', pageWithLinksPathname: '/en/link' },
145+
{ localeLabel: 'explicit non-default locale', pageWithLinksPathname: '/fr/link' },
146+
]) {
147+
test.describe(localeLabel, () => {
148+
test('json data fetch', async ({ middlewareI18n, page }) => {
149+
const dataFetchPromise = new Promise<Response>((resolve) => {
150+
page.on('response', (response) => {
151+
if (response.url().includes(testConfig.jsonPathMatcher)) {
152+
resolve(response)
153+
}
154+
})
155+
})
156+
157+
await page.goto(`${middlewareI18n.url}${pageWithLinksPathname}`)
158+
159+
await page.hover(`[data-link="${testConfig.selector}"]`)
160+
161+
const dataResponse = await dataFetchPromise
162+
163+
expect(dataResponse.ok()).toBe(true)
164+
})
165+
166+
test('navigation', async ({ middlewareI18n, page }) => {
167+
await page.goto(`${middlewareI18n.url}${pageWithLinksPathname}`)
168+
169+
await page.evaluate(() => {
170+
// set some value to window to check later if browser did reload and lost this state
171+
;(window as ExtendedWindow).didReload = false
172+
})
173+
174+
await page.click(`[data-link="${testConfig.selector}"]`)
175+
176+
// wait for page to be rendered
177+
await page.waitForSelector(`[data-page="${testConfig.selector}"]`)
178+
179+
// check if browser navigation worked by checking if state was preserved
180+
const browserNavigationWorked =
181+
(await page.evaluate(() => {
182+
return (window as ExtendedWindow).didReload
183+
})) === false
184+
185+
// we expect client navigation to work without browser reload
186+
expect(browserNavigationWorked).toBe(true)
187+
})
188+
})
189+
}
190+
})
191+
}
61192
})
62-
63-
expect(response.ok).toBe(true)
64-
const body = await response.text()
65-
66-
expect(body).toMatch(/^{"pageProps":/)
67-
68-
const data = JSON.parse(body)
69-
70-
expect(data.pageProps.message).toBeDefined()
71193
})
72194

73195
// those tests use `fetch` instead of `page.goto` intentionally to avoid potential client rendering

tests/fixtures/middleware-i18n/middleware.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,26 @@ export async function middleware(request) {
88
return NextResponse.next()
99
}
1010

11+
if (url.pathname.startsWith('/link/next')) {
12+
return NextResponse.next({
13+
headers: {
14+
'x-middleware-test': 'link-next',
15+
},
16+
})
17+
}
18+
19+
if (url.pathname.startsWith('/link/rewrite-me')) {
20+
const rewriteUrl = new URL(
21+
url.pathname.replace('/link/rewrite-me', '/link/rewrite-target'),
22+
url,
23+
)
24+
return NextResponse.rewrite(rewriteUrl, {
25+
headers: {
26+
'x-middleware-test': 'link-rewrite',
27+
},
28+
})
29+
}
30+
1131
if (url.pathname === '/old-home') {
1232
if (url.searchParams.get('override') === 'external') {
1333
return Response.redirect('https://example.vercel.sh')
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import Link from 'next/link'
2+
3+
export default function Page() {
4+
return (
5+
<div>
6+
<h1>Page with Links</h1>
7+
<ul>
8+
<li>
9+
NextResponse.next()
10+
<ul>
11+
<li>
12+
<Link
13+
href="/link/next-getserversideprops"
14+
data-link="NextResponse.next()#getServerSideProps"
15+
>
16+
getServerSideProps
17+
</Link>
18+
</li>
19+
20+
<li>
21+
<Link href="/link/next-getstaticprops" data-link="NextResponse.next()#getStaticProps">
22+
getStaticProps
23+
</Link>
24+
</li>
25+
26+
<li>
27+
<Link href="/link/next-fullystatic" data-link="NextResponse.next()#fullyStatic">
28+
fullyStatic
29+
</Link>
30+
</li>
31+
</ul>
32+
</li>
33+
<li>
34+
NextResponse.rewrite()
35+
<ul>
36+
<li>
37+
<Link
38+
href="/link/rewrite-me-getserversideprops"
39+
data-link="NextResponse.rewrite()#getServerSideProps"
40+
>
41+
getServerSideProps
42+
</Link>
43+
</li>
44+
45+
<li>
46+
<Link
47+
href="/link/rewrite-me-getstaticprops"
48+
data-link="NextResponse.rewrite()#getStaticProps"
49+
>
50+
getStaticProps
51+
</Link>
52+
</li>
53+
54+
<li>
55+
<Link
56+
href="/link/rewrite-me-fullystatic"
57+
data-link="NextResponse.rewrite()#fullyStatic"
58+
>
59+
fullyStatic
60+
</Link>
61+
</li>
62+
</ul>
63+
</li>
64+
</ul>
65+
</div>
66+
)
67+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Page() {
2+
return (
3+
<div data-page="NextResponse.next()#fullyStatic">
4+
<h1>fully static page</h1>
5+
</div>
6+
)
7+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default function Page() {
2+
return (
3+
<div data-page="NextResponse.next()#getServerSideProps">
4+
<h1>
5+
<code>getServerSideProps</code> page
6+
</h1>
7+
</div>
8+
)
9+
}
10+
11+
export function getServerSideProps() {
12+
return {
13+
props: {},
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default function Page() {
2+
return (
3+
<div data-page="NextResponse.next()#getStaticProps">
4+
<h1>
5+
<code>getStaticProps</code> page
6+
</h1>
7+
</div>
8+
)
9+
}
10+
11+
export function getStaticProps() {
12+
return {
13+
props: {},
14+
}
15+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Page() {
2+
return (
3+
<div data-page="NextResponse.rewrite()#fullyStatic">
4+
<h1>fully static page</h1>
5+
</div>
6+
)
7+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default function Page() {
2+
return (
3+
<div data-page="NextResponse.rewrite()#getServerSideProps">
4+
<h1>
5+
<code>getServerSideProps</code> page
6+
</h1>
7+
</div>
8+
)
9+
}
10+
11+
export function getServerSideProps() {
12+
return {
13+
props: {},
14+
}
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default function Page() {
2+
return (
3+
<div data-page="NextResponse.rewrite()#getStaticProps">
4+
<h1>
5+
<code>getStaticProps</code> page
6+
</h1>
7+
</div>
8+
)
9+
}
10+
11+
export function getStaticProps() {
12+
return {
13+
props: {},
14+
}
15+
}

tests/fixtures/middleware-pages/middleware.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { NextResponse, URLPattern } from 'next/server'
22

3+
console.log('middleware.js loaded')
4+
35
export async function middleware(request) {
46
const url = request.nextUrl
57

@@ -8,6 +10,26 @@ export async function middleware(request) {
810
return NextResponse.next()
911
}
1012

13+
if (url.pathname.startsWith('/link/next')) {
14+
return NextResponse.next({
15+
headers: {
16+
'x-middleware-test': 'link-next',
17+
},
18+
})
19+
}
20+
21+
if (url.pathname.startsWith('/link/rewrite-me')) {
22+
const rewriteUrl = new URL(
23+
url.pathname.replace('/link/rewrite-me', '/link/rewrite-target'),
24+
url,
25+
)
26+
return NextResponse.rewrite(rewriteUrl, {
27+
headers: {
28+
'x-middleware-test': 'link-rewrite',
29+
},
30+
})
31+
}
32+
1133
if (request.headers.get('x-prerender-revalidate')) {
1234
return NextResponse.next({
1335
headers: { 'x-middleware': 'hi' },

0 commit comments

Comments
 (0)