Skip to content

Commit 7eb0803

Browse files
alan-agius4vikerman
authored andcommitted
fix(@angular-devkit/build-angular): only collect coverage from files under sourceRoot (#11974)
In some cases when having libraries within the workspace this is causing a `Maximum call stack size exceeded`, Also for libraries coverage should be collected with the respective `ng test` Closes #11934
1 parent 7f67c64 commit 7eb0803

File tree

4 files changed

+58
-3
lines changed

4 files changed

+58
-3
lines changed

packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ export interface WebpackTestOptions extends BuildOptions {
7474
export interface WebpackConfigOptions<T = BuildOptions> {
7575
root: string;
7676
projectRoot: string;
77+
sourceRoot?: string;
7778
buildOptions: T;
7879
tsConfig: ts.ParsedCommandLine;
7980
tsConfigPath: string;

packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/test.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { WebpackConfigOptions, WebpackTestOptions } from '../build-options';
2323
export function getTestConfig(
2424
wco: WebpackConfigOptions<WebpackTestOptions>,
2525
): webpack.Configuration {
26-
const { root, buildOptions } = wco;
26+
const { root, buildOptions, sourceRoot: include } = wco;
2727

2828
const extraRules: webpack.Rule[] = [];
2929
const extraPlugins: webpack.Plugin[] = [];
@@ -46,10 +46,12 @@ export function getTestConfig(
4646
}
4747

4848
extraRules.push({
49-
test: /\.(js|ts)$/, loader: 'istanbul-instrumenter-loader',
49+
test: /\.(js|ts)$/,
50+
loader: 'istanbul-instrumenter-loader',
5051
options: { esModules: true },
5152
enforce: 'post',
5253
exclude,
54+
include,
5355
});
5456
}
5557

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,13 @@ export class KarmaBuilder implements Builder<KarmaBuilderSchema> {
7171
karmaOptions.browsers = options.browsers.split(',');
7272
}
7373

74+
const sourceRoot = builderConfig.sourceRoot && resolve(root, builderConfig.sourceRoot);
75+
7476
karmaOptions.buildWebpack = {
7577
root: getSystemPath(root),
7678
projectRoot: getSystemPath(projectRoot),
7779
options: options as NormalizedKarmaBuilderSchema,
78-
webpackConfig: this._buildWebpackConfig(root, projectRoot, host,
80+
webpackConfig: this._buildWebpackConfig(root, projectRoot, sourceRoot, host,
7981
options as NormalizedKarmaBuilderSchema),
8082
// Pass onto Karma to emit BuildEvents.
8183
successCb: () => obs.next({ success: true }),
@@ -108,6 +110,7 @@ export class KarmaBuilder implements Builder<KarmaBuilderSchema> {
108110
private _buildWebpackConfig(
109111
root: Path,
110112
projectRoot: Path,
113+
sourceRoot: Path | undefined,
111114
host: virtualFs.Host<fs.Stats>,
112115
options: NormalizedKarmaBuilderSchema,
113116
) {
@@ -130,6 +133,7 @@ export class KarmaBuilder implements Builder<KarmaBuilderSchema> {
130133
wco = {
131134
root: getSystemPath(root),
132135
projectRoot: getSystemPath(projectRoot),
136+
sourceRoot: sourceRoot && getSystemPath(sourceRoot),
133137
// TODO: use only this.options, it contains all flags and configs items already.
134138
buildOptions: compatOptions,
135139
tsConfig,

packages/angular_devkit/build_angular/test/karma/code-coverage_spec_large.ts

+48
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,52 @@ describe('Karma Builder code coverage', () => {
5656
}),
5757
).toPromise().then(done, done.fail);
5858
}, 120000);
59+
60+
it(`should collect coverage from paths in 'sourceRoot'`, (done) => {
61+
const overrides: Partial<NormalizedKarmaBuilderSchema> = { codeCoverage: true };
62+
63+
const files: { [path: string]: string } = {
64+
'./dist/my-lib/index.d.ts': `
65+
export declare const title = 'app';
66+
`,
67+
'./dist/my-lib/index.js': `
68+
export const title = 'app';
69+
`,
70+
'./src/app/app.component.ts': `
71+
import { Component } from '@angular/core';
72+
import { title } from 'my-lib';
73+
74+
@Component({
75+
selector: 'app-root',
76+
templateUrl: './app.component.html',
77+
styleUrls: ['./app.component.css']
78+
})
79+
export class AppComponent {
80+
title = title;
81+
}
82+
`,
83+
};
84+
85+
host.writeMultipleFiles(files);
86+
87+
host.replaceInFile('tsconfig.json', /"baseUrl": ".\/",/, `
88+
"baseUrl": "./",
89+
"paths": {
90+
"my-lib": [
91+
"./dist/my-lib"
92+
]
93+
},
94+
`);
95+
96+
runTargetSpec(host, karmaTargetSpec, overrides).pipe(
97+
// It seems like the coverage files take a while being written to disk, so we wait 500ms here.
98+
debounceTime(500),
99+
tap(buildEvent => {
100+
expect(buildEvent.success).toBe(true);
101+
expect(host.scopedSync().exists(coverageFilePath)).toBe(true);
102+
const content = virtualFs.fileBufferToString(host.scopedSync().read(coverageFilePath));
103+
expect(content).not.toContain('my-lib');
104+
}),
105+
).toPromise().then(done, done.fail);
106+
}, 120000);
59107
});

0 commit comments

Comments
 (0)