Skip to content

fix(@angular-devkit/build-angular): provide an option to exclude specs in Karma builder #24505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions goldens/public-api/angular_devkit/build_angular/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export interface KarmaBuilderOptions {
browsers?: string;
codeCoverage?: boolean;
codeCoverageExclude?: string[];
exclude?: string[];
fileReplacements?: FileReplacement_2[];
include?: string[];
inlineStyleLanguage?: InlineStyleLanguage_2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const PLUGIN_NAME = 'angular-find-tests-plugin';

export interface FindTestsPluginOptions {
include?: string[];
exclude?: string[];
workspaceRoot: string;
projectSourceRoot: string;
}
Expand All @@ -33,7 +34,12 @@ export class FindTestsPlugin {
constructor(private options: FindTestsPluginOptions) {}

apply(compiler: Compiler): void {
const { include = ['**/*.spec.ts'], projectSourceRoot, workspaceRoot } = this.options;
const {
include = ['**/*.spec.ts'],
exclude = [],
projectSourceRoot,
workspaceRoot,
} = this.options;
const webpackOptions = compiler.options;
const entry =
typeof webpackOptions.entry === 'function' ? webpackOptions.entry() : webpackOptions.entry;
Expand All @@ -42,7 +48,7 @@ export class FindTestsPlugin {

// Add tests files are part of the entry-point.
webpackOptions.entry = async () => {
const specFiles = await findTests(include, workspaceRoot, projectSourceRoot);
const specFiles = await findTests(include, exclude, workspaceRoot, projectSourceRoot);

if (!specFiles.length) {
assert(this.compilation, 'Compilation cannot be undefined.');
Expand Down Expand Up @@ -73,12 +79,13 @@ export class FindTestsPlugin {

// go through all patterns and find unique list of files
async function findTests(
patterns: string[],
include: string[],
exclude: string[],
workspaceRoot: string,
projectSourceRoot: string,
): Promise<string[]> {
const matchingTestsPromises = patterns.map((pattern) =>
findMatchingTests(pattern, workspaceRoot, projectSourceRoot),
const matchingTestsPromises = include.map((pattern) =>
findMatchingTests(pattern, exclude, workspaceRoot, projectSourceRoot),
);
const files = await Promise.all(matchingTestsPromises);

Expand All @@ -90,6 +97,7 @@ const normalizePath = (path: string): string => path.replace(/\\/g, '/');

async function findMatchingTests(
pattern: string,
ignore: string[],
workspaceRoot: string,
projectSourceRoot: string,
): Promise<string[]> {
Expand Down Expand Up @@ -132,7 +140,7 @@ async function findMatchingTests(
root: projectSourceRoot,
nomount: true,
absolute: true,
ignore: ['**/node_modules/**'],
ignore: ['**/node_modules/**', ...ignore],
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export function execute(
webpackConfig.plugins.push(
new FindTestsPlugin({
include: options.include,
exclude: options.exclude,
workspaceRoot: context.workspaceRoot,
projectSourceRoot: path.join(context.workspaceRoot, sourceRoot),
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,15 @@
"type": "string"
},
"default": ["**/*.spec.ts"],
"description": "Globs of files to include, relative to workspace or project root. \nThere are 2 special cases:\n - when a path to directory is provided, all spec files ending \".spec.@(ts|tsx)\" will be included\n - when a path to a file is provided, and a matching spec file exists it will be included instead."
"description": "Globs of files to include, relative to project root. \nThere are 2 special cases:\n - when a path to directory is provided, all spec files ending \".spec.@(ts|tsx)\" will be included\n - when a path to a file is provided, and a matching spec file exists it will be included instead."
},
"exclude": {
"type": "array",
"items": {
"type": "string"
},
"default": [],
"description": "Globs of files to exclude, relative to the project root."
},
"sourceMap": {
"description": "Output source maps for scripts and styles. For more information, see https://angular.io/guide/workspace-config#source-map-configuration.",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import { execute } from '../../index';
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';

describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
describe('Option: "exclude"', () => {
beforeEach(async () => {
await harness.writeFiles({
'src/app/error.spec.ts': `
describe('Error spec', () => {
it('should error', () => {
expect(false).toBe(true);
});
});`,
});
});

it(`should not exclude any spec when exclude is not supplied`, async () => {
harness.useTarget('test', {
...BASE_OPTIONS,
});

const { result } = await harness.executeOnce();
expect(result?.success).toBeFalse();
});

it(`should exclude spec that matches the 'exclude' pattern`, async () => {
harness.useTarget('test', {
...BASE_OPTIONS,
exclude: ['**/error.spec.ts'],
});

const { result } = await harness.executeOnce();
expect(result?.success).toBeTrue();
});
});
});