Skip to content

Commit 482ed70

Browse files
committed
test: improved test reliability
1 parent a6189bb commit 482ed70

File tree

5 files changed

+193
-70
lines changed

5 files changed

+193
-70
lines changed

packages/next/src/build/validate-app-paths.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,10 @@ function normalizeSegments(
176176
return segment.name
177177
}
178178

179-
// Dynamic segment - normalize the parameter name by replacing the parameter name with a wildcard
180-
const name = segment.name.replace(segment.param.param, '*')
181-
182-
// Prepend marker if present on the segment
183-
return segment.interceptionMarker
184-
? `${segment.interceptionMarker}${name}`
185-
: name
179+
// Dynamic segment - normalize the parameter name by replacing the
180+
// parameter name with a wildcard. The interception marker is already
181+
// included in the segment name, so no special handling is needed.
182+
return segment.name.replace(segment.param.param, '*')
186183
})
187184
.join('/')
188185
)

test/e2e/app-dir/app-client-cache/client-cache.parallel-routes.test.ts

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { nextTestSetup } from 'e2e-utils'
22
import { createRouterAct } from 'router-act'
33
import { browserConfigWithFixedTime, fastForwardTo } from './test-utils'
44
import path from 'path'
5+
import { Playwright } from 'next-webdriver'
56

