From c828324cd76a70995b3042fc63922fb0e57a9835 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Wed, 2 Oct 2024 12:08:34 -0400 Subject: [PATCH] test(@angular/build): add test harness rebuild case helper function To reduce duplicate code within tests for rebuild/watch scenarios, a new helper has been added to the builder test harness. This helper allows passing in an array of test case functions that are executed in order per rebuild. The development server's watch option tests have been updated to use the new helper. --- .../testing/builder/src/jasmine-helpers.ts | 27 ++++- .../dev-server/tests/options/watch_spec.ts | 112 +++++++----------- 2 files changed, 71 insertions(+), 68 deletions(-) diff --git a/modules/testing/builder/src/jasmine-helpers.ts b/modules/testing/builder/src/jasmine-helpers.ts index dcd11fe59002..269cbc2396ed 100644 --- a/modules/testing/builder/src/jasmine-helpers.ts +++ b/modules/testing/builder/src/jasmine-helpers.ts @@ -9,9 +9,16 @@ import { BuilderHandlerFn } from '@angular-devkit/architect'; import { json } from '@angular-devkit/core'; import { readFileSync } from 'fs'; -import { BuilderHarness } from './builder-harness'; +import { concatMap, count, firstValueFrom, take, timeout } from 'rxjs'; +import { BuilderHarness, BuilderHarnessExecutionResult } from './builder-harness'; import { host } from './test-utils'; +/** + * Maximum time for single build/rebuild + * This accounts for CI variability. + */ +export const BUILD_TIMEOUT = 25_000; + const optionSchemaCache = new Map(); export function describeBuilder( @@ -45,6 +52,24 @@ export class JasmineBuilderHarness extends BuilderHarness { expectDirectory(path: string): HarnessDirectoryMatchers { return expectDirectory(path, this); } + + async executeWithCases( + cases: (( + executionResult: BuilderHarnessExecutionResult, + index: number, + ) => void | Promise)[], + ): Promise { + const executionCount = await firstValueFrom( + this.execute().pipe( + timeout(BUILD_TIMEOUT), + concatMap(async (result, index) => await cases[index](result, index)), + take(cases.length), + count(), + ), + ); + + expect(executionCount).toBe(cases.length); + } } export interface HarnessFileMatchers { diff --git a/packages/angular/build/src/builders/dev-server/tests/options/watch_spec.ts b/packages/angular/build/src/builders/dev-server/tests/options/watch_spec.ts index e09ea21a58c5..9840ea2adc36 100644 --- a/packages/angular/build/src/builders/dev-server/tests/options/watch_spec.ts +++ b/packages/angular/build/src/builders/dev-server/tests/options/watch_spec.ts @@ -6,10 +6,10 @@ * found in the LICENSE file at https://angular.dev/license */ -import { TimeoutError, concatMap, count, take, timeout } from 'rxjs'; +import { TimeoutError } from 'rxjs'; import { executeDevServer } from '../../index'; import { describeServeBuilder } from '../jasmine-helpers'; -import { BASE_OPTIONS, BUILD_TIMEOUT, DEV_SERVER_BUILDER_INFO } from '../setup'; +import { BASE_OPTIONS, DEV_SERVER_BUILDER_INFO } from '../setup'; describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupTarget) => { describe('Option: "watch"', () => { @@ -24,27 +24,21 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT }); await harness - .execute() - .pipe( - timeout(BUILD_TIMEOUT), - concatMap(async ({ result }, index) => { + .executeWithCases([ + async ({ result }) => { + // Initial build should succeed expect(result?.success).toBe(true); - switch (index) { - case 0: - await harness.modifyFile( - 'src/main.ts', - (content) => content + 'console.log("abcd1234");', - ); - break; - case 1: - fail('Expected files to not be watched.'); - break; - } - }), - take(2), - ) - .toPromise() + // Modify a file to attempt to trigger file watcher + await harness.modifyFile( + 'src/main.ts', + (content) => content + 'console.log("abcd1234");', + ); + }, + () => { + fail('Expected files to not be watched.'); + }, + ]) .catch((error) => { // Timeout is expected if watching is disabled if (error instanceof TimeoutError) { @@ -60,30 +54,22 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT watch: undefined, }); - const buildCount = await harness - .execute() - .pipe( - timeout(BUILD_TIMEOUT), - concatMap(async ({ result }, index) => { - expect(result?.success).toBe(true); - - switch (index) { - case 0: - await harness.modifyFile( - 'src/main.ts', - (content) => content + 'console.log("abcd1234");', - ); - break; - case 1: - break; - } - }), - take(2), - count(), - ) - .toPromise(); + await harness.executeWithCases([ + async ({ result }) => { + // Initial build should succeed + expect(result?.success).toBe(true); - expect(buildCount).toBe(2); + // Modify a file to trigger file watcher + await harness.modifyFile( + 'src/main.ts', + (content) => content + 'console.log("abcd1234");', + ); + }, + async ({ result }) => { + // Modifying a file should trigger a successful rebuild + expect(result?.success).toBe(true); + }, + ]); }); it('watches for file changes when true', async () => { @@ -92,30 +78,22 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT watch: true, }); - const buildCount = await harness - .execute() - .pipe( - timeout(BUILD_TIMEOUT), - concatMap(async ({ result }, index) => { - expect(result?.success).toBe(true); - - switch (index) { - case 0: - await harness.modifyFile( - 'src/main.ts', - (content) => content + 'console.log("abcd1234");', - ); - break; - case 1: - break; - } - }), - take(2), - count(), - ) - .toPromise(); + await harness.executeWithCases([ + async ({ result }) => { + // Initial build should succeed + expect(result?.success).toBe(true); - expect(buildCount).toBe(2); + // Modify a file to trigger file watcher + await harness.modifyFile( + 'src/main.ts', + (content) => content + 'console.log("abcd1234");', + ); + }, + async ({ result }) => { + // Modifying a file should trigger a successful rebuild + expect(result?.success).toBe(true); + }, + ]); }); }); });