Skip to content

Commit fdc8639

Browse files
committed
feat(@schematics/angular): configure Vitest for new projects and libraries
This commit updates the application and library schematics to configure Vitest as the unit testing framework, replacing Karma and Jasmine. Key changes: Application Schematic: - Sets '@angular/build:unit-test' as the default builder for the 'test' target. - Adds 'vitest' and 'jsdom' as default dev dependencies. - Removes Karma, Jasmine, and related packages from the generated 'package.json'. - Updates 'tsconfig.spec.json' to include 'vitest/globals' for type support. Library Schematic: - Conditionally configures the 'test' target with the '@angular/build:unit-test' builder if Vitest is detected in the workspace. - Dynamically sets the 'types' in 'tsconfig.spec.json' to 'vitest/globals' or 'jasmine' based on the presence of Vitest.
1 parent 0ae9c99 commit fdc8639

File tree

11 files changed

+70
-59
lines changed

11 files changed

+70
-59
lines changed

packages/schematics/angular/application/files/common-files/tsconfig.spec.json.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"compilerOptions": {
66
"outDir": "<%= relativePathToWorkspaceRoot %>/out-tsc/spec",
77
"types": [
8-
"jasmine"
8+
"vitest/globals"
99
]
1010
},
1111
"include": [

packages/schematics/angular/application/index.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,21 @@ function addDependenciesToPackageJson(options: ApplicationOptions): Rule {
183183
);
184184
}
185185

186+
if (!options.skipTests) {
187+
rules.push(
188+
addDependency('vitest', latestVersions['vitest'], {
189+
type: DependencyType.Dev,
190+
existing: ExistingBehavior.Skip,
191+
install: options.skipInstall ? InstallBehavior.None : InstallBehavior.Auto,
192+
}),
193+
addDependency('jsdom', latestVersions['jsdom'], {
194+
type: DependencyType.Dev,
195+
existing: ExistingBehavior.Skip,
196+
install: options.skipInstall ? InstallBehavior.None : InstallBehavior.Auto,
197+
}),
198+
);
199+
}
200+
186201
return chain(rules);
187202
}
188203

@@ -327,18 +342,13 @@ function addAppToWorkspaceFile(options: ApplicationOptions, appDir: string): Rul
327342
},
328343
},
329344
},
330-
test: options.minimal
331-
? undefined
332-
: {
333-
builder: Builders.BuildKarma,
334-
options: {
335-
polyfills: options.zoneless ? undefined : ['zone.js', 'zone.js/testing'],
336-
tsConfig: `${projectRoot}tsconfig.spec.json`,
337-
inlineStyleLanguage,
338-
assets: [{ 'glob': '**/*', 'input': `${projectRoot}public` }],
339-
styles: [`${sourceRoot}/styles.${options.style}`],
345+
test:
346+
options.skipTests || options.minimal
347+
? undefined
348+
: {
349+
builder: Builders.BuildUnitTest,
350+
options: {},
340351
},
341-
},
342352
},
343353
};
344354

packages/schematics/angular/application/index_spec.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -391,12 +391,6 @@ describe('Application Schematic', () => {
391391
expect(buildOpt.assets).toEqual([{ 'glob': '**/*', 'input': 'public' }]);
392392
expect(buildOpt.polyfills).toBeUndefined();
393393
expect(buildOpt.tsConfig).toEqual('tsconfig.app.json');
394-
395-
const testOpt = prj.architect.test.options;
396-
expect(testOpt.tsConfig).toEqual('tsconfig.spec.json');
397-
expect(testOpt.karmaConfig).toBeUndefined();
398-
expect(testOpt.assets).toEqual([{ 'glob': '**/*', 'input': 'public' }]);
399-
expect(testOpt.styles).toEqual(['src/styles.css']);
400394
});
401395

