mirror of
https://github.com/hanzoai/next.js.git
synced 2026-10-30 14:46:38 +00:00
### 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.
92 lines
2.7 KiB
TypeScript
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)
|
|
}
|
|
)
|
|
})
|
|
})
|