mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
## Summary This fixes adapter `onBuildComplete` outputs for dynamic metadata routes. ## Bug `handleBuildComplete` skipped metadata routes too aggressively via `isStaticMetadataFile(...)`, so dynamic metadata routes (for example `robots.txt` / `sitemap.xml` using `connection()`) were omitted from `outputs.appRoutes`. ## Fix Only skip metadata routes when they are actually prerendered/static (present in prerender manifests). Dynamic metadata routes are now included in adapter `outputs.appRoutes` as expected. ## Tests Added e2e coverage in `test/e2e/app-dir/adapter-dynamic-metadata`: - verifies dynamic `robots.txt`, `sitemap.xml`, and `favicon.ico` functionality - verifies adapter output classification for non-deploy runs - skips output-shape verification in deploy mode - skips the suite in dev mode
66 lines
2.2 KiB
TypeScript
66 lines
2.2 KiB
TypeScript
import type { NextAdapter } from 'next'
|
|
import { nextTestSetup } from 'e2e-utils'
|
|
|
|
describe('adapter-dynamic-metadata', () => {
|
|
const { next, isNextDev, isNextDeploy } = nextTestSetup({
|
|
files: __dirname,
|
|
})
|
|
|
|
if (isNextDev) {
|
|
it('should skip next dev', () => {})
|
|
return
|
|
}
|
|
|
|
if (!isNextDeploy) {
|
|
it('should classify dynamic metadata routes as app routes in adapter outputs', async () => {
|
|
const { outputs }: Parameters<NextAdapter['onBuildComplete']>[0] =
|
|
await next.readJSON('build-complete.json')
|
|
|
|
const expectedDynamicMetadataRoutes = [
|
|
'/robots.txt',
|
|
'/sitemap.xml',
|
|
'/favicon.ico',
|
|
]
|
|
const staticFilePathnames = outputs.staticFiles.map(
|
|
(item) => item.pathname
|
|
)
|
|
const prerenderPathnames = outputs.prerenders.map((item) => item.pathname)
|
|
const appRoutePathnames = outputs.appRoutes.map((item) => item.pathname)
|
|
|
|
expect(staticFilePathnames).toEqual(
|
|
expect.not.arrayContaining(expectedDynamicMetadataRoutes)
|
|
)
|
|
expect(prerenderPathnames).toEqual(
|
|
expect.not.arrayContaining(expectedDynamicMetadataRoutes)
|
|
)
|
|
expect(appRoutePathnames).toEqual(
|
|
expect.arrayContaining(expectedDynamicMetadataRoutes)
|
|
)
|
|
|
|
for (const pathname of expectedDynamicMetadataRoutes) {
|
|
const appRoute = outputs.appRoutes.find(
|
|
(item) => item.pathname === pathname
|
|
)
|
|
expect(appRoute?.runtime).toBe('nodejs')
|
|
}
|
|
})
|
|
}
|
|
|
|
it('should serve dynamic metadata routes', async () => {
|
|
const robots = await next.fetch('/robots.txt')
|
|
expect(robots.status).toBe(200)
|
|
expect(robots.headers.get('content-type')).toContain('text/plain')
|
|
expect(await robots.text()).toContain('User-Agent: *')
|
|
|
|
const sitemap = await next.fetch('/sitemap.xml')
|
|
expect(sitemap.status).toBe(200)
|
|
expect(sitemap.headers.get('content-type')).toBe('application/xml')
|
|
expect(await sitemap.text()).toContain('<urlset')
|
|
|
|
const favicon = await next.fetch('/favicon.ico')
|
|
expect(favicon.status).toBe(200)
|
|
expect(favicon.headers.get('content-type')).toContain('image/x-icon')
|
|
expect(await favicon.text()).toContain('dynamic favicon')
|
|
})
|
|
})
|