Repository: vercel/next.js
Pull request: test: fix more Runtime/Recoverable Error flakiness in HMR

Follow-up to #79254, there's one more test flaking with the same issue.

I pulled the label-ignoring logic out into

```ts
expect(browser).toDisplayRedbox('...', { label: false })
```

so that it's easy to find these later when we fix the underlying issue.

Changed files:
filename: test/development/acceptance-app/ReactRefreshLogBox.test.ts
patch: @@ -1279,19 +1279,24 @@ describe('ReactRefreshLogBox app', () => {
     )
     const { session, browser } = sandbox
 
-    await expect(browser).toDisplayRedbox(`
+    await expect(browser).toDisplayRedbox(
+      `
      {
        "description": "Server component error",
        "environmentLabel": "Server",
-       "label": "Runtime Error",
+       "label": "<FIXME-excluded-label>",
        "source": "app/page.js (2:9) @ Page
      > 2 |   throw new Error('Server component error')
          |         ^",
        "stack": [
          "Page app/page.js (2:9)",
        ],
      }
-    `)
+    `,
+
+      // FIXME: `label` is flaking between "Runtime Error" and "Recoverable Error"
+      { label: false }
+    )
 
     // Remove error
     await session.patch(
@@ -1318,19 +1323,24 @@ describe('ReactRefreshLogBox app', () => {
       `
     )
 
-    await expect(browser).toDisplayRedbox(`
+    await expect(browser).toDisplayRedbox(
+      `
      {
        "description": "Server component error!",
        "environmentLabel": "Server",
-       "label": "Runtime Error",
+       "label": "<FIXME-excluded-label>",
        "source": "app/page.js (2:9) @ Page
      > 2 |   throw new Error('Server component error!')
          |         ^",
        "stack": [
          "Page app/page.js (2:9)",
        ],
      }
-    `)
+    `,
+
+      // FIXME: `label` is flaking between "Runtime Error" and "Recoverable Error"
+      { label: false }
+    )
   })
 
   test('Import trace when module not found in layout', async () => {

filename: test/development/acceptance-app/error-recovery.test.ts
patch: @@ -1,14 +1,7 @@
 /* eslint-env jest */
 import { createSandbox } from 'development-sandbox'
 import { FileRef, nextTestSetup } from 'e2e-utils'
-import {
-  assertHasRedbox,
-  check,
-  getRedboxCallStack,
-  getRedboxDescription,
-  getRedboxEnvironmentLabel,
-  getRedboxSource,
-} from 'next-test-utils'
+import { check } from 'next-test-utils'
 import path from 'path'
 import { outdent } from 'outdent'
 
@@ -382,55 +375,25 @@ describe('Error recovery app', () => {
         `
     )
 
-    {
-      // FIXME: `label` is flaking between "Runtime Error" and "Recoverable Error",
-      // so we have to snapshot the redbox manually we figure out why
-
-      // await expect(browser).toDisplayRedbox(`
-      //  {
-      //    "description": "oops",
-      //    "environmentLabel": "Server",
-      //    "label": "Recoverable Error",
-      //    "source": "child.js (3:9) @ Child
-      //  > 3 |   throw new Error('oops')
-      //      |         ^",
-      //    "stack": [
-      //      "Child child.js (3:9)",
-      //      "Page app/server/page.js (3:10)",
-      //    ],
-      //  }
-      // `)
-
-      await assertHasRedbox(browser)
-      const redbox = await Promise.all([
-        getRedboxDescription(browser),
-        getRedboxEnvironmentLabel(browser),
-        getRedboxSource(browser),
-        getRedboxCallStack(browser),
-      ]).then(([description, environmentLabel, source, stack]) => ({
-        description,
-        environmentLabel,
-        source,
-        stack,
-      }))
-      expect(redbox).toMatchInlineSnapshot(`
-      {
-        "description": "oops",
-        "environmentLabel": "Server",
-        "source": "child.js (3:9) @ Child
-
-        1 | // hello
-        2 | export default function Child() {
-      > 3 |   throw new Error('oops')
-          |         ^
-        4 | }",
-        "stack": [
-          "Child child.js (3:9)",
-          "Page app/server/page.js (3:10)",
-        ],
-      }
-      `)
-    }
+    await expect(browser).toDisplayRedbox(
+      `
+     {
+       "description": "oops",
+       "environmentLabel": "Server",
+       "label": "<FIXME-excluded-label>",
+       "source": "child.js (3:9) @ Child
+     > 3 |   throw new Error('oops')
+         |         ^",
+       "stack": [
+         "Child child.js (3:9)",
+         "Page app/server/page.js (3:10)",
+       ],
+     }
+    `,
+
+      // FIXME: `label` is flaking between "Runtime Error" and "Recoverable Error"
+      { label: false }
+    )
 
     // TODO-APP: re-enable when error recovery doesn't reload the page.
     /* const didNotReload = */ await session.patch(

filename: test/lib/add-redbox-matchers.ts
patch: @@ -37,7 +37,10 @@ declare global {
        *
        * @param inlineSnapshot - The snapshot to compare against.
        */
-      toDisplayRedbox(inlineSnapshot?: string): Promise<void>
+      toDisplayRedbox(
+        inlineSnapshot?: string,
+        opts?: ErrorSnapshotOptions
+      ): Promise<void>
 
       /**
        * Inline snapshot matcher for a Redbox that's collapsed by default.
@@ -57,11 +60,18 @@ declare global {
        *
        * @param inlineSnapshot - The snapshot to compare against.
        */
-      toDisplayCollapsedRedbox(inlineSnapshot?: string): Promise<void>
+      toDisplayCollapsedRedbox(
+        inlineSnapshot?: string,
+        opts?: ErrorSnapshotOptions
+      ): Promise<void>
     }
   }
 }
 
+interface ErrorSnapshotOptions {
+  label?: boolean
+}
+
 interface ErrorSnapshot {
   environmentLabel: string | null
   label: string | null
@@ -73,11 +83,12 @@ interface ErrorSnapshot {
 
 async function createErrorSnapshot(
   browser: Playwright,
-  next: NextInstance | null
+  next: NextInstance | null,
+  { label: includeLabel = true }: ErrorSnapshotOptions = {}
 ): Promise<ErrorSnapshot> {
   const [label, environmentLabel, description, source, stack, componentStack] =
     await Promise.all([
-      getRedboxLabel(browser),
+      includeLabel ? getRedboxLabel(browser) : null,
       getRedboxEnvironmentLabel(browser),
       getRedboxDescription(browser),
       getRedboxSource(browser),
@@ -155,7 +166,7 @@ async function createErrorSnapshot(
 
   const snapshot: ErrorSnapshot = {
     environmentLabel,
-    label,
+    label: label ?? '<FIXME-excluded-label>',
     description:
       description !== null && next !== null
         ? description.replace(next.testDir, '<FIXME-project-root>')
@@ -182,13 +193,14 @@ type RedboxSnapshot = ErrorSnapshot | ErrorSnapshot[]
 
 async function createRedboxSnapshot(
   browser: Playwright,
-  next: NextInstance | null
+  next: NextInstance | null,
+  opts?: ErrorSnapshotOptions
 ): Promise<RedboxSnapshot> {
   const errorTally = await getRedboxTotalErrorCount(browser)
   const errorSnapshots: ErrorSnapshot[] = []
 
   for (let errorIndex = 0; errorIndex < errorTally; errorIndex++) {
-    const errorSnapshot = await createErrorSnapshot(browser, next)
+    const errorSnapshot = await createErrorSnapshot(browser, next, opts)
     errorSnapshots.push(errorSnapshot)
 
     if (errorIndex < errorTally - 1) {
@@ -214,7 +226,8 @@ expect.extend({
   async toDisplayRedbox(
     this: MatcherContext,
     browserOrContext: Playwright | { browser: Playwright; next: NextInstance },
-    expectedRedboxSnapshot?: string
+    expectedRedboxSnapshot?: string,
+    opts?: ErrorSnapshotOptions
   ) {
     let browser: Playwright
     let next: NextInstance | null
@@ -250,7 +263,7 @@ expect.extend({
       }
     }
 
-    const redbox = await createRedboxSnapshot(browser, next)
+    const redbox = await createRedboxSnapshot(browser, next, opts)
 
     // argument length is relevant.
     // Jest will update absent snapshots but fail if you specify a snapshot even if undefined.
@@ -263,7 +276,8 @@ expect.extend({
   async toDisplayCollapsedRedbox(
     this: MatcherContext,
     browserOrContext: Playwright | { browser: Playwright; next: NextInstance },
-    expectedRedboxSnapshot?: string
+    expectedRedboxSnapshot?: string,
+    opts?: ErrorSnapshotOptions
   ) {
     let browser: Playwright
     let next: NextInstance | null
@@ -306,7 +320,7 @@ expect.extend({
       }
     }
 
-    const redbox = await createRedboxSnapshot(browser, next)
+    const redbox = await createRedboxSnapshot(browser, next, opts)
 
     // argument length is relevant.
     // Jest will update absent snapshots but fail if you specify a snapshot even if undefined.