next.js/test/e2e/app-dir/cache-components-segment-configs/cache-components-edge-deduplication.test.ts
cache-components-edge-deduplication.test.ts91 lines3.4 KB
import { nextTestSetup } from 'e2e-utils'

import { waitForRedbox } from 'next-test-utils'

// Filter CLI output to only keep Turbopack error header lines (starting with ⨯ or
// standalone file:line:col) to accurately count error occurrences without counting
// console.error, stack traces, or forwarded browser logs.
function filterToErrorHeaders(output: string): string {
  return output
    .split('\n')
    .filter(
      (line) =>
        !line.includes('[browser]') &&
        !line.includes('console.error') &&
        !line.includes('at <unknown>') &&
        !line.includes('at Object.') &&
        !line.includes('at DevServer.') &&
        !line.includes('at DevBundlerService.') &&
        !line.includes('at async ')
    )
    .join('\n')
}

// Only Turbopack runs the transform on the layout once in edge and non-edge contexts
// so we only test this on Turbopack
;(process.env.IS_TURBOPACK_TEST ? describe : describe.skip)(
  'cache-components-edge-deduplication',
  () => {
    const { next, skipped, isNextDev } = nextTestSetup({
      files: __dirname + '/fixtures/edge-deduplication',
      skipStart: true,
      skipDeployment: true,
    })

    if (skipped) {
      return
    }

    it('should not duplicate errors when layout is compiled for both edge and non-edge contexts', async () => {
      try {
        await next.start()
      } catch {
        // we expect the build to fail
      }

      if (isNextDev) {
        const browser = await next.browser('/edge-with-layout/edge')
        waitForRedbox(browser)
        await expect(browser).toDisplayRedbox(`
         {
           "description": "Route segment config "dynamic" is not compatible with \`nextConfig.cacheComponents\`. Please remove it.",
           "environmentLabel": null,
           "label": "Build Error",
           "source": "./app/edge-with-layout/layout.tsx (1:14)
         Route segment config "dynamic" is not compatible with \`nextConfig.cacheComponents\`. Please remove it.
         > 1 | export const dynamic = 'force-dynamic'
             |              ^^^^^^^",
           "stack": [],
         }
        `)

        // Count occurrences of the layout error at the specific location
        // Filter out browser logs to avoid counting forwarded browser errors
        const filteredOutput = filterToErrorHeaders(next.cliOutput)
        const layoutErrorMatches = filteredOutput.match(
          /\.\/app\/edge-with-layout\/layout\.tsx:1:14/g
        )
        // We don't show an error stack, just the individual error messages at each location
        expect(layoutErrorMatches.length).toBe(1)
      } else {
        // Check that both the layout and edge page errors appear
        expect(next.cliOutput).toContain('./app/edge-with-layout/layout.tsx')
        expect(next.cliOutput).toContain('./app/edge-with-layout/edge/page.tsx')
        expect(next.cliOutput).toContain(
          '"dynamic" is not compatible with `nextConfig.cacheComponents`. Please remove it.'
        )
        expect(next.cliOutput).toContain(
          '"runtime" is not compatible with `nextConfig.cacheComponents`. Please remove it.'
        )
        // Count occurrences of the layout error at the specific location
        const layoutErrorMatches = next.cliOutput.match(
          /\.\/app\/layout\.tsx:1:14/g
        )

        // Should appear exactly twice: once in the formatted error message, once in the stack trace
        expect(layoutErrorMatches.length).toBe(2)
      }
    })
  }
)
Quest for Codev2.0.0
/
SIGN IN