Files
next.js/test/e2e/i18n-data-route/i18n-data-route.test.ts
Wyatt JohnsonandGitHub d56855041c refactor: encapsulate content type within RenderResult (#81861)
### Problem
The PPR boundary sentinel was being incorrectly added to responses due
to flawed content type logic in `sendRenderResult`. The original
conditional logic had complex fallbacks that caused the sentinel to be
added when it shouldn't be:

```javascript
// BEFORE: Incorrect logic - sentinel added to wrong response types
if (
  process.env.__NEXT_TEST_MODE &&
  minimalMode &&
  isRoutePPREnabled &&
  // ❌ This logic was inverted and unreliable
  body.contentType !== RSC_CONTENT_TYPE_HEADER &&
  !isRSCRequest
) {
  body.unshift(createPPRBoundarySentinel())
}
```

The problem was that `body.contentType` was inconsistently determined
through external logic in `sendRenderResult`, causing the sentinel to
appear in responses that shouldn't have it.

### Solution
By moving content type into `RenderResult` constructor, the sentinel
logic now correctly identifies HTML responses:

```javascript
// AFTER: Correct logic - sentinel only added to HTML responses
if (
  process.env.__NEXT_TEST_MODE &&
  minimalMode &&
  isRoutePPREnabled &&
  body.contentType === HTML_CONTENT_TYPE_HEADER // ✅ Reliable content type check
) {
  body.unshift(createPPRBoundarySentinel())
}
```

### Key Changes
- **Fixed sentinel logic**: PPR boundary sentinel now only appears in
HTML responses where it belongs
- **Reliable content type**: Content type is determined at RenderResult
creation, not through fallback logic
- **Consistent API**: Removed redundant `type` parameter that was
causing the confusion

This ensures PPR test assertions work correctly by only adding the
boundary sentinel to the appropriate response types.
2025-07-21 09:06:51 -06:00

92 lines
2.7 KiB
TypeScript

import { nextTestSetup } from 'e2e-utils'
const { i18n } = require('./next.config')
const pages = [
{ url: '/about', page: '/about', params: null },
{ url: '/blog/about', page: '/[slug]/about', params: { slug: 'blog' } },
]
function checkDataRoute(data: any, page: string) {
expect(data).toHaveProperty('pageProps')
expect(data.pageProps).toHaveProperty('page', page)
}
describe('i18n-data-route', () => {
const { next, skipped } = nextTestSetup({
files: __dirname,
// This test skips deployment because env vars that are doubled underscore prefixed
// are not supported.
skipDeployment: true,
env: {
// Disable internal header stripping so we can test the invoke output.
__NEXT_NO_STRIP_INTERNAL_HEADERS: '1',
},
})
if (skipped) return
describe('with locale prefix', () => {
describe.each(i18n.locales)('/%s', (locale) => {
const prefixed = pages.map((page) => ({
...page,
url: `/${locale}${page.url}`,
}))
it.each(prefixed)(
'should render $page via $url',
async ({ url, page }) => {
const $ = await next.render$(url)
expect($('[data-page]').data('page')).toBe(page)
}
)
it.each(prefixed)(
'should serve data for $page',
async ({ url, page, params }) => {
url = `/_next/data/${next.buildId}${url}.json`
if (params) {
const query = new URLSearchParams(params)
// Ensure the query is sorted so it's deterministic.
query.sort()
url += `?${query.toString()}`
}
const res = await next.fetch(url)
expect(res.status).toBe(200)
expect(res.headers.get('content-type')).toStartWith(
'application/json'
)
const data = await res.json()
checkDataRoute(data, page)
}
)
})
})
describe('without locale prefix', () => {
it.each(pages)('should render $page via $url', async ({ url, page }) => {
const $ = await next.render$(url)
expect($('[data-page]').data('page')).toBe(page)
})
it.each(pages)(
'should serve data for $page',
async ({ url, page, params }) => {
url = `/_next/data/${next.buildId}/${i18n.defaultLocale}${url}.json`
if (params) {
const query = new URLSearchParams(params)
// Ensure the query is sorted so it's deterministic.
query.sort()
url += `?${query.toString()}`
}
const res = await next.fetch(url)
expect(res.status).toBe(200)
expect(res.headers.get('content-type')).toStartWith('application/json')
const data = await res.json()
checkDataRoute(data, page)
}
)
})
})