Skip to content

Commit 342ab4a

Browse files
drakeo338alan-agius4
authored andcommitted
test(@angular/build): simplify index HTML generator integrity specs
Use TEST_TMPDIR for the temporary directory, reuse createOutputFile from the bundler files module, follow the 'should ...' naming convention and assert directly on the generated HTML.
1 parent 089d394 commit 342ab4a

1 file changed

Lines changed: 31 additions & 40 deletions

File tree

‎packages/angular/build/src/builders/application/index-html-generator_spec.ts‎

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9+
import assert from 'node:assert';
910
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
10-
import { tmpdir } from 'node:os';
1111
import { join } from 'node:path';
1212
import {
13-
BuildOutputFile,
1413
BuildOutputFileType,
1514
InitialFileRecord,
15+
createOutputFile,
1616
} from '../../tools/esbuild/bundler-files';
1717
import { generateIndexHtml } from './index-html-generator';
1818
import { 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 = /<script type="importmap">(.*?)<\/script>/.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 = /<script type="importmap">(.*?)<\/script>/.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

Comments
 (0)