From e279a4ae94f684d9fd07ad2a3f99605d360794b8 Mon Sep 17 00:00:00 2001 From: eps1lon Date: Mon, 9 Dec 2024 22:43:09 +0100 Subject: [PATCH] Add internal `toDisplayRedbox` and `toDisplayCollapsedRedbox` inline snapshot matchers These are meant to replace `assertHasRedbox` over time. We want that every redbox insertion in the future asserts on the full error (message, stack, codeframe) in both browser and terminal. We'll slowly expand usage of these matchers until all use cases are covered at which point the old, granular helpers are removed. The end goal is full confidence in our error display without sacrificing DX for people focused on the error message itself. The downside of inline snapshot matcher that we can't have fine-grained TODO comments. But that's only a concern for the few working on working on the error display infra. The goal here is to encourage using these helpers so the priorities of the few working on error infra is lowest. The most annoying fact is the need for forking assertions between Turbopack and Webpack. All the more reason for us to fix the off-by-one column issues between Turbopack and Webpack. --- package.json | 2 + pnpm-lock.yaml | 10 +- .../acceptance/ReactRefreshLogBox.test.ts | 40 +- .../ReactRefreshLogBox.test.ts.snap | 14 - .../capture-console-error-owner-stack.test.ts | 398 ++++++------------ .../capture-console-error.test.ts | 389 ++++++----------- .../dynamic-io-dev-errors.test.ts | 181 +++++--- .../server-source-maps.test.ts | 38 +- test/jest-setup-after-env.ts | 1 + test/lib/add-redbox-matchers.ts | 192 +++++++++ test/lib/next-test-utils.ts | 59 ++- 11 files changed, 731 insertions(+), 593 deletions(-) create mode 100644 test/lib/add-redbox-matchers.ts diff --git a/package.json b/package.json index 472598b73e998..1eac4071ff568 100644 --- a/package.json +++ b/package.json @@ -154,6 +154,7 @@ "eslint-v8": "npm:eslint@^8.57.0", "event-stream": "4.0.1", "execa": "2.0.3", + "expect": "29.7.0", "expect-type": "0.14.2", "express": "4.17.0", "faker": "5.5.3", @@ -176,6 +177,7 @@ "jest-environment-jsdom": "29.7.0", "jest-extended": "4.0.2", "jest-junit": "16.0.0", + "jest-snapshot": "30.0.0-alpha.6", "json5": "2.2.3", "kleur": "^4.1.0", "ky": "0.19.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ae4fec670be7f..389265023b973 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -291,6 +291,9 @@ importers: execa: specifier: 2.0.3 version: 2.0.3 + expect: + specifier: 29.7.0 + version: 29.7.0 expect-type: specifier: 0.14.2 version: 0.14.2 @@ -357,6 +360,9 @@ importers: jest-junit: specifier: 16.0.0 version: 16.0.0 + jest-snapshot: + specifier: 30.0.0-alpha.6 + version: 30.0.0-alpha.6 json5: specifier: 2.2.3 version: 2.2.3 @@ -19825,7 +19831,7 @@ snapshots: '@types/jest@29.5.5': dependencies: - expect: 29.5.0 + expect: 29.7.0 pretty-format: 29.5.0 '@types/jscodeshift@0.11.0': @@ -25458,7 +25464,7 @@ snapshots: dependencies: '@babel/core': 7.22.5 '@babel/parser': 7.22.5 - '@istanbuljs/schema': 0.1.2 + '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 7.6.3 transitivePeerDependencies: diff --git a/test/development/acceptance/ReactRefreshLogBox.test.ts b/test/development/acceptance/ReactRefreshLogBox.test.ts index 54d9230e84b7d..f43066175640c 100644 --- a/test/development/acceptance/ReactRefreshLogBox.test.ts +++ b/test/development/acceptance/ReactRefreshLogBox.test.ts @@ -3,13 +3,13 @@ import { createSandbox } from 'development-sandbox' import { FileRef, nextTestSetup } from 'e2e-utils' import { describeVariants as describe, - getRedboxCallStack, toggleCollapseCallStackFrames, } from 'next-test-utils' import path from 'path' import { outdent } from 'outdent' -describe.each(['default', 'turbo'])('ReactRefreshLogBox %s', () => { +describe.each(['default', 'turbo'])('ReactRefreshLogBox %s', (mode) => { + const isTurbopack = mode === 'turbo' const { next } = nextTestSetup({ files: new FileRef(path.join(__dirname, 'fixtures', 'default-template')), skipStart: true, @@ -786,10 +786,38 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox %s', () => { ], ]) ) - const { session, browser } = sandbox - await session.assertHasRedbox() - const texts = await getRedboxCallStack(browser) - expect(texts).toMatchSnapshot() + const { browser } = sandbox + if (isTurbopack) { + await expect(browser).toDisplayRedbox(` + { + "count": 1, + "description": "Error: anonymous error!", + "source": "pages/index.js (3:11) @ + > 3 | throw new Error("anonymous error!"); + | ^", + "stack": [ + "Array.map (0:0)", + "Page pages/index.js (2:13)", + ], + "title": "Server Error", + } + `) + } else { + await expect(browser).toDisplayRedbox(` + { + "count": 1, + "description": "Error: anonymous error!", + "source": "pages/index.js (3:11) @ eval + > 3 | throw new Error("anonymous error!"); + | ^", + "stack": [ + "Array.map (0:0)", + "map pages/index.js (2:13)", + ], + "title": "Server Error", + } + `) + } }) test('should hide unrelated frames in stack trace with node:internal calls', async () => { diff --git a/test/development/acceptance/__snapshots__/ReactRefreshLogBox.test.ts.snap b/test/development/acceptance/__snapshots__/ReactRefreshLogBox.test.ts.snap index 21f0656c91c63..6d1b65efe9343 100644 --- a/test/development/acceptance/__snapshots__/ReactRefreshLogBox.test.ts.snap +++ b/test/development/acceptance/__snapshots__/ReactRefreshLogBox.test.ts.snap @@ -54,13 +54,6 @@ exports[`ReactRefreshLogBox default module init error not shown 1`] = ` 6 | return

Default Export

;" `; -exports[`ReactRefreshLogBox default should show anonymous frames in stack trace 1`] = ` -"Array.map - (0:0) -map -pages/index.js (2:13)" -`; - exports[`ReactRefreshLogBox default should strip whitespace correctly with newline 1`] = ` "index.js (8:27) @ onClick @@ -125,13 +118,6 @@ exports[`ReactRefreshLogBox turbo module init error not shown 1`] = ` 6 | return

Default Export

;" `; -exports[`ReactRefreshLogBox turbo should show anonymous frames in stack trace 1`] = ` -"Array.map - (0:0) -Page -pages/index.js (2:13)" -`; - exports[`ReactRefreshLogBox turbo should strip whitespace correctly with newline 1`] = ` "index.js (8:27) @ onClick diff --git a/test/development/app-dir/capture-console-error-owner-stack/capture-console-error-owner-stack.test.ts b/test/development/app-dir/capture-console-error-owner-stack/capture-console-error-owner-stack.test.ts index a8b794ff74897..e58d34813b634 100644 --- a/test/development/app-dir/capture-console-error-owner-stack/capture-console-error-owner-stack.test.ts +++ b/test/development/app-dir/capture-console-error-owner-stack/capture-console-error-owner-stack.test.ts @@ -1,33 +1,7 @@ import { nextTestSetup } from 'e2e-utils' -import { - getRedboxCallStack, - getRedboxDescription, - getRedboxTitle, - getRedboxSource, - getRedboxTotalErrorCount, - openRedbox, - hasRedboxCallStack, -} from 'next-test-utils' -async function getRedboxResult(browser: any) { - const title = await getRedboxTitle(browser) - const description = await getRedboxDescription(browser) - const callStacks = (await hasRedboxCallStack(browser)) - ? await getRedboxCallStack(browser) - : '' - const count = await getRedboxTotalErrorCount(browser) - const source = await getRedboxSource(browser) - const result = { - title, - count, - source, - description, - callStacks, - } - return result -} describe('app-dir - capture-console-error-owner-stack', () => { - const { next } = nextTestSetup({ + const { isTurbopack, next } = nextTestSetup({ files: __dirname, }) @@ -35,51 +9,35 @@ describe('app-dir - capture-console-error-owner-stack', () => { const browser = await next.browser('/browser/event') await browser.elementByCss('button').click() - await openRedbox(browser) - - const result = await getRedboxResult(browser) - - if (process.env.TURBOPACK) { - expect(result).toMatchInlineSnapshot(` - { - "callStacks": "button - (0:0) - Page - app/browser/event/page.js (5:5)", - "count": 1, - "description": "trigger an console ", - "source": "app/browser/event/page.js (7:17) @ onClick - - 5 |