mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
[flakiness metrics](https://app.datadoghq.com/ci/test/runs?query=test_level%3Atest%20%40git.repository.id%3A%22github.com%2Fvercel%2Fnext.js%22%20%40test.name%3A%22app%20dir%20-%20metadata%20static%20routes%20cache%20should%20generate%20different%20content%20after%20replace%20the%20static%20metadata%20file%22%20%40test.type%3A%22nextjs%22%20%40test.status%3A%28fail%20OR%20pass%29%20%40git.branch%3Acanary&agg_m=count&agg_m_source=base&agg_t=count&fromUser=false&index=citest&start=1780774829532&end=1781379629532&paused=false) <img width="423" height="173" alt="Screenshot 2026-06-13 at 21 41 05" src="https://github.com/user-attachments/assets/d9888a77-db05-4ab5-89e3-97f01b9d7353" /> This test replaces the static favicon and Open Graph image and rebuilds to verify the served content changes, so it needs one production build with the original files and another with the replacements. Running both `next.start()` cycles in a single test case put two full builds under the 60s per-test budget, which is easy to exceed on slower CI runners, where the second build most often stalls while collecting build traces. We move the first build, start, and baseline measurement into `beforeAll`, where it can use the longer setup-hook budget, and leave the test body responsible only for the second build. Keeping the build out of the test body also makes it idempotent, so a retry recomputes the new hashes against the baseline that `beforeAll` captures once.
78 lines
2.7 KiB
TypeScript
78 lines
2.7 KiB
TypeScript
import { nextTestSetup } from 'e2e-utils'
|
|
import crypto from 'crypto'
|
|
|
|
function generateMD5(text: string) {
|
|
const hash = crypto.createHash('md5')
|
|
hash.update(text)
|
|
return hash.digest('hex')
|
|
}
|
|
|
|
describe('app dir - metadata static routes cache', () => {
|
|
const { next } = nextTestSetup({
|
|
files: __dirname,
|
|
skipStart: true,
|
|
})
|
|
|
|
let faviconMd5: string
|
|
let opengraphImageMd5: string
|
|
|
|
// Each `next.start()` performs a full production build, and a single test
|
|
// case only gets a 60s budget, which two builds can exceed on slower CI
|
|
// runners (most often while collecting build traces). The first build and
|
|
// start (with the original metadata files) therefore runs in `beforeAll`,
|
|
// which gets the longer setup-hook budget, leaving the test body responsible
|
|
// for only the second build. Keeping the build out of the test body also
|
|
// makes it idempotent, so a `jest.retryTimes` retry recomputes the new hashes
|
|
// against a stable baseline.
|
|
beforeAll(async () => {
|
|
await next.start()
|
|
|
|
const $ = await next.render$('/')
|
|
const faviconUrl = $('link[rel="icon"]').attr('href')
|
|
const faviconBody = await (await next.fetch(faviconUrl)).text()
|
|
faviconMd5 = generateMD5(faviconBody)
|
|
|
|
const opengraphImageUrl = $('meta[property="og:image"]').attr('href')
|
|
const opengraphImageBody = await (
|
|
await next.fetch(opengraphImageUrl)
|
|
).text()
|
|
opengraphImageMd5 = generateMD5(opengraphImageBody)
|
|
|
|
await next.stop()
|
|
})
|
|
|
|
it('should generate different content after replace the static metadata file', async () => {
|
|
// Update favicon and opengraph image
|
|
const newFaviconContent = await next.readFileBuffer('app/favicon.new.ico')
|
|
await next.remove('app/favicon.ico')
|
|
await next.writeFileBuffer('app/favicon.ico', newFaviconContent)
|
|
|
|
const newOpengraphImageContent = await next.readFileBuffer(
|
|
'app/opengraph-image.new.png'
|
|
)
|
|
await next.remove('app/opengraph-image.png')
|
|
await next.writeFileBuffer(
|
|
'app/opengraph-image.png',
|
|
newOpengraphImageContent
|
|
)
|
|
|
|
await next.start()
|
|
|
|
const new$ = await next.render$('/')
|
|
const newFaviconUrl = new$('link[rel="icon"]').attr('href')
|
|
const newFaviconBody = await (await next.fetch(newFaviconUrl)).text()
|
|
const newFaviconMd5 = generateMD5(newFaviconBody)
|
|
|
|
const newOpengraphImageUrl = new$('meta[property="og:image"]').attr('href')
|
|
const newOpengraphImageBody = await (
|
|
await next.fetch(newOpengraphImageUrl)
|
|
).text()
|
|
const newOpengraphImageMd5 = generateMD5(newOpengraphImageBody)
|
|
|
|
await next.stop()
|
|
|
|
expect(faviconMd5).not.toBe(newFaviconMd5)
|
|
expect(opengraphImageMd5).not.toBe(newOpengraphImageMd5)
|
|
})
|
|
})
|