Skip to content

Commit 3cb12e2

Browse files
committed
fix(@angular/build): avoid internal karma request cache for assets
The internal karma common middleware that handles requests converts the to be cached data into a string when stored. This can lead to invalid data when the cached string is then sent in a followup request if the original content was not intended to be a string. To avoid this problem, asset files are now explicitly not cached by karma's middleware. Ref: https://github.com/karma-runner/karma/blob/84f85e7016efc2266fa6b3465f494a3fa151c85c/lib/middleware/common.js#L72 (cherry picked from commit 90d1db3)
1 parent 3e3abf4 commit 3cb12e2

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

packages/angular/build/src/builders/karma/application_builder.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class AngularAssetsMiddleware {
8484
const file = this.latestBuildFiles.files[pathname];
8585

8686
if (file?.origin === 'disk') {
87-
this.serveFile(file.inputPath, undefined, res);
87+
this.serveFile(file.inputPath, undefined, res, undefined, undefined, /* doNotCache */ true);
8888

8989
return;
9090
} else if (file?.origin === 'memory') {

packages/angular/build/src/builders/karma/tests/behavior/rebuilds_spec.ts

+55
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { concatMap, count, debounceTime, distinctUntilChanged, take, timeout } f
1010
import { execute } from '../../index';
1111
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
1212
import { BuilderOutput } from '@angular-devkit/architect';
13+
import { randomBytes } from 'node:crypto';
1314

1415
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
1516
describe('Behavior: "Rebuilds"', () => {
@@ -68,5 +69,59 @@ describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
6869

6970
expect(buildCount).toBe(expectedSequence.length);
7071
});
72+
73+
it('correctly serves binary assets on rebuilds', async () => {
74+
await harness.writeFiles({
75+
'./src/random.bin': randomBytes(1024),
76+
'./src/app/app.component.spec.ts': `
77+
describe('AppComponent', () => {
78+
it('should fetch binary file with correct size', async () => {
79+
const resp = await fetch('/random.bin');
80+
const data = await resp.arrayBuffer();
81+
expect(data.byteLength).toBe(1024);
82+
});
83+
});`,
84+
});
85+
86+
harness.useTarget('test', {
87+
...BASE_OPTIONS,
88+
watch: true,
89+
assets: ['src/random.bin'],
90+
});
91+
92+
interface OutputCheck {
93+
(result: BuilderOutput | undefined): Promise<void>;
94+
}
95+
96+
const expectedSequence: OutputCheck[] = [
97+
async (result) => {
98+
// Karma run should succeed.
99+
expect(result?.success).withContext('Initial test run should succeed').toBeTrue();
100+
// Modify test file to trigger a rebuild
101+
await harness.appendToFile(
102+
'src/app/app.component.spec.ts',
103+
`\n;console.log('modified');`,
104+
);
105+
},
106+
async (result) => {
107+
expect(result?.success).withContext('Test should succeed again').toBeTrue();
108+
},
109+
];
110+
111+
const buildCount = await harness
112+
.execute({ outputLogsOnFailure: true })
113+
.pipe(
114+
timeout(60000),
115+
debounceTime(500),
116+
concatMap(async ({ result }, index) => {
117+
await expectedSequence[index](result);
118+
}),
119+
take(expectedSequence.length),
120+
count(),
121+
)
122+
.toPromise();
123+
124+
expect(buildCount).toBe(expectedSequence.length);
125+
});
71126
});
72127
});

0 commit comments

Comments
 (0)