Skip to content

Commit de8f5a7

Browse files
committed
fix(@angular/build): add @angular/compiler to ensure the JIT compiler is available specifically for Vitest tests that use providersFile.
Fixes #31993
1 parent 630584e commit de8f5a7

File tree

3 files changed

+76
-3
lines changed

3 files changed

+76
-3
lines changed

packages/angular/build/src/builders/unit-test/options.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,18 @@ export async function normalizeOptions(
135135
};
136136
}
137137

138-
export function injectTestingPolyfills(polyfills: string[] = []): string[] {
139-
return polyfills.includes('zone.js') ? [...polyfills, 'zone.js/testing'] : polyfills;
138+
export function injectTestingPolyfills(
139+
polyfills: string[] = [],
140+
runner?: Runner,
141+
hasProvidersFile?: boolean,
142+
): string[] {
143+
const testPolyfills = polyfills.includes('zone.js')
144+
? [...polyfills, 'zone.js/testing']
145+
: polyfills;
146+
147+
if (runner === Runner.Vitest && hasProvidersFile) {
148+
testPolyfills.push('@angular/compiler');
149+
}
150+
151+
return testPolyfills;
140152
}

packages/angular/build/src/builders/unit-test/runners/vitest/build-options.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { toPosixPath } from '../../../../utils/path';
1111
import type { ApplicationBuilderInternalOptions } from '../../../application/options';
1212
import { OutputHashing } from '../../../application/schema';
1313
import { NormalizedUnitTestBuilderOptions, injectTestingPolyfills } from '../../options';
14+
import { Runner } from '../../schema';
1415
import { findTests, getTestEntrypoints } from '../../test-discovery';
1516
import { RunnerOptions } from '../api';
1617

@@ -130,7 +131,11 @@ export async function getVitestBuildOptions(
130131
externalDependencies,
131132
};
132133

133-
buildOptions.polyfills = injectTestingPolyfills(buildOptions.polyfills);
134+
buildOptions.polyfills = injectTestingPolyfills(
135+
buildOptions.polyfills,
136+
Runner.Vitest,
137+
!!providersFile,
138+
);
134139

135140
const testBedInitContents = createTestBedInitVirtualFile(
136141
providersFile,

packages/angular/build/src/builders/unit-test/tests/options/providers-file_spec.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,61 @@ describeBuilder(execute, UNIT_TEST_BUILDER_INFO, (harness) => {
6060
const { result } = await harness.executeOnce();
6161
expect(result?.success).toBeTrue();
6262
});
63+
64+
it('should work with providers that inject services requiring JIT compilation', async () => {
65+
// This test reproduces the issue from https://github.com/angular/angular-cli/issues/31993
66+
// where using providersFile with a service that injects Router causes JIT compilation errors
67+
await harness.writeFiles({
68+
'src/test.service.ts': `
69+
import { Injectable, inject } from '@angular/core';
70+
import { Router } from '@angular/router';
71+
72+
@Injectable({ providedIn: 'root' })
73+
export class TestService {
74+
router = inject(Router);
75+
}
76+
`,
77+
'src/test.providers.ts': `
78+
import { TestService } from './test.service';
79+
export default [TestService];
80+
`,
81+
'src/app/app.component.spec.ts': `
82+
import { TestBed } from '@angular/core/testing';
83+
import { AppComponent } from './app.component';
84+
import { TestService } from '../test.service';
85+
import { describe, expect, it } from 'vitest';
86+
87+
describe('AppComponent', () => {
88+
it('should create the app and inject TestService', () => {
89+
TestBed.configureTestingModule({
90+
declarations: [AppComponent],
91+
});
92+
const fixture = TestBed.createComponent(AppComponent);
93+
const app = fixture.componentInstance;
94+
const testService = TestBed.inject(TestService);
95+
expect(app).toBeTruthy();
96+
expect(testService).toBeTruthy();
97+
expect(testService.router).toBeTruthy();
98+
});
99+
});
100+
`,
101+
});
102+
await harness.modifyFile('src/tsconfig.spec.json', (content) => {
103+
const tsConfig = JSON.parse(content);
104+
tsConfig.files ??= [];
105+
tsConfig.files.push('test.service.ts', 'test.providers.ts');
106+
107+
return JSON.stringify(tsConfig);
108+
});
109+
110+
harness.useTarget('test', {
111+
...BASE_OPTIONS,
112+
providersFile: 'src/test.providers.ts',
113+
});
114+
115+
const { result } = await harness.executeOnce();
116+
117+
expect(result?.success).toBeTrue();
118+
});
63119
});
64120
});

0 commit comments

Comments
 (0)