Files
next.js/test/e2e/app-dir/interception-segments-two-levels-above/interception-segments-two-levels-above.test.ts
Wyatt JohnsonandGitHub dc61d29e49 Interception routes match from nested route navigation (#84898)
### What?

Refactors interception route regex generation to fix nested route
navigation and improve maintainability.

### Why?

Interception routes failed to trigger when navigating from nested
descendant routes. The previous implementation had overly complex,
fragile regex patterns spread across multiple functions that were
difficult to maintain and didn't handle all navigation scenarios
correctly.

The root cause was an overly restrictive header matching pattern
(`/[^/]+` - single segment only) that prevented matching navigation from
deeper nested routes like `/groups/123/settings` → `/groups/123/new`.

### How?

**Simplified Architecture:**
- Consolidated regex generation logic into `route-regex.ts` where it
properly belongs
- Removed ~230 lines of complex, duplicated regex building code from
`generate-interception-routes-rewrites.ts`
- Leveraged existing `getNamedRouteRegex()` with a new `reference`
parameter to handle parameter name mapping

**Parameter Naming Fix:**
- Introduced `nxtI` prefix for parameters adjacent to interception
markers (e.g., `(.)[id]` → `nxtIid`)
- Maintains `nxtP` prefix for regular parameters
- Ensures consistent parameter naming across source, destination, and
regex patterns

**Regex Pattern Fix:**
- Changed header matching from single-segment (`/[^/]+)?` to
multi-segment `(/.+)?` pattern
- Now correctly matches navigation from any descendant route depth

**Test Coverage:**
- Added comprehensive e2e tests for nested navigation scenarios
- Updated existing tests to reflect new parameter naming convention

Fixes #84813

NAR-445
2025-10-16 16:58:09 -06:00

74 lines
2.0 KiB
TypeScript

import { nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'
describe('interception-segments-two-levels-above', () => {
const { next } = nextTestSetup({
files: __dirname,
})
it('should work when interception route is paired with segments two levels above', async () => {
const browser = await next.browser('/foo/bar')
await browser.elementByCss('[href="/hoge"]').click()
await retry(async () => {
expect(await browser.elementById('intercepted').text()).toMatch(
/intercepted/
)
})
})
it('should intercept consistently with back/forward navigation', async () => {
// Test that interception works correctly with browser back/forward
const browser = await next.browser('/foo/bar')
// Navigate with interception
await browser.elementByCss('[href="/hoge"]').click()
await retry(async () => {
expect(await browser.elementById('intercepted').text()).toMatch(
/intercepted/
)
})
// Go back
await browser.back()
await retry(async () => {
const url = await browser.url()
expect(url).toContain('/foo/bar')
})
// Go forward - should show the intercepted version again
await browser.forward()
await retry(async () => {
expect(await browser.elementById('intercepted').text()).toMatch(
/intercepted/
)
})
})
it('should intercept multiple times from same route', async () => {
// Test that repeated interception works
const browser = await next.browser('/foo/bar')
for (let i = 0; i < 2; i++) {
await retry(async () => {
await browser.elementByCss('[href="/hoge"]').click()
})
await retry(async () => {
expect(await browser.elementById('intercepted').text()).toMatch(
/intercepted/
)
})
await browser.back()
await retry(async () => {
const url = await browser.url()
expect(url).toContain('/foo/bar')
await browser.elementByCss('[href="/hoge"]')
})
}
})
})