mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-16 02:24:10 +08:00
test(@angular-devkit/build-angular): add application/browser test runs
Runs all existing karma tests twice: Once in an environment that uses the application builder and once in one that uses the browser builder. The general approach is taken from the dev server tests. This is in preparation for supporting the application builder for karma tests.
This commit is contained in:
parent
65b6e75a5d
commit
66c55df468
@ -318,7 +318,7 @@ LARGE_SPECS = {
|
||||
},
|
||||
"extract-i18n": {},
|
||||
"karma": {
|
||||
"shards": 3,
|
||||
"shards": 6,
|
||||
"size": "large",
|
||||
"flaky": True,
|
||||
"extra_deps": [
|
||||
|
@ -10,7 +10,7 @@ import { setTimeout } from 'node:timers/promises';
|
||||
import { tags } from '@angular-devkit/core';
|
||||
import { last, tap } from 'rxjs';
|
||||
import { execute } from '../../index';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
|
||||
|
||||
// In each of the test below we'll have to call setTimeout to wait for the coverage
|
||||
// analysis to be done. This is because karma-coverage performs the analysis
|
||||
@ -21,8 +21,12 @@ import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
|
||||
const coveragePath = 'coverage/lcov.info';
|
||||
|
||||
describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
|
||||
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget, isApplicationBuilder) => {
|
||||
describe('Behavior: "codeCoverage"', () => {
|
||||
beforeEach(() => {
|
||||
setupTarget(harness);
|
||||
});
|
||||
|
||||
it('should generate coverage report when file was previously processed by Babel', async () => {
|
||||
// Force Babel transformation.
|
||||
await harness.appendToFile('src/app/app.component.ts', '// async');
|
||||
|
@ -7,10 +7,14 @@
|
||||
*/
|
||||
|
||||
import { execute } from '../../index';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
|
||||
|
||||
describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
|
||||
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
|
||||
describe('Behavior: "Errors"', () => {
|
||||
beforeEach(() => {
|
||||
setupTarget(harness);
|
||||
});
|
||||
|
||||
it('should fail when there is a TypeScript error', async () => {
|
||||
harness.useTarget('test', {
|
||||
...BASE_OPTIONS,
|
||||
|
@ -7,10 +7,14 @@
|
||||
*/
|
||||
|
||||
import { execute } from '../../index';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
|
||||
|
||||
describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
|
||||
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
|
||||
describe('Behavior: "module commonjs"', () => {
|
||||
beforeEach(() => {
|
||||
setupTarget(harness);
|
||||
});
|
||||
|
||||
it('should work when module is commonjs', async () => {
|
||||
harness.useTarget('test', {
|
||||
...BASE_OPTIONS,
|
||||
|
@ -8,10 +8,14 @@
|
||||
|
||||
import { concatMap, count, debounceTime, take, timeout } from 'rxjs';
|
||||
import { execute } from '../../index';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
|
||||
|
||||
describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
|
||||
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
|
||||
describe('Behavior: "Rebuilds"', () => {
|
||||
beforeEach(() => {
|
||||
setupTarget(harness);
|
||||
});
|
||||
|
||||
it('recovers from compilation failures in watch mode', async () => {
|
||||
harness.useTarget('test', {
|
||||
...BASE_OPTIONS,
|
||||
|
@ -7,10 +7,14 @@
|
||||
*/
|
||||
|
||||
import { execute } from '../../index';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
|
||||
|
||||
describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
|
||||
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
|
||||
describe('Option: "assets"', () => {
|
||||
beforeEach(() => {
|
||||
setupTarget(harness);
|
||||
});
|
||||
|
||||
it('includes assets', async () => {
|
||||
await harness.writeFiles({
|
||||
'./src/string-file-asset.txt': 'string-file-asset.txt',
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
import { setTimeout } from 'node:timers/promises';
|
||||
import { execute } from '../../index';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
|
||||
|
||||
// In each of the test below we'll have to call setTimeout to wait for the coverage
|
||||
// analysis to be done. This is because karma-coverage performs the analysis
|
||||
@ -18,8 +18,12 @@ import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
|
||||
const coveragePath = 'coverage/lcov.info';
|
||||
|
||||
describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
|
||||
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
|
||||
describe('Option: "codeCoverageExclude"', () => {
|
||||
beforeEach(() => {
|
||||
setupTarget(harness);
|
||||
});
|
||||
|
||||
it('should exclude file from coverage when set', async () => {
|
||||
harness.useTarget('test', {
|
||||
...BASE_OPTIONS,
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import { setTimeout } from 'node:timers/promises';
|
||||
import { execute } from '../../index';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
|
||||
|
||||
// In each of the test below we'll have to call setTimeout to wait for the coverage
|
||||
// analysis to be done. This is because karma-coverage performs the analysis
|
||||
@ -19,8 +19,12 @@ import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
|
||||
const coveragePath = 'coverage/lcov.info';
|
||||
|
||||
describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
|
||||
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
|
||||
describe('Option: "codeCoverage"', () => {
|
||||
beforeEach(() => {
|
||||
setupTarget(harness);
|
||||
});
|
||||
|
||||
it('should generate coverage report when option is set to true', async () => {
|
||||
harness.useTarget('test', {
|
||||
...BASE_OPTIONS,
|
||||
|
@ -7,10 +7,14 @@
|
||||
*/
|
||||
|
||||
import { execute } from '../../index';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
|
||||
|
||||
describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
|
||||
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
|
||||
describe('Option: "exclude"', () => {
|
||||
beforeEach(() => {
|
||||
setupTarget(harness);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await harness.writeFiles({
|
||||
'src/app/error.spec.ts': `
|
||||
|
@ -7,10 +7,14 @@
|
||||
*/
|
||||
|
||||
import { execute } from '../../index';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
|
||||
|
||||
describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
|
||||
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
|
||||
describe('Option: "include"', () => {
|
||||
beforeEach(() => {
|
||||
setupTarget(harness);
|
||||
});
|
||||
|
||||
it(`should fail when includes doesn't match any files`, async () => {
|
||||
harness.useTarget('test', {
|
||||
...BASE_OPTIONS,
|
||||
|
@ -7,10 +7,14 @@
|
||||
*/
|
||||
|
||||
import { execute } from '../../index';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
|
||||
|
||||
describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
|
||||
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
|
||||
describe('Option: "styles"', () => {
|
||||
beforeEach(() => {
|
||||
setupTarget(harness);
|
||||
});
|
||||
|
||||
it(`processes 'styles.css' styles`, async () => {
|
||||
await harness.writeFiles({
|
||||
'src/styles.css': 'p {display: none}',
|
||||
|
@ -7,10 +7,14 @@
|
||||
*/
|
||||
|
||||
import { execute } from '../../index';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeBuilder } from '../setup';
|
||||
import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup';
|
||||
|
||||
describeBuilder(execute, KARMA_BUILDER_INFO, (harness) => {
|
||||
describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => {
|
||||
describe('Option: "webWorkerTsConfig"', () => {
|
||||
beforeEach(() => {
|
||||
setupTarget(harness);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await harness.writeFiles({
|
||||
'src/tsconfig.worker.json': `
|
||||
|
@ -7,6 +7,21 @@
|
||||
*/
|
||||
|
||||
import { Schema } from '../schema';
|
||||
import { BuilderHandlerFn } from '@angular-devkit/architect';
|
||||
import { json } from '@angular-devkit/core';
|
||||
import { ApplicationBuilderOptions as ApplicationSchema, buildApplication } from '@angular/build';
|
||||
import * as path from 'node:path';
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
import { JasmineBuilderHarness } from '../../../testing';
|
||||
import { host } from '../../../testing/test-utils';
|
||||
import { BuilderHarness } from '../../../testing';
|
||||
import { buildWebpackBrowser } from '../../browser';
|
||||
import { Schema as BrowserSchema } from '../../browser/schema';
|
||||
import {
|
||||
BASE_OPTIONS as BROWSER_BASE_OPTIONS,
|
||||
BROWSER_BUILDER_INFO,
|
||||
} from '../../browser/tests/setup';
|
||||
|
||||
export { describeBuilder } from '../../../testing';
|
||||
|
||||
@ -27,3 +42,133 @@ export const BASE_OPTIONS = Object.freeze<Schema>({
|
||||
progress: false,
|
||||
watch: false,
|
||||
});
|
||||
|
||||
const optionSchemaCache = new Map<string, json.schema.JsonSchema>();
|
||||
|
||||
function getCachedSchema(options: { schemaPath: string }): json.schema.JsonSchema {
|
||||
let optionSchema = optionSchemaCache.get(options.schemaPath);
|
||||
if (optionSchema === undefined) {
|
||||
optionSchema = JSON.parse(readFileSync(options.schemaPath, 'utf8')) as json.schema.JsonSchema;
|
||||
optionSchemaCache.set(options.schemaPath, optionSchema);
|
||||
}
|
||||
return optionSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a `build` target to a builder test harness for the browser builder with the base options
|
||||
* used by the browser builder tests.
|
||||
*
|
||||
* @param harness The builder harness to use when setting up the browser builder target
|
||||
* @param extraOptions The additional options that should be used when executing the target.
|
||||
*/
|
||||
export function setupBrowserTarget<T>(
|
||||
harness: BuilderHarness<T>,
|
||||
extraOptions?: Partial<BrowserSchema>,
|
||||
): void {
|
||||
const browserSchema = getCachedSchema(BROWSER_BUILDER_INFO);
|
||||
|
||||
harness.withBuilderTarget(
|
||||
'build',
|
||||
buildWebpackBrowser,
|
||||
{
|
||||
...BROWSER_BASE_OPTIONS,
|
||||
...extraOptions,
|
||||
},
|
||||
{
|
||||
builderName: BROWSER_BUILDER_INFO.name,
|
||||
optionSchema: browserSchema,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains all required application builder fields.
|
||||
* Also disables progress reporting to minimize logging output.
|
||||
*/
|
||||
export const APPLICATION_BASE_OPTIONS = Object.freeze<ApplicationSchema>({
|
||||
index: 'src/index.html',
|
||||
browser: 'src/main.ts',
|
||||
outputPath: 'dist',
|
||||
tsConfig: 'src/tsconfig.app.json',
|
||||
progress: false,
|
||||
|
||||
// Disable optimizations
|
||||
optimization: false,
|
||||
|
||||
// Enable polling (if a test enables watch mode).
|
||||
// This is a workaround for bazel isolation file watch not triggering in tests.
|
||||
poll: 100,
|
||||
});
|
||||
|
||||
// TODO: Remove and use import after Vite-based dev server is moved to new package
|
||||
export const APPLICATION_BUILDER_INFO = Object.freeze({
|
||||
name: '@angular-devkit/build-angular:application',
|
||||
schemaPath: path.join(
|
||||
path.dirname(require.resolve('@angular/build/package.json')),
|
||||
'src/builders/application/schema.json',
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
* Adds a `build` target to a builder test harness for the application builder with the base options
|
||||
* used by the application builder tests.
|
||||
*
|
||||
* @param harness The builder harness to use when setting up the application builder target
|
||||
* @param extraOptions The additional options that should be used when executing the target.
|
||||
*/
|
||||
export function setupApplicationTarget<T>(
|
||||
harness: BuilderHarness<T>,
|
||||
extraOptions?: Partial<ApplicationSchema>,
|
||||
): void {
|
||||
const applicationSchema = getCachedSchema(APPLICATION_BUILDER_INFO);
|
||||
|
||||
harness.withBuilderTarget(
|
||||
'build',
|
||||
buildApplication,
|
||||
{
|
||||
...APPLICATION_BASE_OPTIONS,
|
||||
...extraOptions,
|
||||
},
|
||||
{
|
||||
builderName: APPLICATION_BUILDER_INFO.name,
|
||||
optionSchema: applicationSchema,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/** Runs the test against both an application- and a browser-builder context. */
|
||||
export function describeKarmaBuilder<T>(
|
||||
builderHandler: BuilderHandlerFn<T & json.JsonObject>,
|
||||
options: { name?: string; schemaPath: string },
|
||||
specDefinitions: ((
|
||||
harness: JasmineBuilderHarness<T>,
|
||||
setupTarget: typeof setupApplicationTarget,
|
||||
isApplicationTarget: true,
|
||||
) => void) &
|
||||
((
|
||||
harness: JasmineBuilderHarness<T>,
|
||||
setupTarget: typeof setupBrowserTarget,
|
||||
isApplicationTarget: false,
|
||||
) => void),
|
||||
) {
|
||||
const optionSchema = getCachedSchema(options);
|
||||
const harness = new JasmineBuilderHarness<T>(builderHandler, host, {
|
||||
builderName: options.name,
|
||||
optionSchema,
|
||||
});
|
||||
|
||||
describe(options.name || builderHandler.name, () => {
|
||||
for (const isApplicationTarget of [true, false]) {
|
||||
describe(isApplicationTarget ? 'with application builder' : 'with browser builder', () => {
|
||||
beforeEach(() => host.initialize().toPromise());
|
||||
afterEach(() => host.restore().toPromise());
|
||||
|
||||
if (isApplicationTarget) {
|
||||
specDefinitions(harness, setupApplicationTarget, true);
|
||||
} else {
|
||||
specDefinitions(harness, setupBrowserTarget, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user