fix: harden prerender publication boundary
This commit is contained in:
92
tests/unit/build-contract.test.ts
Normal file
92
tests/unit/build-contract.test.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { resolveViteAssetClosure } from '../../scripts/build-contract.mjs';
|
||||
import type { ViteManifest } from '../../scripts/prerender.mjs';
|
||||
|
||||
const recursiveManifest = (): ViteManifest => ({
|
||||
'index.html': {
|
||||
file: 'assets/entry-a1.js',
|
||||
src: 'index.html',
|
||||
isEntry: true,
|
||||
css: ['assets/entry-a1.css'],
|
||||
assets: ['assets/entry-logo-a1.webp'],
|
||||
imports: ['src/shared.ts'],
|
||||
dynamicImports: ['src/lazy.ts'],
|
||||
},
|
||||
'src/shared.ts': {
|
||||
file: 'assets/shared-b2.js',
|
||||
src: 'src/shared.ts',
|
||||
css: ['assets/shared-b2.css'],
|
||||
imports: ['src/deep.ts'],
|
||||
},
|
||||
'src/deep.ts': {
|
||||
file: 'assets/deep-c3.js',
|
||||
src: 'src/deep.ts',
|
||||
},
|
||||
'src/lazy.ts': {
|
||||
file: 'assets/lazy-d4.js',
|
||||
src: 'src/lazy.ts',
|
||||
css: ['assets/lazy-d4.css'],
|
||||
},
|
||||
});
|
||||
|
||||
describe('trusted Vite asset closure', () => {
|
||||
it('resolves the exact recursive executable, preload, style, and Vite asset sets', () => {
|
||||
expect(resolveViteAssetClosure(recursiveManifest())).toEqual({
|
||||
entryModule: 'assets/entry-a1.js',
|
||||
executableModules: [
|
||||
'assets/deep-c3.js',
|
||||
'assets/entry-a1.js',
|
||||
'assets/lazy-d4.js',
|
||||
'assets/shared-b2.js',
|
||||
],
|
||||
modulePreloads: [
|
||||
'assets/deep-c3.js',
|
||||
'assets/entry-a1.js',
|
||||
'assets/shared-b2.js',
|
||||
],
|
||||
styles: [
|
||||
'assets/entry-a1.css',
|
||||
'assets/lazy-d4.css',
|
||||
'assets/shared-b2.css',
|
||||
],
|
||||
viteAssets: ['assets/entry-logo-a1.webp'],
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: 'a missing exact index.html entry',
|
||||
mutate: (manifest: ViteManifest) => {
|
||||
manifest['src/entry-client.ts'] = manifest['index.html']!;
|
||||
delete manifest['index.html'];
|
||||
},
|
||||
error: /exact index\.html/i,
|
||||
},
|
||||
{
|
||||
name: 'an unreachable manifest record',
|
||||
mutate: (manifest: ViteManifest) => {
|
||||
manifest['src/orphan.ts'] = { file: 'assets/orphan.js', src: 'src/orphan.ts' };
|
||||
},
|
||||
error: /unreachable manifest/i,
|
||||
},
|
||||
{
|
||||
name: 'an unsafe emitted path',
|
||||
mutate: (manifest: ViteManifest) => {
|
||||
manifest['src/shared.ts']!.file = '../outside.js';
|
||||
},
|
||||
error: /unsafe.*path/i,
|
||||
},
|
||||
{
|
||||
name: 'a missing recursive import',
|
||||
mutate: (manifest: ViteManifest) => {
|
||||
manifest['src/shared.ts']!.imports = ['src/missing.ts'];
|
||||
},
|
||||
error: /missing manifest import/i,
|
||||
},
|
||||
])('rejects $name', ({ mutate, error }) => {
|
||||
const manifest = recursiveManifest();
|
||||
mutate(manifest);
|
||||
|
||||
expect(() => resolveViteAssetClosure(manifest)).toThrow(error);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user