From d29ca1a609d6f09e28682204ddb8a1529497f3f4 Mon Sep 17 00:00:00 2001 From: Sebastian Sebbie Silbermann Date: Tue, 27 May 2025 12:51:43 +0200 Subject: [PATCH] [dev-overlay] Show error overlay on any thrown value in /app --- .changeset/smooth-bears-run.md | 8 ++++++++ .../app/app-dev-overlay-error-boundary.tsx | 16 +++++----------- .../react-dev-overlay/app/app-dev-overlay.tsx | 2 +- .../acceptance-app/hydration-error.test.ts | 6 +++--- .../serialize-circular-error.test.ts | 14 ++++++++++---- 5 files changed, 27 insertions(+), 19 deletions(-) create mode 100644 .changeset/smooth-bears-run.md diff --git a/.changeset/smooth-bears-run.md b/.changeset/smooth-bears-run.md new file mode 100644 index 000000000000..2a2ea3b1c035 --- /dev/null +++ b/.changeset/smooth-bears-run.md @@ -0,0 +1,8 @@ +--- +'next': patch +--- + +[dev-overlay] Show error overlay on any thrown value + +We used to only show the error overlay on thrown values with a stack property. +On other thrown values we kept the overlay collapsed. diff --git a/packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay-error-boundary.tsx b/packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay-error-boundary.tsx index 88a529ee6431..ce005e6a2262 100644 --- a/packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay-error-boundary.tsx +++ b/packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay-error-boundary.tsx @@ -8,11 +8,10 @@ import DefaultGlobalError, { type AppDevOverlayErrorBoundaryProps = { children: React.ReactNode globalError: [GlobalErrorComponent, React.ReactNode] - onError: (value: boolean) => void + onError: () => void } type AppDevOverlayErrorBoundaryState = { - isReactError: boolean reactError: unknown } @@ -43,33 +42,28 @@ export class AppDevOverlayErrorBoundary extends PureComponent< AppDevOverlayErrorBoundaryProps, AppDevOverlayErrorBoundaryState > { - state = { isReactError: false, reactError: null } + state = { reactError: null } static getDerivedStateFromError(error: Error) { - if (!error.stack) { - return { isReactError: false, reactError: null } - } - RuntimeErrorHandler.hadRuntimeError = true return { - isReactError: true, reactError: error, } } componentDidCatch() { - this.props.onError(this.state.isReactError) + this.props.onError() } render() { const { children, globalError } = this.props - const { isReactError, reactError } = this.state + const { reactError } = this.state const fallback = ( ) - return isReactError ? fallback : children + return reactError !== null ? fallback : children } } diff --git a/packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay.tsx b/packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay.tsx index 72958ff9a472..46d256572ae2 100644 --- a/packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay.tsx +++ b/packages/next/src/client/components/react-dev-overlay/app/app-dev-overlay.tsx @@ -86,7 +86,7 @@ export function AppDevOverlay({ <> {children} diff --git a/test/development/acceptance-app/hydration-error.test.ts b/test/development/acceptance-app/hydration-error.test.ts index 16e9d9365c55..d26e9c790f18 100644 --- a/test/development/acceptance-app/hydration-error.test.ts +++ b/test/development/acceptance-app/hydration-error.test.ts @@ -210,7 +210,7 @@ describe('Error overlay for hydration errors in App router', () => { "componentStack": "... - + }> @@ -246,7 +246,7 @@ describe('Error overlay for hydration errors in App router', () => { "componentStack": "... - + }> @@ -1046,7 +1046,7 @@ describe('Error overlay for hydration errors in App router', () => { "componentStack": "... - + }> diff --git a/test/development/app-dir/serialize-circular-error/serialize-circular-error.test.ts b/test/development/app-dir/serialize-circular-error/serialize-circular-error.test.ts index 2161cbc39ac8..26cfcfbf9341 100644 --- a/test/development/app-dir/serialize-circular-error/serialize-circular-error.test.ts +++ b/test/development/app-dir/serialize-circular-error/serialize-circular-error.test.ts @@ -1,5 +1,4 @@ import { nextTestSetup } from 'e2e-utils' -import { assertNoRedbox } from 'next-test-utils' describe('serialize-circular-error', () => { const { next } = nextTestSetup({ @@ -27,9 +26,16 @@ describe('serialize-circular-error', () => { it('should serialize the object from client component in console correctly', async () => { const browser = await next.browser('/client') - // It's not a valid error object, it will display the global-error instead of the error overlay - // TODO: handle the error object in the client-side - await assertNoRedbox(browser) + // TODO: Format arbitrary messages in Redbox + await expect(browser).toDisplayRedbox(` + { + "description": "[object Object]", + "environmentLabel": null, + "label": "Runtime Error", + "source": null, + "stack": [], + } + `) const bodyText = await browser.elementByCss('body').text() expect(bodyText).toContain(