66 * found in the LICENSE file at https://angular.dev/license
77 */
88
9+ import assert from 'node:assert' ;
910import { mkdtemp , rm , writeFile } from 'node:fs/promises' ;
10- import { tmpdir } from 'node:os' ;
1111import { join } from 'node:path' ;
1212import {
13- BuildOutputFile ,
1413 BuildOutputFileType ,
1514 InitialFileRecord ,
15+ createOutputFile ,
1616} from '../../tools/esbuild/bundler-files' ;
1717import { generateIndexHtml } from './index-html-generator' ;
1818import { NormalizedApplicationBuildOptions } from './options' ;
@@ -21,7 +21,9 @@ describe('generateIndexHtml', () => {
2121 let tempDir : string ;
2222
2323 beforeEach ( async ( ) => {
24- tempDir = await mkdtemp ( join ( tmpdir ( ) , 'index-html-generator-spec-' ) ) ;
24+ const baseTmpDir = process . env [ 'TEST_TMPDIR' ] ;
25+ assert ( baseTmpDir , 'TEST_TMPDIR is not set' ) ;
26+ tempDir = await mkdtemp ( join ( baseTmpDir , 'index-html-generator-spec-' ) ) ;
2527 await writeFile (
2628 join ( tempDir , 'index.html' ) ,
2729 '<html><head><base href="/"></head><body><app-root></app-root></body></html>' ,
@@ -32,31 +34,23 @@ describe('generateIndexHtml', () => {
3234 await rm ( tempDir , { recursive : true , force : true } ) ;
3335 } ) ;
3436
35- function createOutputFile ( path : string ) : BuildOutputFile {
36- const text = `console.log(${ JSON . stringify ( path ) } );` ;
37-
38- return {
39- path,
40- text,
41- contents : Buffer . from ( text ) ,
42- type : BuildOutputFileType . Browser ,
43- } as unknown as BuildOutputFile ;
44- }
45-
46- function createOptions ( subresourceIntegrity : boolean ) : NormalizedApplicationBuildOptions {
37+ function createOptions (
38+ subresourceIntegrity : boolean ,
39+ preloadInitial = true ,
40+ ) : NormalizedApplicationBuildOptions {
4741 return {
4842 indexHtmlOptions : {
4943 input : join ( tempDir , 'index.html' ) ,
5044 insertionOrder : [ [ 'main.js' , true ] ] ,
51- preloadInitial : true ,
45+ preloadInitial,
5246 } ,
5347 subresourceIntegrity,
5448 baseHref : '/' ,
5549 security : { } ,
5650 } as unknown as NormalizedApplicationBuildOptions ;
5751 }
5852
59- it ( 'adds integrity metadata for every initial chunk when there are more than the module preload limit' , async ( ) => {
53+ it ( 'should add integrity metadata for every initial chunk when there are more than the module preload limit' , async ( ) => {
6054 const chunkCount = 15 ;
6155 const chunks = Array . from ( { length : chunkCount } , ( _ , i ) => `chunk-${ i } .js` ) ;
6256 const initialFiles = new Map < string , InitialFileRecord > ( [
@@ -69,46 +63,43 @@ describe('generateIndexHtml', () => {
6963 ] ,
7064 ) ,
7165 ] ) ;
72- const outputFiles = [ 'main.js' , ...chunks ] . map ( createOutputFile ) ;
66+ const outputFiles = [ 'main.js' , ...chunks ] . map ( ( path ) =>
67+ createOutputFile ( path , `console.log(${ JSON . stringify ( path ) } );` , BuildOutputFileType . Browser ) ,
68+ ) ;
7369
7470 const { csrContent, errors } = await generateIndexHtml (
7571 initialFiles ,
7672 outputFiles ,
7773 createOptions ( true ) ,
7874 ) ;
79- expect ( errors ) . toEqual ( [ ] ) ;
75+ expect ( errors ) . toHaveSize ( 0 ) ;
8076
81- const importMapMatch = / < s c r i p t t y p e = " i m p o r t m a p " > ( .* ?) < \/ s c r i p t > / . exec ( csrContent ) ;
82- const importMapIntegrity : Record < string , string > = importMapMatch
83- ? JSON . parse ( importMapMatch [ 1 ] ) . integrity
84- : { } ;
85-
86- for ( const chunk of chunks ) {
87- const hasPreloadIntegrity = new RegExp (
88- `<link rel="modulepreload" href="${ chunk } " integrity="sha384-[^"]+"` ,
89- ) . test ( csrContent ) ;
77+ for ( const chunk of chunks . slice ( 0 , 10 ) ) {
78+ expect ( csrContent ) . toContain ( `<link rel="modulepreload" href="${ chunk } " integrity="sha384` ) ;
79+ expect ( csrContent ) . not . toContain ( `./${ chunk } ` ) ;
80+ }
9081
91- expect ( hasPreloadIntegrity || `./ ${ chunk } ` in importMapIntegrity )
92- . withContext ( `Expected integrity metadata for ${ chunk } `)
93- . toBeTrue ( ) ;
82+ for ( const chunk of chunks . slice ( 10 ) ) {
83+ expect ( csrContent ) . toContain ( `./ ${ chunk } `) ;
84+ expect ( csrContent ) . not . toContain ( `<link rel="modulepreload" href=" ${ chunk } "` ) ;
9485 }
9586 } ) ;
9687
97- it ( 'adds integrity metadata for initial chunks when module preloads are disabled' , async ( ) => {
88+ it ( 'should add integrity metadata for initial chunks when module preloads are disabled' , async ( ) => {
9889 const initialFiles = new Map < string , InitialFileRecord > ( [
9990 [ 'main.js' , { entrypoint : true , name : 'main' , type : 'script' , serverFile : false , depth : 0 } ] ,
10091 [ 'chunk-a.js' , { entrypoint : false , type : 'script' , serverFile : false , depth : 1 } ] ,
10192 ] ) ;
102- const outputFiles = [ 'main.js' , 'chunk-a.js' ] . map ( createOutputFile ) ;
103- const options = createOptions ( true ) ;
104- options . indexHtmlOptions ! . preloadInitial = false ;
93+ const outputFiles = [ 'main.js' , 'chunk-a.js' ] . map ( ( path ) =>
94+ createOutputFile ( path , `console.log(${ JSON . stringify ( path ) } );` , BuildOutputFileType . Browser ) ,
95+ ) ;
96+ const options = createOptions ( true , false ) ;
10597
10698 const { csrContent, errors } = await generateIndexHtml ( initialFiles , outputFiles , options ) ;
107- expect ( errors ) . toEqual ( [ ] ) ;
108-
109- const importMapMatch = / < s c r i p t t y p e = " i m p o r t m a p " > ( .* ?) < \/ s c r i p t > / . exec ( csrContent ) ;
110- const importMapIntegrity : Record < string , string > = JSON . parse ( importMapMatch ! [ 1 ] ) . integrity ;
99+ expect ( errors ) . toHaveSize ( 0 ) ;
111100
112- expect ( Object . keys ( importMapIntegrity ) ) . toEqual ( [ './chunk-a.js' ] ) ;
101+ expect ( csrContent ) . toContain ( `"./${ outputFiles [ 1 ] . path } ":` ) ;
102+ expect ( csrContent ) . not . toContain ( `"./${ outputFiles [ 0 ] . path } ":` ) ;
103+ expect ( csrContent ) . not . toContain ( 'rel="modulepreload"' ) ;
113104 } ) ;
114105} ) ;
0 commit comments