or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

application-builders.mddevelopment-server.mdindex.mdlibrary-packaging.mdserver-side-rendering.mdtesting-builders.mdtesting-utilities.md
tile.json

testing-utilities.mddocs/

Testing Utilities

Comprehensive testing utilities for unit testing Angular builders, including test harness, file system mocking, and builder execution helpers.

Testing Framework

The testing utilities provide a complete testing framework specifically designed for Angular builders.

import {
  BuilderHarness,
  JasmineBuilderHarness,
  describeBuilder,
  type BuilderHarnessExecutionOptions,
  type BuilderHarnessExecutionResult,
  type HarnessFileMatchers
} from "@angular-devkit/build-angular/testing";

Capabilities

Builder Harness

Core testing infrastructure for Angular builders providing isolated execution environment.

/**
 * Test harness for Angular builders
 * Provides isolated file system and workspace environment for testing builder execution
 */
class BuilderHarness {
  /** Execute a builder with the given options */
  executeTarget<T extends BuilderOutput = BuilderOutput>(
    target: Target,
    overrides?: any,
    options?: BuilderHarnessExecutionOptions
  ): Promise<BuilderHarnessExecutionResult<T>>;

  /** Write a file to the harness file system */
  writeFile(path: string, content: string | Buffer): Promise<void>;

  /** Write multiple files to the harness file system */
  writeFiles(files: Record<string, string | Buffer>): Promise<void>;

  /** Remove a file from the harness file system */
  removeFile(path: string): Promise<void>;

  /** Modify a file in the harness file system */
  modifyFile(path: string, modifier: (content: string) => string): Promise<void>;

  /** Check if a file exists in the harness file system */
  hasFile(path: string): Promise<boolean>;

  /** Read a file from the harness file system */
  readFile(path: string): Promise<string>;

  /** Append content to a file in the harness file system */
  appendToFile(path: string, content: string): Promise<void>;
}

/**
 * Jasmine-specific builder harness with additional test helpers
 */
class JasmineBuilderHarness extends BuilderHarness {
  /** Expect file to exist */
  expectFile(path: string): HarnessFileMatchers;
}

interface BuilderHarnessExecutionOptions {
  /** Override configuration options */
  outputLogsOnException?: boolean;
  /** Override configuration options */
  outputLogsOnFailure?: boolean;
  /** Logger to use during execution */
  logger?: logging.Logger;
}

interface BuilderHarnessExecutionResult<T extends BuilderOutput = BuilderOutput> {
  /** Execution result if successful */
  result?: T;
  /** Error if execution failed */
  error?: Error;
  /** All log entries from execution */
  logs: readonly logging.LogEntry[];
}

interface HarnessFileMatchers {
  /** Expect file content to match */
  toEqual(content: string): void;
  /** Expect file content to contain */
  toContain(content: string): void;
  /** Expect file to match pattern */
  toMatch(pattern: RegExp): void;
}

Jasmine Test Helpers

Jasmine-specific testing utilities for Angular builders.

/**
 * Describe a builder test suite with automatic harness setup
 * @param builderHandler - The builder function to test
 * @param options - Test configuration options
 * @param specDefinitions - Test specifications
 */
function describeBuilder<T>(
  builderHandler: BuilderHandlerFn<T>,
  options: {
    name?: string;
    schemaPath: string;
    workspaceRoot?: string;
  },
  specDefinitions: (harness: JasmineBuilderHarness) => void
): void;

Usage Examples:

import { describeBuilder } from '@angular-devkit/build-angular/testing';
import { buildWebpackBrowser } from '@angular-devkit/build-angular';

describeBuilder(buildWebpackBrowser, {
  name: 'Browser Builder',
  schemaPath: require.resolve('../schema.json'),
}, (harness) => {
  
  beforeEach(async () => {
    // Setup test files
    await harness.writeFiles({
      'src/main.ts': `console.log('Hello World');`,
      'src/index.html': '<html><body><app-root></app-root></body></html>',
      'tsconfig.json': JSON.stringify({
        compilerOptions: { target: 'es2015' }
      })
    });
  });

  it('should build successfully', async () => {
    const { result } = await harness.executeTarget({
      project: 'test',
      target: 'build'
    }, {
      outputPath: 'dist',
      index: 'src/index.html',
      main: 'src/main.ts',
      tsConfig: 'tsconfig.json'
    });

    expect(result?.success).toBe(true);
    harness.expectFile('dist/main.js').toExist();
  });
});

File System Mocking

Virtual file system for testing builders without real file I/O.

/**
 * Virtual file system host for testing
 * Provides in-memory file system operations
 */
interface VirtualFileSystemHost {
  /** Write file to virtual file system */
  writeFile(path: string, content: string): void;
  /** Read file from virtual file system */
  readFile(path: string): string;
  /** Check if file exists */
  exists(path: string): boolean;
  /** List directory contents */
  list(path: string): string[];
  /** Create directory */
  mkdir(path: string): void;
  /** Remove file or directory */
  delete(path: string): void;
  /** Get file stats */
  stat(path: string): { isFile(): boolean; isDirectory(): boolean };
}

