Skip to content

Commit e8951a8

Browse files
committed
test: add some unit tests about static html blobs and fallbacks
1 parent 43b8488 commit e8951a8

File tree

1 file changed

+206
-44
lines changed

1 file changed

+206
-44
lines changed

src/build/content/static.test.ts

Lines changed: 206 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import { Buffer } from 'node:buffer'
1+
import { readFile } from 'node:fs/promises'
22
import { join } from 'node:path'
33
import { inspect } from 'node:util'
44

55
import type { NetlifyPluginOptions } from '@netlify/build'
66
import glob from 'fast-glob'
7+
import type { PrerenderManifest } from 'next/dist/build/index.js'
78
import { beforeEach, describe, expect, Mock, test, vi } from 'vitest'
89

9-
import { mockFileSystem } from '../../../tests/index.js'
10+
import { decodeBlobKey, encodeBlobKey, mockFileSystem } from '../../../tests/index.js'
1011
import { type FixtureTestContext } from '../../../tests/utils/contexts.js'
1112
import { createFsFixture } from '../../../tests/utils/fixture.js'
1213
import { PluginContext, RequiredServerFilesManifest } from '../plugin-context.js'
@@ -21,20 +22,33 @@ type Context = FixtureTestContext & {
2122
const createFsFixtureWithBasePath = (
2223
fixture: Record<string, string>,
2324
ctx: Omit<Context, 'pluginContext'>,
24-
basePath = '',
25+
26+
{
27+
basePath = '',
28+
// eslint-disable-next-line unicorn/no-useless-undefined
29+
i18n = undefined,
30+
dynamicRoutes = {},
31+
}: {
32+
basePath?: string
33+
i18n?: Pick<NonNullable<RequiredServerFilesManifest['config']['i18n']>, 'locales'>
34+
dynamicRoutes?: {
35+
[route: string]: Pick<PrerenderManifest['dynamicRoutes'][''], 'fallback'>
36+
}
37+
} = {},
2538
) => {
2639
return createFsFixture(
2740
{
28-
[join(ctx.publishDir, 'prerender-manifest.json')]: JSON.stringify({ dynamicRoutes: [] }),
2941
...fixture,
3042
[join(ctx.publishDir, 'routes-manifest.json')]: JSON.stringify({ basePath }),
3143
[join(ctx.publishDir, 'required-server-files.json')]: JSON.stringify({
3244
relativeAppDir: ctx.relativeAppDir,
3345
appDir: ctx.relativeAppDir,
3446
config: {
3547
distDir: ctx.publishDir,
48+
i18n,
3649
},
3750
} as Pick<RequiredServerFilesManifest, 'relativeAppDir' | 'appDir'>),
51+
[join(ctx.publishDir, 'prerender-manifest.json')]: JSON.stringify({ dynamicRoutes }),
3852
},
3953
ctx,
4054
)
@@ -122,7 +136,7 @@ describe('Regular Repository layout', () => {
122136
'.next/static/sub-dir/test2.js': '',
123137
},
124138
ctx,
125-
'/base/path',
139+
{ basePath: '/base/path' },
126140
)
127141

128142
await copyStaticAssets(pluginContext)
@@ -169,7 +183,7 @@ describe('Regular Repository layout', () => {
169183
'public/another-asset.json': '',
170184
},
171185
ctx,
172-
'/base/path',
186+
{ basePath: '/base/path' },
173187
)
174188

175189
await copyStaticAssets(pluginContext)
@@ -183,26 +197,100 @@ describe('Regular Repository layout', () => {
183197
)
184198
})
185199

186-
test<Context>('should copy the static pages to the publish directory if there are no corresponding JSON files', async ({
187-
pluginContext,
188-
...ctx
189-
}) => {
190-
await createFsFixtureWithBasePath(
191-
{
192-
'.next/server/pages/test.html': '',
193-
'.next/server/pages/test2.html': '',
194-
'.next/server/pages/test3.json': '',
195-
},
196-
ctx,
197-
)
200+
describe('should copy the static pages to the publish directory if there are no corresponding JSON files and mark wether html file is a fallback', () => {
201+
test<Context>('no i18n', async ({ pluginContext, ...ctx }) => {
202+
await createFsFixtureWithBasePath(
203+
{
204+
'.next/server/pages/test.html': '',
205+
'.next/server/pages/test2.html': '',
206+
'.next/server/pages/test3.json': '',
207+
'.next/server/pages/blog/[slug].html': '',
208+
},
209+
ctx,
210+
{
211+
dynamicRoutes: {
212+
'/blog/[slug]': {
213+
fallback: '/blog/[slug].html',
214+
},
215+
},
216+
},
217+
)
198218

199-
await copyStaticContent(pluginContext)
200-
const files = await glob('**/*', { cwd: pluginContext.blobDir, dot: true })
219+
await copyStaticContent(pluginContext)
220+
const files = await glob('**/*', { cwd: pluginContext.blobDir, dot: true })
221+
222+
const expectedStaticPages = ['blog/[slug].html', 'test.html', 'test2.html']
223+
const expectedFallbacks = new Set(['blog/[slug].html'])
224+
225+
expect(files.map((path) => decodeBlobKey(path)).sort()).toEqual(expectedStaticPages)
226+
227+
for (const page of expectedStaticPages) {
228+
const expectedIsFallback = expectedFallbacks.has(page)
229+
230+
const blob = JSON.parse(
231+
await readFile(join(pluginContext.blobDir, await encodeBlobKey(page)), 'utf-8'),
232+
)
201233

202-
expect(files.map((path) => Buffer.from(path, 'base64').toString('utf-8')).sort()).toEqual([
203-
'test.html',
204-
'test2.html',
205-
])
234+
expect(blob, `${page} should ${expectedIsFallback ? '' : 'not '}be a fallback`).toEqual({
235+
html: '',
236+
isFallback: expectedIsFallback,
237+
})
238+
}
239+
})
240+
241+
test<Context>('with i18n', async ({ pluginContext, ...ctx }) => {
242+
await createFsFixtureWithBasePath(
243+
{
244+
'.next/server/pages/de/test.html': '',
245+
'.next/server/pages/de/test2.html': '',
246+
'.next/server/pages/de/test3.json': '',
247+
'.next/server/pages/de/blog/[slug].html': '',
248+
'.next/server/pages/en/test.html': '',
249+
'.next/server/pages/en/test2.html': '',
250+
'.next/server/pages/en/test3.json': '',
251+
'.next/server/pages/en/blog/[slug].html': '',
252+
},
253+
ctx,
254+
{
255+
dynamicRoutes: {
256+
'/blog/[slug]': {
257+
fallback: '/blog/[slug].html',
258+
},
259+
},
260+
i18n: {
261+
locales: ['en', 'de'],
262+
},
263+
},
264+
)
265+
266+
await copyStaticContent(pluginContext)
267+
const files = await glob('**/*', { cwd: pluginContext.blobDir, dot: true })
268+
269+
const expectedStaticPages = [
270+
'de/blog/[slug].html',
271+
'de/test.html',
272+
'de/test2.html',
273+
'en/blog/[slug].html',
274+
'en/test.html',
275+
'en/test2.html',
276+
]
277+
const expectedFallbacks = new Set(['en/blog/[slug].html', 'de/blog/[slug].html'])
278+
279+
expect(files.map((path) => decodeBlobKey(path)).sort()).toEqual(expectedStaticPages)
280+
281+
for (const page of expectedStaticPages) {
282+
const expectedIsFallback = expectedFallbacks.has(page)
283+
284+
const blob = JSON.parse(
285+
await readFile(join(pluginContext.blobDir, await encodeBlobKey(page)), 'utf-8'),
286+
)
287+
288+
expect(blob, `${page} should ${expectedIsFallback ? '' : 'not '}be a fallback`).toEqual({
289+
html: '',
290+
isFallback: expectedIsFallback,
291+
})
292+
}
293+
})
206294
})
207295

208296
test<Context>('should not copy the static pages to the publish directory if there are corresponding JSON files', async ({
@@ -270,7 +358,7 @@ describe('Mono Repository', () => {
270358
'apps/app-1/.next/static/sub-dir/test2.js': '',
271359
},
272360
ctx,
273-
'/base/path',
361+
{ basePath: '/base/path' },
274362
)
275363

276364
await copyStaticAssets(pluginContext)
@@ -317,7 +405,7 @@ describe('Mono Repository', () => {
317405
'apps/app-1/public/another-asset.json': '',
318406
},
319407
ctx,
320-
'/base/path',
408+
{ basePath: '/base/path' },
321409
)
322410

323411
await copyStaticAssets(pluginContext)
@@ -331,26 +419,100 @@ describe('Mono Repository', () => {
331419
)
332420
})
333421

334-
test<Context>('should copy the static pages to the publish directory if there are no corresponding JSON files', async ({
335-
pluginContext,
336-
...ctx
337-
}) => {
338-
await createFsFixtureWithBasePath(
339-
{
340-
'apps/app-1/.next/server/pages/test.html': '',
341-
'apps/app-1/.next/server/pages/test2.html': '',
342-
'apps/app-1/.next/server/pages/test3.json': '',
343-
},
344-
ctx,
345-
)
422+
describe('should copy the static pages to the publish directory if there are no corresponding JSON files and mark wether html file is a fallback', () => {
423+
test<Context>('no i18n', async ({ pluginContext, ...ctx }) => {
424+
await createFsFixtureWithBasePath(
425+
{
426+
'apps/app-1/.next/server/pages/test.html': '',
427+
'apps/app-1/.next/server/pages/test2.html': '',
428+
'apps/app-1/.next/server/pages/test3.json': '',
429+
'apps/app-1/.next/server/pages/blog/[slug].html': '',
430+
},
431+
ctx,
432+
{
433+
dynamicRoutes: {
434+
'/blog/[slug]': {
435+
fallback: '/blog/[slug].html',
436+
},
437+
},
438+
},
439+
)
346440

347-
await copyStaticContent(pluginContext)
348-
const files = await glob('**/*', { cwd: pluginContext.blobDir, dot: true })
441+
await copyStaticContent(pluginContext)
442+
const files = await glob('**/*', { cwd: pluginContext.blobDir, dot: true })
443+
444+
const expectedStaticPages = ['blog/[slug].html', 'test.html', 'test2.html']
445+
const expectedFallbacks = new Set(['blog/[slug].html'])
446+
447+
expect(files.map((path) => decodeBlobKey(path)).sort()).toEqual(expectedStaticPages)
448+
449+
for (const page of expectedStaticPages) {
450+
const expectedIsFallback = expectedFallbacks.has(page)
451+
452+
const blob = JSON.parse(
453+
await readFile(join(pluginContext.blobDir, await encodeBlobKey(page)), 'utf-8'),
454+
)
349455

350-
expect(files.map((path) => Buffer.from(path, 'base64').toString('utf-8')).sort()).toEqual([
351-
'test.html',
352-
'test2.html',
353-
])
456+
expect(blob, `${page} should ${expectedIsFallback ? '' : 'not '}be a fallback`).toEqual({
457+
html: '',
458+
isFallback: expectedIsFallback,
459+
})
460+
}
461+
})
462+
463+
test<Context>('with i18n', async ({ pluginContext, ...ctx }) => {
464+
await createFsFixtureWithBasePath(
465+
{
466+
'apps/app-1/.next/server/pages/de/test.html': '',
467+
'apps/app-1/.next/server/pages/de/test2.html': '',
468+
'apps/app-1/.next/server/pages/de/test3.json': '',
469+
'apps/app-1/.next/server/pages/de/blog/[slug].html': '',
470+
'apps/app-1/.next/server/pages/en/test.html': '',
471+
'apps/app-1/.next/server/pages/en/test2.html': '',
472+
'apps/app-1/.next/server/pages/en/test3.json': '',
473+
'apps/app-1/.next/server/pages/en/blog/[slug].html': '',
474+
},
475+
ctx,
476+
{
477+
dynamicRoutes: {
478+
'/blog/[slug]': {
479+
fallback: '/blog/[slug].html',
480+
},
481+
},
482+
i18n: {
483+
locales: ['en', 'de'],
484+
},
485+
},
486+
)
487+
488+
await copyStaticContent(pluginContext)
489+
const files = await glob('**/*', { cwd: pluginContext.blobDir, dot: true })
490+
491+
const expectedStaticPages = [
492+
'de/blog/[slug].html',
493+
'de/test.html',
494+
'de/test2.html',
495+
'en/blog/[slug].html',
496+
'en/test.html',
497+
'en/test2.html',
498+
]
499+
const expectedFallbacks = new Set(['en/blog/[slug].html', 'de/blog/[slug].html'])
500+
501+
expect(files.map((path) => decodeBlobKey(path)).sort()).toEqual(expectedStaticPages)
502+
503+
for (const page of expectedStaticPages) {
504+
const expectedIsFallback = expectedFallbacks.has(page)
505+
506+
const blob = JSON.parse(
507+
await readFile(join(pluginContext.blobDir, await encodeBlobKey(page)), 'utf-8'),
508+
)
509+
510+
expect(blob, `${page} should ${expectedIsFallback ? '' : 'not '}be a fallback`).toEqual({
511+
html: '',
512+
isFallback: expectedIsFallback,
513+
})
514+
}
515+
})
354516
})
355517

356518
test<Context>('should not copy the static pages to the publish directory if there are corresponding JSON files', async ({

0 commit comments

Comments
 (0)