Skip to content

Commit

Permalink
propagate notFound errors past a segment's error boundary
Browse files Browse the repository at this point in the history
  • Loading branch information
ztanner committed Jan 12, 2024
1 parent 4640ed0 commit dab9038
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 14 deletions.
7 changes: 7 additions & 0 deletions packages/next/src/client/components/error-boundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import React from 'react'
import { usePathname } from './navigation'
import { isNextRouterError } from './is-next-router-error'

const styles = {
error: {
Expand Down Expand Up @@ -73,6 +74,12 @@ export class ErrorBoundaryHandler extends React.Component<
}

static getDerivedStateFromError(error: Error) {
if (isNextRouterError(error)) {
// Re-throw if an expected internal Next.js router error occurs
// this means it should be handled by a different boundary (such as a NotFound boundary in a parent segment)
throw error
}

return { error }
}

Expand Down
14 changes: 0 additions & 14 deletions test/e2e/app-dir/not-found-default/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,6 @@ createNextDescribe(
)
return 'success'
}, /success/)
} else {
expect(await browser.elementByCss('h2').text()).toBe(
'Application error: a server-side exception has occurred (see the server logs for more information).'
)
expect(await browser.elementByCss('p').text()).toBe(
'Digest: NEXT_NOT_FOUND'
)
}
})

Expand All @@ -54,13 +47,6 @@ createNextDescribe(
expect(await getRedboxDescription(browser)).toBe(
'Error: notFound() is not allowed to use in root layout'
)
} else {
expect(await browser.elementByCss('h2').text()).toBe(
'Application error: a server-side exception has occurred (see the server logs for more information).'
)
expect(await browser.elementByCss('p').text()).toBe(
'Digest: NEXT_NOT_FOUND'
)
}
})

Expand Down
4 changes: 4 additions & 0 deletions test/e2e/app-dir/not-found/basic/app/error-boundary/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
'use client'
export default function Error() {
return <div>There was an error</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { notFound } from 'next/navigation'
import React from 'react'

export default function Page({ params }) {
if (params.dynamic === 'trigger-not-found') {
notFound()
}

return <div>Hello World</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
'use client'
export default function Error() {
return <div>There was an error</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client'
import { notFound } from 'next/navigation'
import React from 'react'
export default function Page() {
const [shouldError, setShouldError] = React.useState(false)
if (shouldError) {
notFound()
}
return (
<button
onClick={() => {
setShouldError(true)
}}
>
Trigger Not Found
</button>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return <h1>Not Found (error-boundary/nested)</h1>
}
18 changes: 18 additions & 0 deletions test/e2e/app-dir/not-found/basic/app/error-boundary/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client'
import { notFound } from 'next/navigation'
import React from 'react'
export default function Page() {
const [shouldError, setShouldError] = React.useState(false)
if (shouldError) {
notFound()
}
return (
<button
onClick={() => {
setShouldError(true)
}}
>
Trigger Not Found
</button>
)
}
17 changes: 17 additions & 0 deletions test/e2e/app-dir/not-found/basic/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ createNextDescribe(
skipDeployment: true,
},
({ next, isNextDev, isNextStart }) => {
it("should propagate notFound errors past a segment's error boundary", async () => {
let browser = await next.browser('/error-boundary')
await browser.elementByCss('button').click()
expect(await browser.elementByCss('h1').text()).toBe('Root Not Found')

browser = await next.browser('/error-boundary/nested/nested-2')
await browser.elementByCss('button').click()
expect(await browser.elementByCss('h1').text()).toBe(
'Not Found (error-boundary/nested)'
)

browser = await next.browser('/error-boundary/nested/trigger-not-found')
expect(await browser.elementByCss('h1').text()).toBe(
'Not Found (error-boundary/nested)'
)
})

if (isNextStart) {
it('should include not found client reference manifest in the file trace', async () => {
const fileTrace = JSON.parse(
Expand Down

0 comments on commit dab9038

Please sign in to comment.