/**
 * Create virtual file system host
 * @param files - Initial file structure
 * @returns Virtual host instance
 */
function createVirtualHost(files: Record<string, string>): VirtualFileSystemHost;

Test Utilities

/**
 * Workspace configuration for testing
 */
interface TestWorkspace {
  /** Workspace root directory */
  root: string;
  /** Project configurations */
  projects: Record<string, TestProject>;
  /** Angular CLI configuration */
  cli?: {
    version: string;
    packageManager?: string;
  };
}

/**
 * Project configuration for testing
 */
interface TestProject {
  /** Project root relative to workspace */
  root: string;
  /** Project type */
  projectType: 'application' | 'library';
  /** Build targets */
  targets: Record<string, TestTarget>;
  /** Source root */
  sourceRoot?: string;
}

/**
 * Target configuration for testing
 */
interface TestTarget {
  /** Builder to use */
  builder: string;
  /** Default options */
  options: any;
  /** Configuration-specific options */
  configurations?: Record<string, any>;
}

/**
 * Create test workspace configuration
 * @param projects - Project configurations
 * @param workspaceOptions - Additional workspace options
 * @returns Test workspace
 */
function createTestWorkspace(
  projects: Record<string, Partial<TestProject>>,
  workspaceOptions?: Partial<TestWorkspace>
): TestWorkspace;

Mock Implementations

/**
 * Mock logger for testing
 */
interface MockLogger {
  /** Debug messages */
  debug: jest.Mock;
  /** Info messages */
  info: jest.Mock;
  /** Warning messages */
  warn: jest.Mock;
  /** Error messages */  
  error: jest.Mock;
  /** Fatal messages */
  fatal: jest.Mock;
}

/**
 * Create mock logger instance
 * @returns Mock logger with jest spy functions
 */
function createMockLogger(): MockLogger;

/**
 * Mock analytics for testing
 */
interface MockAnalytics {
  /** Track events */
  track: jest.Mock;
  /** Page views */
  page: jest.Mock;
  /** User identification */
  identify: jest.Mock;
  /** Flush analytics */
  flush: jest.Mock;
}

/**
 * Create mock analytics instance
 * @returns Mock analytics with jest spy functions
 */
function createMockAnalytics(): MockAnalytics;

Test Helpers

/**
 * Builder test runner with common setup
 */
class BuilderTestRunner {
  /** Setup test environment */
  setup(workspaceRoot: string, projectRoot: string): Promise<void>;
  
  /** Run builder with options */
  runBuilder<T>(
    builderName: string,
    options: T,
    timeout?: number
  ): Promise<BuilderOutput>;
  
  /** Add file to virtual file system */
  addFile(path: string, content: string): void;
  
  /** Cleanup test environment */
  cleanup(): Promise<void>;
}

/**
 * Webpack test utilities
 */
interface WebpackTestUtils {
  /** Create test webpack configuration */
  createTestConfig(options: any): webpack.Configuration;
  
  /** Mock webpack stats */
  createMockStats(options?: Partial<webpack.Stats>): webpack.Stats;
  
  /** Validate webpack configuration */
  validateConfig(config: webpack.Configuration): ValidationResult;
}

/**
 * Karma test utilities  
 */
interface KarmaTestUtils {
  /** Create test karma configuration */
  createTestKarmaConfig(options: any): any;
  
  /** Mock karma server */
  createMockKarmaServer(): any;
  
  /** Generate test coverage report */
  generateCoverageReport(coverage: any): CoverageReport;
}

Usage Examples

import { createArchitectHost, createArchitect, testBuilder } from "@angular-devkit/build-angular/testing";
import { executeBrowserBuilder } from "@angular-devkit/build-angular";

describe('Browser Builder', () => {
  let architect: Architect;
  let architectHost: TestingArchitectHost;

  beforeEach(async () => {
    const workspaceRoot = '/test-workspace';
    architectHost = createArchitectHost(workspaceRoot);
    architect = createArchitect(architectHost);
    
    // Add builder to test environment
    architectHost.addBuilder('@angular-devkit/build-angular:browser', executeBrowserBuilder);
    
    // Add target configuration
    architectHost.addTarget({
      project: 'test-app',
      target: 'build'
    }, '@angular-devkit/build-angular:browser', {
      outputPath: 'dist/test-app',
      index: 'src/index.html',
      main: 'src/main.ts',
      tsConfig: 'tsconfig.app.json'
    });
  });

  it('should build application successfully', async () => {
    const run = await architect.scheduleTarget({
      project: 'test-app',
      target: 'build'
    });

    const output = await run.result;
    expect(output.success).toBe(true);
    
    await run.stop();
  });

  it('should test builder directly', async () => {
    const options = {
      outputPath: 'dist/test-app',
      index: 'src/index.html',
      main: 'src/main.ts',  
      tsConfig: 'tsconfig.app.json'
    };

    const context = createMockContext(
      { name: '@angular-devkit/build-angular:browser', version: '1.0.0' },
      '/test-workspace',
      'src'
    );

    const output = await testBuilder(executeBrowserBuilder, options, context);
    expect(output.success).toBe(true);
  });
});