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('accepts Vite emitted-asset records when a reachable module owns the emitted file', () => { const manifest = recursiveManifest(); manifest['index.html']!.assets = [ 'assets/entry-logo-a1.webp', 'assets/geist-latin-a1.woff2', ]; manifest['node_modules/font/files/geist-latin.woff2'] = { file: 'assets/geist-latin-a1.woff2', src: 'node_modules/font/files/geist-latin.woff2', }; expect(resolveViteAssetClosure(manifest).viteAssets).toEqual([ 'assets/entry-logo-a1.webp', 'assets/geist-latin-a1.woff2', ]); }); 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); }); });