diff --git a/packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/index.tsx b/packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/index.tsx index a168c5bc38888..f86a0170633f1 100644 --- a/packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/index.tsx +++ b/packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/index.tsx @@ -16,7 +16,7 @@ export function RuntimeError({ error }: RuntimeErrorProps) { !( f.sourceStackFrame.file === '' && ['stringify', ''].includes(f.sourceStackFrame.methodName) - ) + ) && !f.sourceStackFrame.file?.startsWith('node:internal') ) const firstFirstPartyFrameIndex = filteredFrames.findIndex( diff --git a/test/development/acceptance-app/ReactRefreshLogBox.test.ts b/test/development/acceptance-app/ReactRefreshLogBox.test.ts index 1f12763c75138..5a80e3702783d 100644 --- a/test/development/acceptance-app/ReactRefreshLogBox.test.ts +++ b/test/development/acceptance-app/ReactRefreshLogBox.test.ts @@ -839,7 +839,7 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox app %s', () => { await cleanup() }) - test('stringify and are hidden in stack trace', async () => { + test('useless frames are hidden in stack trace', async () => { const { session, browser, cleanup } = await sandbox( next, new Map([ @@ -849,6 +849,7 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox app %s', () => { export default function Page() { const e = new Error("Boom!"); e.stack += \` + // REVIEW: how to reliably test the presence of these stack frames? at stringify () at () at foo (bar:1:1)\`; @@ -860,13 +861,34 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox app %s', () => { ) expect(await session.hasRedbox()).toBe(true) await expandCallStack(browser) - const callStackFrames = await browser.elementsByCss( + let callStackFrames = await browser.elementsByCss( '[data-nextjs-call-stack-frame]' ) - const texts = await Promise.all(callStackFrames.map((f) => f.innerText())) + let texts = await Promise.all(callStackFrames.map((f) => f.innerText())) expect(texts).not.toContain('stringify\n') expect(texts).not.toContain('\n') expect(texts).toContain('foo\nbar (1:1)') + + // Test that node:internal errors should be hidden + + next.patchFile( + 'app/page.js', + // Node.js will throw an error about the invalid URL since this is a server component + outdent` + export default function Page() { + new URL("/", "invalid"); + }` + ) + + expect(await session.hasRedbox()).toBe(true) + await expandCallStack(browser) + callStackFrames = await browser.elementsByCss( + '[data-nextjs-call-stack-frame]' + ) + texts = await Promise.all(callStackFrames.map((f) => f.innerText())) + + expect(texts.filter((t) => t.includes('node:internal'))).toHaveLength(0) + await cleanup() }) diff --git a/test/development/acceptance/ReactRefreshLogBox.test.ts b/test/development/acceptance/ReactRefreshLogBox.test.ts index 562a415d44b88..3c6234ea43703 100644 --- a/test/development/acceptance/ReactRefreshLogBox.test.ts +++ b/test/development/acceptance/ReactRefreshLogBox.test.ts @@ -784,34 +784,59 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox %s', () => { await cleanup() }) - test('stringify and are hidden in stack trace for pages error', async () => { + test('useless frames are hidden in stack trace for pages error', async () => { const { session, browser, cleanup } = await sandbox( next, new Map([ [ 'pages/index.js', outdent` - export default function Page() { - const e = new Error("Client error!"); - e.stack += \` + export default function Page() { + const e = new Error("Client error!"); + e.stack += \` + // REVIEW: how to reliably test the presence of these stack frames? at stringify () at () at foo (bar:1:1)\`; throw e; } - `, + `, ], ]) ) expect(await session.hasRedbox()).toBe(true) await expandCallStack(browser) - const callStackFrames = await browser.elementsByCss( + let callStackFrames = await browser.elementsByCss( '[data-nextjs-call-stack-frame]' ) - const texts = await Promise.all(callStackFrames.map((f) => f.innerText())) + let texts = await Promise.all(callStackFrames.map((f) => f.innerText())) expect(texts).not.toContain('stringify\n') expect(texts).not.toContain('\n') expect(texts).toContain('foo\nbar (1:1)') + + // Test that node:internal errors should be hidden + + next.patchFile( + 'pages/index.js', + // Node.js will throw an error about the invalid URL since it happens server-side + outdent` + export default function Page() {} + + export function getServerSideProps() { + new URL("/", "invalid"); + return { props: {} }; + }` + ) + + expect(await session.hasRedbox()).toBe(true) + await expandCallStack(browser) + callStackFrames = await browser.elementsByCss( + '[data-nextjs-call-stack-frame]' + ) + texts = await Promise.all(callStackFrames.map((f) => f.innerText())) + + expect(texts.filter((t) => t.includes('node:internal'))).toHaveLength(0) + await cleanup() }) })