402396
it('should set values in angular.json correctly when using a style preprocessor', async () => {
@@ -407,8 +401,6 @@ describe('Application Schematic', () => {
407401
const prj = config.projects.foo;
408402
const buildOpt = prj.architect.build.options;
409403
expect(buildOpt.styles).toEqual(['src/styles.sass']);
410-
const testOpt = prj.architect.test.options;
411-
expect(testOpt.styles).toEqual(['src/styles.sass']);
412404
expect(tree.exists('src/styles.sass')).toBe(true);
413405
});
414406

@@ -421,9 +413,6 @@ describe('Application Schematic', () => {
421413

422414
const buildOpt = prj.architect.build.options;
423415
expect(buildOpt.inlineStyleLanguage).toBe('sass');
424-
425-
const testOpt = prj.architect.test.options;
426-
expect(testOpt.inlineStyleLanguage).toBe('sass');
427416
});
428417

429418
it('does not set "inlineStyleLanguage" in angular.json when not using a style preprocessor', async () => {
@@ -435,9 +424,6 @@ describe('Application Schematic', () => {
435424

436425
const buildOpt = prj.architect.build.options;
437426
expect(buildOpt.inlineStyleLanguage).toBeUndefined();
438-
439-
const testOpt = prj.architect.test.options;
440-
expect(testOpt.inlineStyleLanguage).toBeUndefined();
441427
});
442428

443429
it('does not set "inlineStyleLanguage" in angular.json when using CSS styles', async () => {
@@ -449,9 +435,6 @@ describe('Application Schematic', () => {
449435

450436
const buildOpt = prj.architect.build.options;
451437
expect(buildOpt.inlineStyleLanguage).toBeUndefined();
452-
453-
const testOpt = prj.architect.test.options;
454-
expect(testOpt.inlineStyleLanguage).toBeUndefined();
455438
});
456439

457440
it('should set the relative tsconfig paths', async () => {
@@ -482,12 +465,6 @@ describe('Application Schematic', () => {
482465
expect(buildOpt.tsConfig).toEqual('foo/tsconfig.app.json');
483466
expect(buildOpt.assets).toEqual([{ 'glob': '**/*', 'input': 'foo/public' }]);
484467

485-
const testOpt = project.architect.test.options;
486-
expect(testOpt.tsConfig).toEqual('foo/tsconfig.spec.json');
487-
expect(testOpt.karmaConfig).toBeUndefined();
488-
expect(testOpt.assets).toEqual([{ 'glob': '**/*', 'input': 'foo/public' }]);
489-
expect(testOpt.styles).toEqual(['foo/src/styles.css']);
490-
491468
const appTsConfig = readJsonFile(tree, '/foo/tsconfig.app.json');
492469
expect(appTsConfig.extends).toEqual('../tsconfig.json');
493470
const specTsConfig = readJsonFile(tree, '/foo/tsconfig.spec.json');

packages/schematics/angular/config/index_spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ describe('Config Schematic', () => {
5050
defaultAppOptions,
5151
workspaceTree,
5252
);
53+
54+
// Set builder to a karma builder for testing purposes
55+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
56+
const angularJson = applicationTree.readJson('angular.json') as any;
57+
angularJson['projects']['foo']['architect']['test']['builder'] = '@angular/build:karma';
58+
applicationTree.overwrite('angular.json', JSON.stringify(angularJson));
5359
});
5460

5561
describe(`when 'type' is 'karma'`, () => {

packages/schematics/angular/library/files/tsconfig.spec.json.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"compilerOptions": {
66
"outDir": "<%= relativePathToWorkspaceRoot %>/out-tsc/spec",
77
"types": [
8-
"jasmine"
8+
"<%= testTypesPackage %>"
99
]
1010
},
1111
"include": [

packages/schematics/angular/library/index.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ function addLibToWorkspaceFile(
9191
projectRoot: string,
9292
projectName: string,
9393
hasZoneDependency: boolean,
94+
hasVitest: boolean,
9495
): Rule {
9596
return updateWorkspace((workspace) => {
9697
workspace.projects.add({
@@ -112,13 +113,20 @@ function addLibToWorkspaceFile(
112113
},
113114
},
114115
},
115-
test: {
116-
builder: Builders.BuildKarma,
117-
options: {
118-
tsConfig: `${projectRoot}/tsconfig.spec.json`,
119-
polyfills: hasZoneDependency ? ['zone.js', 'zone.js/testing'] : undefined,
120-
},
121-
},
116+
test: hasVitest
117+
? {
118+
builder: Builders.BuildUnitTest,
119+
options: {
120+
tsConfig: `${projectRoot}/tsconfig.spec.json`,
121+
},
122+
}
123+
: {
124+
builder: Builders.BuildKarma,
125+
options: {
126+
tsConfig: `${projectRoot}/tsconfig.spec.json`,
127+
polyfills: hasZoneDependency ? ['zone.js', 'zone.js/testing'] : undefined,
128+
},
129+
},
122130
},
123131
});
124132
});
@@ -150,6 +158,7 @@ export default function (options: LibraryOptions): Rule {
150158

151159
const distRoot = `dist/${folderName}`;
152160
const sourceDir = `${libDir}/src/lib`;
161+
const hasVitest = getDependency(host, 'vitest') !== null;
153162

154163
const templateSource = apply(url('./files'), [
155164
applyTemplates({
@@ -163,6 +172,7 @@ export default function (options: LibraryOptions): Rule {
163172
angularLatestVersion: latestVersions.Angular.replace(/~|\^/, ''),
164173
tsLibLatestVersion: latestVersions['tslib'].replace(/~|\^/, ''),
165174
folderName,
175+
testTypesPackage: hasVitest ? 'vitest/globals' : 'jasmine',
166176
}),
167177
move(libDir),
168178
]);
@@ -171,7 +181,7 @@ export default function (options: LibraryOptions): Rule {
171181

172182
return chain([
173183
mergeWith(templateSource),
174-
addLibToWorkspaceFile(options, libDir, packageName, hasZoneDependency),
184+
addLibToWorkspaceFile(options, libDir, packageName, hasZoneDependency, hasVitest),
175185
options.skipPackageJson ? noop() : addDependenciesToPackageJson(!!options.skipInstall),
176186
options.skipTsConfig ? noop() : updateTsConfig(packageName, './' + distRoot),
177187
options.skipTsConfig

packages/schematics/angular/library/index_spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,17 @@ describe('Library Schematic', () => {
414414
expect(workspace.projects.foo.architect.test.builder).toBe('@angular/build:karma');
415415
});
416416

417+
it(`should add 'unit-test' test builder`, async () => {
418+
const packageJson = getJsonFileContent(workspaceTree, 'package.json');
419+
packageJson['devDependencies']['vitest'] = '^4.0.0';
420+
workspaceTree.overwrite('package.json', JSON.stringify(packageJson));
421+
422+
const tree = await schematicRunner.runSchematic('library', defaultOptions, workspaceTree);
423+
424+
const workspace = JSON.parse(tree.readContent('/angular.json'));
425+
expect(workspace.projects.foo.architect.test.builder).toBe('@angular/build:unit-test');
426+
});
427+
417428
describe('standalone=false', () => {
418429
const defaultNonStandaloneOptions = { ...defaultOptions, standalone: false };
419430

packages/schematics/angular/utility/latest-versions/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"karma-jasmine-html-reporter": "~2.1.0",
1616
"karma-jasmine": "~5.1.0",
1717
"karma": "~6.4.0",
18+
"jsdom": "^27.0.0",
1819
"less": "^4.2.0",
1920
"postcss": "^8.5.3",
2021
"protractor": "~7.0.0",
@@ -24,6 +25,7 @@
2425
"tslib": "^2.3.0",
2526
"ts-node": "~10.9.0",
2627
"typescript": "~5.9.2",
28+
"vitest": "^4.0.0",
2729
"zone.js": "~0.15.0"
2830
}
2931
}

packages/schematics/angular/utility/workspace-models.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export enum Builders {
2727
BrowserEsbuild = '@angular-devkit/build-angular:browser-esbuild',
2828
Karma = '@angular-devkit/build-angular:karma',
2929
BuildKarma = '@angular/build:karma',
30+
BuildUnitTest = '@angular/build:unit-test',
3031
TsLint = '@angular-devkit/build-angular:tslint',
3132
NgPackagr = '@angular-devkit/build-angular:ng-packagr',
3233
BuildNgPackagr = '@angular/build:ng-packagr',

packages/schematics/angular/workspace/files/package.json.template

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,7 @@
3434
},
3535
"devDependencies": {
3636
"@angular/cli": "<%= '^' + version %>",
37-
"@angular/compiler-cli": "<%= latestVersions.Angular %>",<% if (!minimal) { %>
38-
"@types/jasmine": "<%= latestVersions['@types/jasmine'] %>",
39-
"jasmine-core": "<%= latestVersions['jasmine-core'] %>",
40-
"karma": "<%= latestVersions['karma'] %>",
41-
"karma-chrome-launcher": "<%= latestVersions['karma-chrome-launcher'] %>",
42-
"karma-coverage": "<%= latestVersions['karma-coverage'] %>",
43-
"karma-jasmine": "<%= latestVersions['karma-jasmine'] %>",
44-
"karma-jasmine-html-reporter": "<%= latestVersions['karma-jasmine-html-reporter'] %>",<% } %>
37+
"@angular/compiler-cli": "<%= latestVersions.Angular %>",
4538
"typescript": "<%= latestVersions['typescript'] %>"
4639
}
4740
}

0 commit comments

Comments
 (0)