mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
Currently we error if you cannot produce a shell unless you have a Suspense boundary above the root. This is fine for normal IO but sync IO like Math.random() and new Date() have much more significant bad consequences for prerendering. Instead of treating these errors as another flavor of "must have a shell" validation we should instead treat them like they must be guarded behind something else dynamic like `await connection()`. In addition to unconditionally erroring for Sync IO in Server Components when prerendering this change also removes the Sync IO warning for runtime prefetches. This is because at the moment there is no way to debug these errors in dev. In the future we will add validation for prefetches and need to add back in some ability to warn for these cases but until then we will leave this case as a silent deopt.
271 lines
8.7 KiB
TypeScript
271 lines
8.7 KiB
TypeScript
import { nextTestSetup } from 'e2e-utils'
|
|
|
|
describe('Node Extensions', () => {
|
|
describe('Random', () => {
|
|
describe('Cache Components', () => {
|
|
const { next, skipped } = nextTestSetup({
|
|
files: __dirname + '/fixtures/random/cache-components',
|
|
skipDeployment: true,
|
|
})
|
|
|
|
if (skipped) {
|
|
return
|
|
}
|
|
|
|
it('should not error when accessing middlware that use Math.random()', async () => {
|
|
let res: Awaited<ReturnType<typeof next.fetch>>,
|
|
$: Awaited<ReturnType<typeof next.render$>>
|
|
|
|
res = await next.fetch('/rewrite')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/rewrite')
|
|
expect($('[data-testid="content"]').text()).toBe('rewritten')
|
|
})
|
|
|
|
it('should not error when accessing pages that use Math.random() in App Router', async () => {
|
|
let res, $
|
|
|
|
res = await next.fetch('/app/prerendered/unstable-cache')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/app/prerendered/unstable-cache')
|
|
expect($('li').length).toBe(2)
|
|
|
|
res = await next.fetch('/app/prerendered/use-cache')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/app/prerendered/use-cache')
|
|
expect($('li').length).toBe(2)
|
|
|
|
res = await next.fetch('/app/rendered/uncached')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/app/rendered/uncached')
|
|
expect($('li').length).toBe(2)
|
|
|
|
res = await next.fetch('/app/rendered/unstable-cache')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/app/rendered/unstable-cache')
|
|
expect($('li').length).toBe(2)
|
|
|
|
res = await next.fetch('/app/rendered/use-cache')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/app/rendered/use-cache')
|
|
expect($('li').length).toBe(2)
|
|
})
|
|
|
|
it('should not error when accessing routes that use Math.random() in App Router', async () => {
|
|
let res, body
|
|
|
|
res = await next.fetch('/app/prerendered/uncached/api')
|
|
expect(res.status).toBe(200)
|
|
body = await res.json()
|
|
expect(body).toEqual({
|
|
rand1: expect.any(Number),
|
|
rand2: expect.any(Number),
|
|
})
|
|
|
|
res = await next.fetch('/app/prerendered/unstable-cache/api')
|
|
expect(res.status).toBe(200)
|
|
body = await res.json()
|
|
expect(body).toEqual({
|
|
rand1: expect.any(Number),
|
|
rand2: expect.any(Number),
|
|
})
|
|
|
|
res = await next.fetch('/app/prerendered/use-cache/api')
|
|
expect(res.status).toBe(200)
|
|
body = await res.json()
|
|
expect(body).toEqual({
|
|
rand1: expect.any(Number),
|
|
rand2: expect.any(Number),
|
|
})
|
|
|
|
res = await next.fetch('/app/rendered/uncached/api')
|
|
expect(res.status).toBe(200)
|
|
body = await res.json()
|
|
expect(body).toEqual({
|
|
rand1: expect.any(Number),
|
|
rand2: expect.any(Number),
|
|
})
|
|
|
|
res = await next.fetch('/app/rendered/unstable-cache/api')
|
|
expect(res.status).toBe(200)
|
|
body = await res.json()
|
|
expect(body).toEqual({
|
|
rand1: expect.any(Number),
|
|
rand2: expect.any(Number),
|
|
})
|
|
|
|
res = await next.fetch('/app/rendered/use-cache/api')
|
|
expect(res.status).toBe(200)
|
|
body = await res.json()
|
|
expect(body).toEqual({
|
|
rand1: expect.any(Number),
|
|
rand2: expect.any(Number),
|
|
})
|
|
})
|
|
|
|
it('should not error when accessing pages that use Math.random() in Pages Router', async () => {
|
|
let res, $
|
|
|
|
res = await next.fetch('/pages/gip/random')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/pages/gip/random')
|
|
expect($('li').length).toBe(2)
|
|
|
|
res = await next.fetch('/pages/gssp/random')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/pages/gssp/random')
|
|
expect($('li').length).toBe(2)
|
|
|
|
res = await next.fetch('/pages/gsp/random')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/pages/gsp/random')
|
|
expect($('li').length).toBe(2)
|
|
})
|
|
|
|
it('should not error when accessing routes that use Math.random() in Pages Router', async () => {
|
|
let res, body
|
|
|
|
res = await next.fetch('/api/random')
|
|
expect(res.status).toBe(200)
|
|
body = await res.json()
|
|
expect(body).toEqual({
|
|
rand1: expect.any(Number),
|
|
rand2: expect.any(Number),
|
|
})
|
|
|
|
expect(body.rand1).not.toBe(body.rand2)
|
|
|
|
const first1 = body.rand1
|
|
const first2 = body.rand2
|
|
|
|
res = await next.fetch('/api/random')
|
|
body = await res.json()
|
|
expect(body.rand1).not.toBe(body.rand2)
|
|
expect(body.rand1).not.toBe(first1)
|
|
expect(body.rand2).not.toBe(first2)
|
|
})
|
|
})
|
|
|
|
describe('Legacy', () => {
|
|
const { next, skipped } = nextTestSetup({
|
|
files: __dirname + '/fixtures/random/legacy',
|
|
})
|
|
|
|
if (skipped) {
|
|
return
|
|
}
|
|
|
|
it('should not error when accessing middlware that use Math.random()', async () => {
|
|
let res, $
|
|
|
|
res = await next.fetch('/rewrite')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/rewrite')
|
|
expect($('[data-testid="content"]').text()).toBe('rewritten')
|
|
})
|
|
|
|
it('should not error when accessing pages that use Math.random() in App Router', async () => {
|
|
let res, $
|
|
|
|
res = await next.fetch('/app/prerendered/uncached')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/app/prerendered/uncached')
|
|
expect($('li').length).toBe(2)
|
|
|
|
res = await next.fetch('/app/prerendered/unstable-cache')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/app/prerendered/unstable-cache')
|
|
expect($('li').length).toBe(2)
|
|
|
|
res = await next.fetch('/app/rendered/uncached')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/app/rendered/uncached')
|
|
expect($('li').length).toBe(2)
|
|
|
|
res = await next.fetch('/app/rendered/unstable-cache')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/app/rendered/unstable-cache')
|
|
expect($('li').length).toBe(2)
|
|
})
|
|
|
|
it('should not error when accessing routes that use Math.random() in App Router', async () => {
|
|
let res, body
|
|
|
|
res = await next.fetch('/app/prerendered/uncached/api')
|
|
expect(res.status).toBe(200)
|
|
body = await res.json()
|
|
expect(body).toEqual({
|
|
rand1: expect.any(Number),
|
|
rand2: expect.any(Number),
|
|
})
|
|
|
|
res = await next.fetch('/app/prerendered/unstable-cache/api')
|
|
expect(res.status).toBe(200)
|
|
body = await res.json()
|
|
expect(body).toEqual({
|
|
rand1: expect.any(Number),
|
|
rand2: expect.any(Number),
|
|
})
|
|
|
|
res = await next.fetch('/app/rendered/uncached/api')
|
|
expect(res.status).toBe(200)
|
|
body = await res.json()
|
|
expect(body).toEqual({
|
|
rand1: expect.any(Number),
|
|
rand2: expect.any(Number),
|
|
})
|
|
|
|
res = await next.fetch('/app/rendered/unstable-cache/api')
|
|
expect(res.status).toBe(200)
|
|
body = await res.json()
|
|
expect(body).toEqual({
|
|
rand1: expect.any(Number),
|
|
rand2: expect.any(Number),
|
|
})
|
|
})
|
|
|
|
it('should not error when accessing pages that use Math.random() in Pages Router', async () => {
|
|
let res, $
|
|
|
|
res = await next.fetch('/pages/gip/random')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/pages/gip/random')
|
|
expect($('li').length).toBe(2)
|
|
|
|
res = await next.fetch('/pages/gssp/random')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/pages/gssp/random')
|
|
expect($('li').length).toBe(2)
|
|
|
|
res = await next.fetch('/pages/gsp/random')
|
|
expect(res.status).toBe(200)
|
|
$ = await next.render$('/pages/gsp/random')
|
|
expect($('li').length).toBe(2)
|
|
})
|
|
|
|
it('should not error when accessing routes that use Math.random() in Pages Router', async () => {
|
|
let res, body
|
|
|
|
res = await next.fetch('/api/random')
|
|
expect(res.status).toBe(200)
|
|
body = await res.json()
|
|
expect(body).toEqual({
|
|
rand1: expect.any(Number),
|
|
rand2: expect.any(Number),
|
|
})
|
|
|
|
expect(body.rand1).not.toBe(body.rand2)
|
|
|
|
const first1 = body.rand1
|
|
const first2 = body.rand2
|
|
|
|
res = await next.fetch('/api/random')
|
|
body = await res.json()
|
|
expect(body.rand1).not.toBe(body.rand2)
|
|
expect(body.rand1).not.toBe(first1)
|
|
expect(body.rand2).not.toBe(first2)
|
|
})
|
|
})
|
|
})
|
|
})
|