import { nextTestSetup } from 'e2e-utils' import { retry, waitForRedbox, getRedboxDescription, getRedboxSource, } from 'next-test-utils' describe('cache-components-segment-configs', () => { const { next, skipped, isNextDev, isTurbopack } = nextTestSetup({ files: __dirname + '/fixtures/default', skipStart: true, skipDeployment: true, }) if (skipped) { return } it("it should error when using segment configs that aren't supported by cacheComponents", async () => { try { await next.start() } catch { // we expect the build to fail } if (isNextDev) { const browser = await next.browser('/revalidate') await waitForRedbox(browser) const redbox = { description: await getRedboxDescription(browser), source: await getRedboxSource(browser), } if (isTurbopack) { expect(redbox.description).toMatchInlineSnapshot( `"Route segment config "revalidate" is not compatible with \`nextConfig.cacheComponents\`. Please remove it."` ) } else { expect(redbox.description).toMatchInlineSnapshot( `" x Route segment config "revalidate" is not compatible with \`nextConfig.cacheComponents\`. Please remove it."` ) } expect(redbox.source).toContain( '"revalidate" is not compatible with `nextConfig.cacheComponents`. Please remove it.' ) } else { expect(next.cliOutput).toContain('./app/dynamic-params/[slug]/page.tsx') expect(next.cliOutput).toContain( '"dynamicParams" is not compatible with `nextConfig.cacheComponents`. Please remove it.' ) expect(next.cliOutput).toContain('./app/dynamic/nested/page.tsx') expect(next.cliOutput).toContain('./app/dynamic/page.tsx') expect(next.cliOutput).toContain( '"dynamic" is not compatible with `nextConfig.cacheComponents`. Please remove it.' ) expect(next.cliOutput).toContain('./app/fetch-cache/page.tsx') expect(next.cliOutput).toContain( '"fetchCache" is not compatible with `nextConfig.cacheComponents`. Please remove it.' ) expect(next.cliOutput).toContain('./app/revalidate/page.tsx') expect(next.cliOutput).toContain( '"revalidate" is not compatible with `nextConfig.cacheComponents`. Please remove it.' ) } }) it('should propagate configurations from layouts to pages', async () => { // patch the root layout. We expect the "dynamic" segment config to now be part of // each sub-page that uses this layout. await next.patchFile( 'app/layout.tsx', (content) => { return ` export const runtime = 'nodejs'; ${content} ` }, async () => { try { await next.start() } catch { // we expect the build to fail } if (isNextDev) { const browser = await next.browser('/revalidate') await waitForRedbox(browser) const redbox = { description: await getRedboxDescription(browser), source: await getRedboxSource(browser), } if (isTurbopack) { // The page-level error is shown first in the redbox, but // the layout error is also present in the CLI output. expect(redbox.description).toMatchInlineSnapshot( `"Route segment config "revalidate" is not compatible with \`nextConfig.cacheComponents\`. Please remove it."` ) } else { expect(redbox.description).toMatchInlineSnapshot( `" x Route segment config "runtime" is not compatible with \`nextConfig.cacheComponents\`. Please remove it."` ) } expect(redbox.source).toContain( 'is not compatible with `nextConfig.cacheComponents`. Please remove it.' ) // Verify that the "runtime" error from the layout propagation // is present in the CLI output even if it's not the first error // shown in the redbox. expect(next.cliOutput).toContain( '"runtime" is not compatible with `nextConfig.cacheComponents`. Please remove it.' ) } else { await retry(async () => { expect(next.cliOutput).toContain( '"runtime" is not compatible with `nextConfig.cacheComponents`. Please remove it.' ) // the stack trace is different between turbopack/webpack if (isTurbopack) { expectLinesToAppearTogether(next.cliOutput, [ './app/layout.tsx:2:24', ]) } else { expectLinesToAppearTogether(next.cliOutput, [ 'Import trace for requested module:', './app/fetch-cache/page.tsx', './app/layout.tsx', ]) } }) } } ) }) }) function expectLinesToAppearTogether(output: string, lines: string[]) { const escapedLines = lines.map((line) => line.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') ) const pattern = new RegExp(escapedLines.join('\\s*'), 's') expect(output).toMatch(pattern) }