From 2b602924538bf987e92f806c25c2a3d008a3f0a9 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Fri, 23 Sep 2022 13:11:41 +0000 Subject: [PATCH] feat(@angular-devkit/build-angular): providing a karma config is now optional Karma will now use a builtin config when the `karmaConfig` is not specified. --- .../angular_devkit/build_angular/index.md | 2 +- .../build_angular/src/builders/karma/index.ts | 71 +++++++++++++++---- .../src/builders/karma/schema.json | 2 +- 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/goldens/public-api/angular_devkit/build_angular/index.md b/goldens/public-api/angular_devkit/build_angular/index.md index 5a7c1a144a75..e34dfbd7cad7 100644 --- a/goldens/public-api/angular_devkit/build_angular/index.md +++ b/goldens/public-api/angular_devkit/build_angular/index.md @@ -177,7 +177,7 @@ export interface KarmaBuilderOptions { fileReplacements?: FileReplacement_2[]; include?: string[]; inlineStyleLanguage?: InlineStyleLanguage_2; - karmaConfig: string; + karmaConfig?: string; main?: string; poll?: number; polyfills?: Polyfills_2; diff --git a/packages/angular_devkit/build_angular/src/builders/karma/index.ts b/packages/angular_devkit/build_angular/src/builders/karma/index.ts index f406fa769047..87b322e2ac87 100644 --- a/packages/angular_devkit/build_angular/src/builders/karma/index.ts +++ b/packages/angular_devkit/build_angular/src/builders/karma/index.ts @@ -7,7 +7,9 @@ */ import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect'; -import { Config, ConfigOptions } from 'karma'; +import { strings } from '@angular-devkit/core'; +import { Config, ConfigOptions, config, constants } from 'karma'; +import { createRequire } from 'module'; import * as path from 'path'; import { Observable, from } from 'rxjs'; import { defaultIfEmpty, switchMap } from 'rxjs/operators'; @@ -86,9 +88,17 @@ export function execute( return from(initialize(options, context, transforms.webpackConfiguration)).pipe( switchMap(async ([karma, webpackConfig]) => { - const karmaOptions: KarmaConfigOptions = { - singleRun, - }; + // Determine project name from builder context target + const projectName = context.target?.project; + if (!projectName) { + throw new Error(`The 'karma' builder requires a target to be specified.`); + } + + const karmaOptions: KarmaConfigOptions = options.karmaConfig + ? {} + : getBuiltInKarmaConfig(context.workspaceRoot, projectName); + + karmaOptions.singleRun = singleRun; // Convert browsers from a string to an array if (options.browsers) { @@ -106,11 +116,6 @@ export function execute( } } - const projectName = context.target?.project; - if (!projectName) { - throw new Error('The builder requires a target.'); - } - if (!options.main) { webpackConfig.entry ??= {}; if (typeof webpackConfig.entry === 'object' && !Array.isArray(webpackConfig.entry)) { @@ -140,13 +145,13 @@ export function execute( logger: context.logger, }; - const config = await karma.config.parseConfig( - path.resolve(context.workspaceRoot, options.karmaConfig), + const parsedKarmaConfig = await config.parseConfig( + options.karmaConfig && path.resolve(context.workspaceRoot, options.karmaConfig), transforms.karmaOptions ? transforms.karmaOptions(karmaOptions) : karmaOptions, { promiseConfig: true, throwErrors: true }, ); - return [karma, config] as [typeof karma, KarmaConfigOptions]; + return [karma, parsedKarmaConfig] as [typeof karma, KarmaConfigOptions]; }), switchMap( ([karma, karmaConfig]) => @@ -178,6 +183,48 @@ export function execute( ); } +function getBuiltInKarmaConfig( + workspaceRoot: string, + projectName: string, +): ConfigOptions & Record { + let coverageFolderName = projectName.charAt(0) === '@' ? projectName.slice(1) : projectName; + if (/[A-Z]/.test(coverageFolderName)) { + coverageFolderName = strings.dasherize(coverageFolderName); + } + + const workspaceRootRequire = createRequire(workspaceRoot + '/'); + + return { + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + 'karma-jasmine', + 'karma-chrome-launcher', + 'karma-jasmine-html-reporter', + 'karma-coverage', + '@angular-devkit/build-angular/plugins/karma', + ].map((p) => workspaceRootRequire(p)), + client: { + clearContext: false, // leave Jasmine Spec Runner output visible in browser + }, + jasmineHtmlReporter: { + suppressAll: true, // removes the duplicated traces + }, + coverageReporter: { + dir: path.join(workspaceRoot, 'coverage', coverageFolderName), + subdir: '.', + reporters: [{ type: 'html' }, { type: 'text-summary' }], + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: constants.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + restartOnFileChange: true, + }; +} + export { KarmaBuilderOptions }; export default createBuilder & KarmaBuilderOptions>(execute); diff --git a/packages/angular_devkit/build_angular/src/builders/karma/schema.json b/packages/angular_devkit/build_angular/src/builders/karma/schema.json index 1d55ee6434c9..f9a081b5bdd5 100644 --- a/packages/angular_devkit/build_angular/src/builders/karma/schema.json +++ b/packages/angular_devkit/build_angular/src/builders/karma/schema.json @@ -255,7 +255,7 @@ } }, "additionalProperties": false, - "required": ["tsConfig", "karmaConfig"], + "required": ["tsConfig"], "definitions": { "assetPattern": { "oneOf": [