next.js/test/e2e/app-dir/cache-components/cache-components.params.test.ts
cache-components.params.test.ts720 lines33.2 KB
import { nextTestSetup } from 'e2e-utils'

// cSpell:words lowcard highcard
describe('cache-components', () => {
  const { next, isNextDev, skipped } = nextTestSetup({
    files: __dirname,
    skipDeployment: true,
  })

  if (skipped) {
    return
  }

  let cliIndex = 0
  beforeEach(() => {
    cliIndex = next.cliOutput.length
  })
  function getLines(containing: string): Array<string> {
    const warnings = next.cliOutput
      .slice(cliIndex)
      .split('\n')
      .filter((l) => l.includes(containing))

    cliIndex = next.cliOutput.length
    return warnings
  }

  describe('Params', () => {
    it('should partially prerender pages that await params in a server components', async () => {
      expect(getLines('Route "/params')).toEqual([])

      let $ = await next.render$(
        '/params/semantics/one/build/layout-access/server'
      )
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')

        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('build')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at buildtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('build')
      }

      $ = await next.render$('/params/semantics/one/run/layout-access/server')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')

        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('run')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#highcard-fallback').text()).toBe('loading highcard children')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('run')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/build/page-access/server')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')

        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('build')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at buildtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('build')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/run/page-access/server')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')

        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('run')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#highcard-fallback').text()).toBe('loading highcard children')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('run')
        expect(getLines('Route "/params')).toEqual([])
      }
    })

    // Since #85155, we intentionally omit search params from client segments
    // if the page is otherwise static, and resume using a client fetch
    // instead. So it's expected that the value is missing pre-hydration.
    // There are separate tests that verify that it is eventually hydrated.
    // TODO: Rewrite or update this test.
    it.skip('should partially prerender pages that use params in a client components', async () => {
      expect(getLines('Route "/params')).toEqual([])

      let $ = await next.render$(
        '/params/semantics/one/build/layout-access/client'
      )
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('build')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at buildtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('build')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/run/layout-access/client')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')

        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('run')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#highcard-fallback').text()).toBe('loading highcard children')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('run')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/build/page-access/client')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('build')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at buildtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('build')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/run/page-access/client')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('run')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#highcard-fallback').text()).toBe('loading highcard children')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-lowcard').text()).toBe('one')
        expect($('#param-highcard').text()).toBe('run')
        expect(getLines('Route "/params')).toEqual([])
      }
    })

    it('should fully prerender pages that check individual param keys after awaiting params in a server component', async () => {
      expect(getLines('Route "/params')).toEqual([])
      let $ = await next.render$(
        '/params/semantics/one/build/layout-has/server'
      )
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at buildtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/build/page-has/server')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at buildtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/run/layout-has/server')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        // With PPR fallbacks the first visit is still partially prerendered
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#highcard-fallback').text()).toBe('loading highcard children')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/run/page-has/server')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        // With PPR fallbacks the first visit is still partially prerendered
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#highcard-fallback').text()).toBe('loading highcard children')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      }
    })

    // Since #85155, we intentionally omit search params from client segments
    // if the page is otherwise static, and resume using a client fetch
    // instead. So it's expected that the value is missing pre-hydration.
    // There are separate tests that verify that it is eventually hydrated.
    // TODO: Rewrite or update this test.
    it.skip('should fully prerender pages that check individual param keys after `use`ing params in a client component', async () => {
      expect(getLines('Route "/params')).toEqual([])
      let $ = await next.render$(
        '/params/semantics/one/build/layout-has/client'
      )
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at buildtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/build/page-has/client')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at buildtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/run/layout-has/client')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        // With PPR fallbacks the first visit is still partially prerendered
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#highcard-fallback').text()).toBe('loading highcard children')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/run/page-has/client')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        // With PPR fallbacks the first visit is still partially prerendered
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#highcard-fallback').text()).toBe('loading highcard children')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-has-lowcard').text()).toBe('true')
        expect($('#param-has-highcard').text()).toBe('true')
        expect($('#param-has-foo').text()).toBe('false')
        expect(getLines('Route "/params')).toEqual([])
      }
    })

    it('should partially prerender pages that spread awaited params in a server component', async () => {
      expect(getLines('Route "/params')).toEqual([])
      let $ = await next.render$(
        '/params/semantics/one/build/layout-spread/server'
      )
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('build')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at buildtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('build')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/build/page-spread/server')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('build')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at buildtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('build')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/run/layout-spread/server')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('run')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#highcard-fallback').text()).toBe('loading highcard children')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('run')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/run/page-spread/server')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('run')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#highcard-fallback').text()).toBe('loading highcard children')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('run')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      }
    })

    // Since #85155, we intentionally omit search params from client segments
    // if the page is otherwise static, and resume using a client fetch
    // instead. So it's expected that the value is missing pre-hydration.
    // There are separate tests that verify that it is eventually hydrated.
    // TODO: Rewrite or update this test.
    it.skip('should partially prerender pages that spread `use`ed params in a client component', async () => {
      expect(getLines('Route "/params')).toEqual([])
      let $ = await next.render$(
        '/params/semantics/one/build/layout-spread/client'
      )
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('build')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at buildtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('build')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/build/page-spread/client')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('build')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at buildtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('build')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/run/layout-spread/client')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('run')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#highcard-fallback').text()).toBe('loading highcard children')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('run')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/semantics/one/run/page-spread/client')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#lowcard').text()).toBe('at runtime')
        expect($('#highcard').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('run')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#lowcard').text()).toBe('at buildtime')
        expect($('#highcard').text()).toBe('at buildtime')
        expect($('#highcard-fallback').text()).toBe('loading highcard children')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-copied-lowcard').text()).toBe('one')
        expect($('#param-copied-highcard').text()).toBe('run')
        expect($('#param-key-count').text()).toBe('2')
        expect(getLines('Route "/params')).toEqual([])
      }
    })
  })

  describe('Param Shadowing', () => {
    it('should correctly allow param names like then, value, and status when awaiting params in a server component', async () => {
      expect(getLines('Route "/params')).toEqual([])
      let $ = await next.render$(
        '/params/shadowing/foo/bar/baz/qux/layout/server'
      )
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-dyn').text()).toBe('foo')
        expect($('#param-then').text()).toBe('bar')
        expect($('#param-value').text()).toBe('baz')
        expect($('#param-status').text()).toBe('qux')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-dyn').text()).toBe('foo')
        expect($('#param-then').text()).toBe('bar')
        expect($('#param-value').text()).toBe('baz')
        expect($('#param-status').text()).toBe('qux')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/shadowing/foo/bar/baz/qux/page/server')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-dyn').text()).toBe('foo')
        expect($('#param-then').text()).toBe('bar')
        expect($('#param-value').text()).toBe('baz')
        expect($('#param-status').text()).toBe('qux')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-dyn').text()).toBe('foo')
        expect($('#param-then').text()).toBe('bar')
        expect($('#param-value').text()).toBe('baz')
        expect($('#param-status').text()).toBe('qux')
        expect(getLines('Route "/params')).toEqual([])
      }
    })

    // Since #85155, we intentionally omit search params from client segments
    // if the page is otherwise static, and resume using a client fetch
    // instead. So it's expected that the value is missing pre-hydration.
    // There are separate tests that verify that it is eventually hydrated.
    // TODO: Rewrite or update this test.
    it.skip('should correctly allow param names like then, value, and status when `use`ing params in a client component', async () => {
      expect(getLines('Route "/params')).toEqual([])
      let $ = await next.render$(
        '/params/shadowing/foo/bar/baz/qux/layout/client'
      )
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-dyn').text()).toBe('foo')
        expect($('#param-then').text()).toBe('bar')
        expect($('#param-value').text()).toBe('baz')
        expect($('#param-status').text()).toBe('qux')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-dyn').text()).toBe('foo')
        expect($('#param-then').text()).toBe('bar')
        expect($('#param-value').text()).toBe('baz')
        expect($('#param-status').text()).toBe('qux')
        expect(getLines('Route "/params')).toEqual([])
      }

      $ = await next.render$('/params/shadowing/foo/bar/baz/qux/page/client')
      if (isNextDev) {
        expect($('#layout').text()).toBe('at runtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-dyn').text()).toBe('foo')
        expect($('#param-then').text()).toBe('bar')
        expect($('#param-value').text()).toBe('baz')
        expect($('#param-status').text()).toBe('qux')
        expect(getLines('Route "/params')).toEqual([])
      } else {
        expect($('#layout').text()).toBe('at buildtime')
        expect($('#page').text()).toBe('at runtime')
        expect($('#param-dyn').text()).toBe('foo')
        expect($('#param-then').text()).toBe('bar')
        expect($('#param-value').text()).toBe('baz')
        expect($('#param-status').text()).toBe('qux')
        expect(getLines('Route "/params')).toEqual([])
      }
    })
  })

  if (!isNextDev) {
    describe('generateStaticParams', () => {
      // This test is skipped as the previous workaround of using `fetch-cache` will no longer be supported with DIO.
      it.skip('should have cacheComponents semantics inside generateStaticParams', async () => {
        // This test is named what we want but our current implementation is not actually correct yet.
        // We are asserting current behavior and will update the test when we land the correct behavior

        const lines: Array<string> = next.cliOutput.split('\n')
        let i = 0
        while (true) {
          const line = lines[i++]
          if (typeof line !== 'string') {
            throw new Error(
              'Could not find expected route output for /params/generate-static-params/[slug]/page/...'
            )
          }

          if (
            line.startsWith('├') &&
            line.includes('/params/generate-static-params/[slug]')
          ) {
            let nextLine = lines[i++]
            // we expect the fallback shell first
            expect(nextLine).toContain('/params/generate-static-params/[slug]')
            nextLine = lines[i++]

            expect(nextLine).toMatch(
              /\/params\/generate-static-params\/\d+\/page/
            )
            nextLine = lines[i++]
            // Because we force-cache we only end up with one prebuilt page.
            // When cacheComponents semantics are fully respected we will end up with two.
            expect(nextLine).not.toMatch(
              /\/params\/generate-static-params\/\d+\/page/
            )
            break
          }
        }
      })
    })
  }
})
Quest for Codev2.0.0
/
SIGN IN