Skip to content

Commit 9428e8c

Browse files
committed
feat(@angular-devkit/build-angular): support karma with esbuild
Adds a new "builderMode" setting for Karma that can be used to switch between webpack ("browser") and esbuild ("application"). It supports a third value "detect" that will use the same bundler that's also used for development builds. The detect mode is modelled after the logic used for the dev-server builder. This initial implementation doesn't properly support `--watch` mode or code coverage.
1 parent 4c99336 commit 9428e8c

File tree

8 files changed

+439
-14
lines changed

8 files changed

+439
-14
lines changed

packages/angular_devkit/build_angular/src/builders/karma/index.ts

Lines changed: 318 additions & 11 deletions
Large diffs are not rendered by default.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import { getTestBed } from '@angular/core/testing';
10+
import {
11+
BrowserDynamicTestingModule,
12+
platformBrowserDynamicTesting,
13+
} from '@angular/platform-browser-dynamic/testing';
14+
15+
// Initialize the Angular testing environment.
16+
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
17+
errorOnUnknownElements: true,
18+
errorOnUnknownProperties: true,
19+
});

packages/angular_devkit/build_angular/src/builders/karma/schema.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,12 @@
267267
"type": "string"
268268
}
269269
},
270+
"builderMode": {
271+
"type": "string",
272+
"description": "Determines how to build the code under test. If set to 'detect', attempts to follow the development builder.",
273+
"enum": ["detect", "browser", "application"],
274+
"default": "browser"
275+
},
270276
"webWorkerTsConfig": {
271277
"type": "string",
272278
"description": "TypeScript configuration for Web Worker modules."

packages/angular_devkit/build_angular/src/builders/karma/tests/behavior/code-coverage_spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ const coveragePath = 'coverage/lcov.info';
2323

2424
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget, isApplicationBuilder) => {
2525
describe('Behavior: "codeCoverage"', () => {
26+
if (isApplicationBuilder) {
27+
beforeEach(() => {
28+
pending('Code coverage not implemented yet for application builder');
29+
});
30+
}
31+
2632
beforeEach(() => {
2733
setupTarget(harness);
2834
});
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import { execute } from '../../index';
10+
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
11+
import { BuilderMode } from '../../schema';
12+
13+
const ESBUILD_LOG_TEXT = 'Application bundle generation complete.';
14+
15+
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget, isApplicationTarget) => {
16+
describe('option: "builderMode"', () => {
17+
beforeEach(() => {
18+
setupTarget(harness);
19+
});
20+
21+
it('"application" always uses esbuild', async () => {
22+
harness.useTarget('test', {
23+
...BASE_OPTIONS,
24+
builderMode: BuilderMode.Application,
25+
});
26+
27+
const { result, logs } = await harness.executeOnce();
28+
expect(result?.success).toBeTrue();
29+
expect(logs).toContain(
30+
jasmine.objectContaining({
31+
message: jasmine.stringMatching(ESBUILD_LOG_TEXT),
32+
}),
33+
);
34+
});
35+
36+
it('"browser" always uses webpack', async () => {
37+
harness.useTarget('test', {
38+
...BASE_OPTIONS,
39+
builderMode: BuilderMode.Browser,
40+
});
41+
42+
const { result, logs } = await harness.executeOnce();
43+
expect(result?.success).toBeTrue();
44+
expect(logs).not.toContain(
45+
jasmine.objectContaining({
46+
message: jasmine.stringMatching(ESBUILD_LOG_TEXT),
47+
}),
48+
);
49+
});
50+
51+
it('"detect" follows configuration of the development builder', async () => {
52+
harness.useTarget('test', {
53+
...BASE_OPTIONS,
54+
builderMode: BuilderMode.Detect,
55+
});
56+
57+
const { result, logs } = await harness.executeOnce();
58+
expect(result?.success).toBeTrue();
59+
if (isApplicationTarget) {
60+
expect(logs).toContain(
61+
jasmine.objectContaining({
62+
message: jasmine.stringMatching(ESBUILD_LOG_TEXT),
63+
}),
64+
);
65+
} else {
66+
expect(logs).not.toContain(
67+
jasmine.objectContaining({
68+
message: jasmine.stringMatching(ESBUILD_LOG_TEXT),
69+
}),
70+
);
71+
}
72+
});
73+
});
74+
});

packages/angular_devkit/build_angular/src/builders/karma/tests/options/code-coverage-exclude_spec.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,14 @@ import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup
1818

1919
const coveragePath = 'coverage/lcov.info';
2020

21-
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
21+
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget, isApplicationBuilder) => {
2222
describe('Option: "codeCoverageExclude"', () => {
23+
if (isApplicationBuilder) {
24+
beforeEach(() => {
25+
pending('Code coverage not implemented yet for application builder');
26+
});
27+
}
28+
2329
beforeEach(() => {
2430
setupTarget(harness);
2531
});

packages/angular_devkit/build_angular/src/builders/karma/tests/options/code-coverage_spec.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,14 @@ import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup
1919

2020
const coveragePath = 'coverage/lcov.info';
2121

22-
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
22+
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget, isApplicationBuilder) => {
2323
describe('Option: "codeCoverage"', () => {
24+
if (isApplicationBuilder) {
25+
beforeEach(() => {
26+
pending('Code coverage not implemented yet for application builder');
27+
});
28+
}
29+
2430
beforeEach(() => {
2531
setupTarget(harness);
2632
});

packages/angular_devkit/build_angular/src/builders/karma/tests/setup.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import { Schema } from '../schema';
9+
import { BuilderMode, Schema } from '../schema';
1010
import { BuilderHandlerFn } from '@angular-devkit/architect';
1111
import { json } from '@angular-devkit/core';
1212
import { ApplicationBuilderOptions as ApplicationSchema, buildApplication } from '@angular/build';
@@ -41,6 +41,7 @@ export const BASE_OPTIONS = Object.freeze<Schema>({
4141
browsers: 'ChromeHeadlessCI',
4242
progress: false,
4343
watch: false,
44+
builderMode: BuilderMode.Detect,
4445
});
4546

4647
const optionSchemaCache = new Map<string, json.schema.JsonSchema>();

0 commit comments

Comments
 (0)