67
describe('app dir client cache with parallel routes', () => {
78
const { next, isNextDev } = nextTestSetup({
@@ -14,6 +15,18 @@ describe('app dir client cache with parallel routes', () => {
1415
return
1516
}
1617

18+
async function reveal(browser: Playwright, href: string) {
19+
// Get the reveal element and scroll it into view.
20+
const reveal = await browser.elementByCss(`[data-link-accordion="${href}"]`)
21+
await reveal.scrollIntoViewIfNeeded()
22+
23+
// Click the reveal element to reveal the content.
24+
await reveal.click()
25+
26+
// Return the anchor link element.
27+
return browser.elementByCss(`a[href="${href}"]`)
28+
}
29+
1730
describe('prefetch={true}', () => {
1831
it('should prefetch the full page', async () => {
1932
let act: ReturnType<typeof createRouterAct>
@@ -27,11 +40,7 @@ describe('app dir client cache with parallel routes', () => {
2740
// Reveal the link to trigger prefetch and wait for it to complete
2841
const link = await act(
2942
async () => {
30-
const reveal = await browser.elementByCss(
31-
'[data-link-accordion="/0"]'
32-
)
33-
await reveal.click()
34-
return await browser.elementByCss('[href="/0"]')
43+
return reveal(browser, '/0')
3544
},
3645
{ includes: 'random-number' }
3746
)
@@ -55,11 +64,8 @@ describe('app dir client cache with parallel routes', () => {
5564
// Toggle the link, assert on the prefetch content
5665
const link = await act(
5766
async () => {
58-
const reveal = await browser.elementByCss(
59-
'[data-link-accordion="/0"]'
60-
)
61-
await reveal.click()
62-
return await browser.elementByCss('[href="/0"]')
67+
await reveal(browser, '/0')
68+
return browser.elementByCss('[href="/0"]')
6369
},
6470
{ includes: 'random-number' }
6571
)
@@ -68,15 +74,13 @@ describe('app dir client cache with parallel routes', () => {
6874
const randomNumber = await act(async () => {
6975
await link.click()
7076
await browser.waitForElementByCss('#random-number')
71-
return await browser.elementByCss('#random-number').text()
77+
return browser.elementByCss('#random-number').text()
7278
}, 'no-requests')
7379

7480
// Toggle the home link, assert on the homepage content
7581
const homeLink = await act(
7682
async () => {
77-
const reveal = await browser.elementByCss('[data-link-accordion="/"]')
78-
await reveal.click()
79-
return await browser.elementByCss('[href="/"]')
83+
return reveal(browser, '/')
8084
},
8185
{ includes: 'home-page' }
8286
)
@@ -89,22 +93,18 @@ describe('app dir client cache with parallel routes', () => {
8993

9094
// Toggle the link to the other page again, navigate, assert no requests (because it's cached)
9195
const number = await act(async () => {
92-
const reveal = await browser.elementByCss('[data-link-accordion="/0"]')
93-
await reveal.click()
94-
const link = await browser.elementByCss('[href="/0"]')
96+
const link = await reveal(browser, '/0')
9597
await link.click()
9698
await browser.waitForElementByCss('#random-number')
97-
return await browser.elementByCss('#random-number').text()
99+
return browser.elementByCss('#random-number').text()
98100
}, 'no-requests')
99101

100102
expect(number).toBe(randomNumber)
101103

102104
// Navigate back home
103105
await act(async () => {
104-
const reveal = await browser.elementByCss('[data-link-accordion="/"]')
105-
await reveal.click()
106-
const homeLink = await browser.elementByCss('[href="/"]')
107-
await homeLink.click()
106+
const link = await reveal(browser, '/')
107+
await link.click()
108108
await browser.waitForElementByCss('#home-page')
109109
}, 'no-requests')
110110

@@ -114,11 +114,7 @@ describe('app dir client cache with parallel routes', () => {
114114
// Toggle the link to the other page again, assert on prefetch content
115115
const linkAfterExpiry = await act(
116116
async () => {
117-
const reveal = await browser.elementByCss(
118-
'[data-link-accordion="/0"]'
119-
)
120-
await reveal.click()
121-
return await browser.elementByCss('[href="/0"]')
117+
return reveal(browser, '/0')
122118
},
123119
{ includes: 'random-number' }
124120
)
@@ -127,7 +123,7 @@ describe('app dir client cache with parallel routes', () => {
127123
const newNumber = await act(async () => {
128124
await linkAfterExpiry.click()
129125
await browser.waitForElementByCss('#random-number')
130-
return await browser.elementByCss('#random-number').text()
126+
return browser.elementByCss('#random-number').text()
131127
}, 'no-requests')
132128

133129
expect(newNumber).not.toBe(randomNumber)
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
'use client'
2+
3+
import Link from 'next/link'
4+
import { useState } from 'react'
5+
6+
export function LinkAccordion({ href }: { href: string }) {
7+
const [isOpen, setIsOpen] = useState(false)
8+
9+
return (
10+
<div
11+
data-testid="link-accordion"
12+
data-href={href}
13+
style={{
14+
border: '1px solid #e5e7eb',
15+
borderRadius: '12px',
16+
padding: '16px',
17+
margin: '12px 0',
18+
backgroundColor: 'white',
19+
boxShadow:
20+
'0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
21+
transition: 'all 0.2s ease',
22+
cursor: 'pointer',
23+
}}
24+
>
25+
<div
26+
style={{
27+
display: 'flex',
28+
justifyContent: 'space-between',
29+
alignItems: 'center',
30+
gap: '12px',
31+
}}
32+
>
33+
<div
34+
style={{
35+
fontFamily: 'monospace',
36+
fontSize: '14px',
37+
color: '#374151',
38+
fontWeight: '500',
39+
flex: 1,
40+
}}
41+
>
42+
{href}
43+
</div>
44+
{!isOpen && (
45+
<button
46+
onClick={() => setIsOpen(true)}
47+
style={{
48+
padding: '8px 16px',
49+
borderRadius: '8px',
50+
border: 'none',
51+
backgroundColor: '#3b82f6',
52+
color: 'white',
53+
fontSize: '14px',
54+
fontWeight: '600',
55+
cursor: 'pointer',
56+
transition: 'all 0.2s ease',
57+
display: 'flex',
58+
alignItems: 'center',
59+
gap: '6px',
60+
}}
61+
>
62+
<span></span>
63+
Open
64+
</button>
65+
)}
66+
</div>
67+
{isOpen && (
68+
<div
69+
style={{
70+
marginTop: '16px',
71+
paddingTop: '16px',
72+
borderTop: '1px solid #e5e7eb',
73+
}}
74+
>
75+
<Link
76+
href={href}
77+
style={{
78+
display: 'inline-block',
79+
padding: '10px 20px',
80+
backgroundColor: '#10b981',
81+
color: 'white',
82+
textDecoration: 'none',
83+
borderRadius: '8px',
84+
fontSize: '14px',
85+
fontWeight: '600',
86+
}}
87+
>
88+
Navigate to {href}
89+
</Link>
90+
</div>
91+
)}
92+
</div>
93+
)
94+
}

test/e2e/app-dir/interception-dynamic-segment/app/page.tsx

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Link from 'next/link'
1+
import { LinkAccordion } from './page.client'
22

33
export default function Page() {
44
return (
@@ -8,17 +8,15 @@ export default function Page() {
88

99
<div>
1010
<h3>Test Case 1a: Simple page (no parallel routes)</h3>
11-
<Link href="/simple-page" style={{ color: 'blue', fontSize: '16px' }}>
12-
→ /simple-page
13-
</Link>
11+
<LinkAccordion href="/simple-page" />
1412
<p>
1513
Interception route with just a page.tsx, no parallel routes at all.
1614
</p>
1715
</div>
1816

1917
<div>
2018
<h3>Test Case 1b: Has page.tsx</h3>
21-
<Link href="/has-page">→ /has-page</Link>
19+
<LinkAccordion href="/has-page" />
2220
<p>
2321
Interception route has page.tsx at root level. No children slot
2422
exists.
@@ -27,15 +25,13 @@ export default function Page() {
2725

2826
<div>
2927
<h3>Test Case 2: No parallel routes</h3>
30-
<Link href="/no-parallel-routes/deeper">
31-
→ /no-parallel-routes/deeper
32-
</Link>
28+
<LinkAccordion href="/no-parallel-routes/deeper" />
3329
<p>No @parallel routes exist, so no implicit layout created.</p>
3430
</div>
3531

3632
<div>
3733
<h3>Test Case 3: Has both @sidebar AND page.tsx</h3>
38-
<Link href="/has-both">→ /has-both</Link>
34+
<LinkAccordion href="/has-both" />
3935
<p>
4036
Has @sidebar parallel route BUT page.tsx fills the children slot.
4137
</p>
@@ -47,14 +43,14 @@ export default function Page() {
4743

4844
<div>
4945
<h3>Test Case 4a: Has @sidebar but NO page.tsx (implicit layout)</h3>
50-
<Link href="/test-nested">→ /test-nested</Link>
46+
<LinkAccordion href="/test-nested" />
5147
<p>Has @sidebar (creates implicit layout) but NO page.tsx.</p>
5248
<p>✓ Auto-uses null default (no explicit files needed)</p>
5349
</div>
5450

5551
<div>
5652
<h3>Test Case 4b: Has explicit layout.tsx but NO parallel routes</h3>
57-
<Link href="/explicit-layout/deeper">→ /explicit-layout/deeper</Link>
53+
<LinkAccordion href="/explicit-layout/deeper" />
5854
<p>
5955
Has explicit layout.tsx with children slot, but NO parallel routes
6056
like @sidebar.
@@ -69,18 +65,16 @@ export default function Page() {
6965
<h2>Original Tests</h2>
7066
<ul>
7167
<li>
72-
<Link href="/foo/1">/foo/1</Link>
68+
<LinkAccordion href="/foo/1" />
7369
</li>
7470
<li>
75-
<Link href="/bar/1">/bar/1</Link>
71+
<LinkAccordion href="/bar/1" />
7672
</li>
7773
<li>
78-
<Link href="/test-nested/deeper">/test-nested/deeper</Link>
74+
<LinkAccordion href="/test-nested/deeper" />
7975
</li>
8076
<li>
81-
<Link href="/generate-static-params/foo">
82-
/generate-static-params/foo
83-
</Link>
77+
<LinkAccordion href="/generate-static-params/foo" />
8478
</li>
8579
</ul>
8680
</section>

0 commit comments

Comments
 (0)