From f9a4d5cac87e80834c4091e056c8a638fb8ca735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Tue, 10 May 2022 14:23:56 +0200 Subject: [PATCH 1/3] Don't convert errors to string --- packages/next/build/output/log.ts | 14 +++++++------- packages/next/server/dev/next-dev-server.ts | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/next/build/output/log.ts b/packages/next/build/output/log.ts index 9220fe1834e3..bbf520da350d 100644 --- a/packages/next/build/output/log.ts +++ b/packages/next/build/output/log.ts @@ -10,30 +10,30 @@ export const prefixes = { trace: chalk.magenta('trace') + ' -', } -export function wait(...message: string[]) { +export function wait(...message: any[]) { console.log(prefixes.wait, ...message) } -export function error(...message: string[]) { +export function error(...message: any[]) { console.error(prefixes.error, ...message) } -export function warn(...message: string[]) { +export function warn(...message: any[]) { console.warn(prefixes.warn, ...message) } -export function ready(...message: string[]) { +export function ready(...message: any[]) { console.log(prefixes.ready, ...message) } -export function info(...message: string[]) { +export function info(...message: any[]) { console.log(prefixes.info, ...message) } -export function event(...message: string[]) { +export function event(...message: any[]) { console.log(prefixes.event, ...message) } -export function trace(...message: string[]) { +export function trace(...message: any[]) { console.log(prefixes.trace, ...message) } diff --git a/packages/next/server/dev/next-dev-server.ts b/packages/next/server/dev/next-dev-server.ts index 7a5c28597ddd..f9e75f2b9202 100644 --- a/packages/next/server/dev/next-dev-server.ts +++ b/packages/next/server/dev/next-dev-server.ts @@ -751,11 +751,11 @@ export default class DevServer extends Server { if (!usedOriginalStack) { if (type === 'warning') { - Log.warn(err + '') + Log.warn(err) } else if (type) { - Log.error(`${type}:`, err + '') + Log.error(`${type}:`, err) } else { - Log.error(err + '') + Log.error(err) } } } From 6f91622e5aea7d682fb1e21a69e3e43f1b9c8c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Wed, 11 May 2022 11:28:08 +0200 Subject: [PATCH 2/3] regression test --- test/integration/custom-server/server.js | 5 +++++ .../custom-server/test/index.test.js | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/test/integration/custom-server/server.js b/test/integration/custom-server/server.js index 29550fb1906f..94d244235665 100644 --- a/test/integration/custom-server/server.js +++ b/test/integration/custom-server/server.js @@ -18,6 +18,11 @@ app.prepare().then(() => { return app.render(req, res, '/no-query') } + if (req.url === '/unhandled-rejection') { + Promise.reject(new Error('unhandled rejection')) + return res.end('ok') + } + if (/setAssetPrefix/.test(req.url)) { app.setAssetPrefix(`http://127.0.0.1:${port}`) } else if (/setEmptyAssetPrefix/.test(req.url)) { diff --git a/test/integration/custom-server/test/index.test.js b/test/integration/custom-server/test/index.test.js index 8d4e2ee70311..c30ce36049d6 100644 --- a/test/integration/custom-server/test/index.test.js +++ b/test/integration/custom-server/test/index.test.js @@ -216,4 +216,26 @@ describe('Custom Server', () => { expect(data).toMatch(/hello world/) }) }) + + describe('unhandled rejection', () => { + afterEach(() => killApp(server)) + + it('stderr should include error message and stack trace', async () => { + let stderr = '' + await startServer( + {}, + { + onStderr(msg) { + stderr += msg || '' + }, + } + ) + await fetchViaHTTP(appPort, '/unhandled-rejection') + await check(() => stderr, /unhandledRejection/) + expect(stderr).toContain( + 'error - unhandledRejection: Error: unhandled rejection' + ) + expect(stderr).toContain('server.js:22:22') + }) + }) }) From fd4700d3c43ee46b823baf4eba098190788dfd34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Born=C3=B6?= Date: Wed, 11 May 2022 15:04:46 +0200 Subject: [PATCH 3/3] Fix error message for empty errors --- packages/next/server/dev/next-dev-server.ts | 2 +- .../pages/uncaught-empty-exception.js | 12 +++++++ .../pages/uncaught-empty-rejection.js | 12 +++++++ .../server-side-dev-errors/test/index.test.js | 33 +++++++++++++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 test/integration/server-side-dev-errors/pages/uncaught-empty-exception.js create mode 100644 test/integration/server-side-dev-errors/pages/uncaught-empty-rejection.js diff --git a/packages/next/server/dev/next-dev-server.ts b/packages/next/server/dev/next-dev-server.ts index f9e75f2b9202..91222ebabe7d 100644 --- a/packages/next/server/dev/next-dev-server.ts +++ b/packages/next/server/dev/next-dev-server.ts @@ -693,7 +693,7 @@ export default class DevServer extends Server { ) { let usedOriginalStack = false - if (isError(err) && err.name && err.stack && err.message) { + if (isError(err) && err.stack) { try { const frames = parseStack(err.stack!) const frame = frames[0] diff --git a/test/integration/server-side-dev-errors/pages/uncaught-empty-exception.js b/test/integration/server-side-dev-errors/pages/uncaught-empty-exception.js new file mode 100644 index 000000000000..8674cae72bda --- /dev/null +++ b/test/integration/server-side-dev-errors/pages/uncaught-empty-exception.js @@ -0,0 +1,12 @@ +export default function Page() { + return

