rsnext/test/e2e/app-dir/parallel-route-not-found-params/parallel-route-not-found-params.test.ts
Zack Tanner 1481b2649f
Fix TypeError when using params in RootLayout with parallel routes (#60401)
### What?
When accessing `params` on a `RootLayout`, while also using parallel
routes, two potential errors would occur:
- A `Warning: React.createElement: type is invalid` error when
attempting to render a `NotFound` component that doesn't exist
- A `TypeError: Cannot read properties of undefined` error when
attempting to access params in the root layout.

### Why?
`createComponentTree` will render a duplicate `RootLayout` (to ensure
the `notFound()` fallback in unmatched parallel slots have a
`NotFoundBoundary` to catch them) but it currently doesn't ensure a
`NotFound` component exists nor does it forward `params` to the layout.

### How?
This forwards the params to the `RootLayout` and doesn't render a
`NotFoundComponent` if one doesn't exist. This replaces a few `any`
types with more sound types that would have helped catch these mistakes.
There's still a lot more typing that needs to be done (left a comment
below with some additional details) but I opted to make the minimal
changes related to this issue.

Longer term we should remove this duplicate `RootLayout` (see #60220)
which will require special UI to show unmatched slots (similar to the
error overlay, but less harsh)

Closes NEXT-1909
Fixes #59711
2024-01-09 07:06:24 -08:00

73 lines
1.9 KiB
TypeScript

import { createNextDescribe } from 'e2e-utils'
import { check } from 'next-test-utils'
createNextDescribe(
'parallel-route-not-found',
{
files: __dirname,
},
({ next }) => {
it('should behave correctly without any errors', async () => {
const browser = await next.browser('/en')
await check(() => {
if (
next.cliOutput.includes('TypeError') ||
next.cliOutput.includes('Warning')
) {
return 'has-errors'
}
return 'success'
}, 'success')
expect(await browser.elementByCss('body').text()).not.toContain(
'Interception Modal'
)
expect(await browser.elementByCss('body').text()).toContain('Locale: en')
await browser.elementByCss("[href='/en/show']").click()
await check(() => {
if (
next.cliOutput.includes('TypeError') ||
next.cliOutput.includes('Warning')
) {
return 'has-errors'
}
return 'success'
}, 'success')
await check(
() => browser.elementByCss('body').text(),
/Interception Modal/
)
await check(() => browser.elementByCss('body').text(), /Locale: en/)
await browser.refresh()
await check(
() => browser.elementByCss('body').text(),
/Regular Modal Page/
)
await check(() => browser.elementByCss('body').text(), /Locale: en/)
})
it('should handle the not found case correctly without any errors', async () => {
const browser = await next.browser('/de/show')
await check(() => {
if (
next.cliOutput.includes('TypeError') ||
next.cliOutput.includes('Warning')
) {
return 'has-errors'
}
return 'success'
}, 'success')
expect(await browser.elementByCss('body').text()).toContain(
'Custom Not Found'
)
})
}
)