Skip to content

Commit 62ed00c

Browse files
committed
test: add test for ISR case that always return same body
1 parent aab8803 commit 62ed00c

File tree

5 files changed

+122
-0
lines changed

5 files changed

+122
-0
lines changed

tests/e2e/page-router.test.ts

+39
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -494,6 +494,45 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => {
494
'.env.production.local': 'defined in .env.production.local',
494
'.env.production.local': 'defined in .env.production.local',
495
})
495
})
496
})
496
})
497+
498+
test('ISR pages that are the same after regeneration execute background getStaticProps uninterrupted', async ({
499+
page,
500+
pageRouter,
501+
}) => {
502+
const slug = Date.now()
503+
504+
await page.goto(new URL(`always-the-same-body/${slug}`, pageRouter.url).href)
505+
506+
await new Promise((resolve) => setTimeout(resolve, 15_000))
507+
508+
await page.goto(new URL(`always-the-same-body/${slug}`, pageRouter.url).href)
509+
510+
await new Promise((resolve) => setTimeout(resolve, 15_000))
511+
512+
await page.goto(new URL(`always-the-same-body/${slug}`, pageRouter.url).href)
513+
514+
await new Promise((resolve) => setTimeout(resolve, 15_000))
515+
516+
// keep lambda executing to allow for background getStaticProps to finish in case background work execution was suspended
517+
await fetch(new URL(`api/sleep-5`, pageRouter.url).href)
518+
519+
const response = await fetch(new URL(`read-static-props-blobs/${slug}`, pageRouter.url).href)
520+
expect(response.ok, 'response for stored data status should not fail').toBe(true)
521+
522+
const data = await response.json()
523+
524+
expect(typeof data.start, 'timestamp of getStaticProps start should be a number').toEqual(
525+
'number',
526+
)
527+
expect(typeof data.end, 'timestamp of getStaticProps end should be a number').toEqual('number')
528+
529+
// duration should be around 5s overall, due to 5s timeout, but this is not exact so let's be generous and allow 10 seconds
530+
// which is still less than 15 seconds between requests
531+
expect(
532+
data.end - data.start,
533+
'getStaticProps duration should not be longer than 10 seconds',
534+
).toBeLessThan(10_000)
535+
})
497
})
536
})
498

537

499
test.describe('Page Router with basePath and i18n', () => {
538
test.describe('Page Router with basePath and i18n', () => {
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { getDeployStore } from '@netlify/blobs'
2+
import { Context } from '@netlify/functions'
3+
4+
function numberOrNull(value: string | null) {
5+
if (!value) {
6+
return null
7+
}
8+
9+
const maybeNumber = parseInt(value)
10+
return isNaN(maybeNumber) ? null : maybeNumber
11+
}
12+
13+
// intentionally using Netlify Function to not hit Next.js server handler function instance
14+
// to avoid potentially resuming suspended execution
15+
export default async function handler(_request: Request, context: Context) {
16+
const slug = context.params['slug']
17+
18+
const store = getDeployStore({ name: 'get-static-props-tracker', consistency: 'strong' })
19+
20+
const [start, end] = await Promise.all([store.get(`${slug}-start`), store.get(`${slug}-end`)])
21+
22+
return Response.json({ slug, start: numberOrNull(start), end: numberOrNull(end) })
23+
}
24+
25+
export const config = {
26+
path: '/read-static-props-blobs/:slug',
27+
}

tests/fixtures/page-router/package.json

+1
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -8,6 +8,7 @@
8
"build": "next build"
8
"build": "next build"
9
},
9
},
10
"dependencies": {
10
"dependencies": {
11+
"@netlify/blobs": "^8.1.0",
11
"@netlify/functions": "^2.7.0",
12
"@netlify/functions": "^2.7.0",
12
"next": "latest",
13
"next": "latest",
13
"react": "18.2.0",
14
"react": "18.2.0",
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { getDeployStore } from '@netlify/blobs'
2+
3+
const Show = ({ slug }) => {
4+
// ensure that the content is stable to trigger 304 responses
5+
return <pre>{slug}</pre>
6+
}
7+
8+
/** @type {import('next').getStaticPaths} */
9+
export async function getStaticPaths() {
10+
return {
11+
paths: [],
12+
fallback: 'blocking',
13+
}
14+
}
15+
16+
/** @type {import('next').GetStaticProps} */
17+
export async function getStaticProps({ params }) {
18+
const store = getDeployStore({ name: 'get-static-props-tracker', consistency: 'strong' })
19+
20+
const start = Date.now()
21+
22+
console.log(`[timestamp] ${params.slug} getStaticProps start`)
23+
24+
const storeStartPromise = store.set(`${params.slug}-start`, start).then(() => {
25+
console.log(`[timestamp] ${params.slug} getStaticProps start stored`)
26+
})
27+
28+
// simulate a long running operation
29+
await new Promise((resolve) => setTimeout(resolve, 5000))
30+
31+
const storeEndPromise = store.set(`${params.slug}-end`, Date.now()).then(() => {
32+
console.log(`[timestamp] ${params.slug} getStaticProps end stored`)
33+
})
34+
35+
console.log(
36+
`[timestamp] ${params.slug} getStaticProps end (duration: ${(Date.now() - start) / 1000}s)`,
37+
)
38+
39+
await Promise.all([storeStartPromise, storeEndPromise])
40+
41+
// ensure that the data is stable and always the same to trigger 304 responses
42+
return {
43+
props: {
44+
slug: params.slug,
45+
},
46+
revalidate: 5,
47+
}
48+
}
49+
50+
export default Show
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default async function handler(req, res) {
2+
await new Promise((resolve) => setTimeout(resolve, 5000))
3+
4+
res.json({ message: 'ok' })
5+
}

0 commit comments

Comments
 (0)