getServerSideProps page

+} + +export async function getServerSideProps() { + setTimeout(() => { + throw new Error() + }, 10) + return { + props: {}, + } +} diff --git a/test/integration/server-side-dev-errors/pages/uncaught-empty-rejection.js b/test/integration/server-side-dev-errors/pages/uncaught-empty-rejection.js new file mode 100644 index 000000000000..ca00826da1e7 --- /dev/null +++ b/test/integration/server-side-dev-errors/pages/uncaught-empty-rejection.js @@ -0,0 +1,12 @@ +export default function Page() { + return

getServerSideProps page

+} + +export async function getServerSideProps() { + setTimeout(() => { + Promise.reject(new Error()) + }, 10) + return { + props: {}, + } +} diff --git a/test/integration/server-side-dev-errors/test/index.test.js b/test/integration/server-side-dev-errors/test/index.test.js index f2570ffcd184..272ac54af423 100644 --- a/test/integration/server-side-dev-errors/test/index.test.js +++ b/test/integration/server-side-dev-errors/test/index.test.js @@ -11,6 +11,7 @@ import { hasRedbox, getRedboxSource, } from 'next-test-utils' +import stripAnsi from 'strip-ansi' const appDir = join(__dirname, '../') const gspPage = join(appDir, 'pages/gsp.js') @@ -213,6 +214,22 @@ describe('server-side dev errors', () => { }, 'success') }) + it('should show server-side error for uncaught empty rejection correctly', async () => { + const stderrIdx = stderr.length + await webdriver(appPort, '/uncaught-empty-rejection') + + await check(async () => { + const cleanStderr = stripAnsi(stderr.slice(stderrIdx)) + + return cleanStderr.includes('pages/uncaught-empty-rejection.js') && + cleanStderr.includes('7:19') && + cleanStderr.includes('getServerSideProps') && + cleanStderr.includes('new Error()') + ? 'success' + : cleanStderr + }, 'success') + }) + it('should show server-side error for uncaught exception correctly', async () => { const stderrIdx = stderr.length await webdriver(appPort, '/uncaught-exception') @@ -228,4 +245,20 @@ describe('server-side dev errors', () => { : err }, 'success') }) + + it('should show server-side error for uncaught empty exception correctly', async () => { + const stderrIdx = stderr.length + await webdriver(appPort, '/uncaught-empty-exception') + + await check(async () => { + const cleanStderr = stripAnsi(stderr.slice(stderrIdx)) + + return cleanStderr.includes('pages/uncaught-empty-exception.js') && + cleanStderr.includes('7:10') && + cleanStderr.includes('getServerSideProps') && + cleanStderr.includes('new Error()') + ? 'success' + : cleanStderr + }, 'success') + }) })