Build Testing

Documentation for Developers

Build & Testing Guide

This guide covers all aspects of building, testing, and deploying code in our NX monorepo, including troubleshooting common issues and best practices.

Quick Reference

Essential Commands

# Development
yarn install                    # Install dependencies
npx nx serve app-name           # Start development server
npx nx build app-name           # Build application
npx nx test lib-name            # Run tests
npx nx lint project-name        # Run linting

# Build All
npx nx run-many -t build        # Build all projects
yarn build:libs                 # Build all libraries
npx nx build-apps               # Build all applications

# Testing
npx nx run-many -t test         # Test all projects
npx nx run-many -t lint         # Lint all projects
npx nx run-many -t e2e          # Run all E2E tests

Port Assignments

Development Environment

Node.js Requirements

Current Version: Node.js 24.7.0 (LTS)

Our workspace requires Node.js 24+ for full compatibility with:

Installation: Managed via Homebrew

# Check current version
node --version  # Should show v24.x.x

# Update if needed
brew upgrade node

Important: The workspace is configured to use Homebrew Node.js instead of NVM to ensure consistent builds across all environments.

Build System Architecture

NX Build Process

NX uses a sophisticated caching and dependency management system:

  1. Dependency Graph: NX analyzes project dependencies to determine build order
  2. Task Caching: Results are cached based on inputs to avoid unnecessary rebuilds
  3. Affected Detection: Only builds projects affected by changes
  4. Parallel Execution: Runs tasks in parallel when possible

Build Targets

Standard Targets

Custom Targets

Library Build Process

Build Order

Libraries must be built in dependency order:

# 1. Foundation
npx nx build core-types

# 2. Core Libraries  
npx nx build core
npx nx build permissions

# 3. Framework Libraries
npx nx build theme-system
npx nx build ux-framework
npx nx build data-core
npx nx build gograb-ai
npx nx build ux-widgets
npx nx build component-library

# 4. Feature Libraries
npx nx build widgets
npx nx build editor-ui
npx nx build shared-ui
npx nx build page-management
npx nx build data-binding
npx nx build auth

# 5. Applications (can be built in any order)
npx nx build editor-web
npx nx build ux-test
npx nx build space-map

Automated Build Commands

# Build all libraries in correct order
yarn build:libs

# Build libraries in development mode (faster, includes source maps)
yarn build:libs:dev

# Build specific library with dependencies
npx nx build my-library --with-deps

# Watch mode for development
npx nx build my-library --watch

Application Build Process

Build Configuration

Applications use Angular's build system with NX optimizations:

{
  "targets": {
    "build": {
      "executor": "@angular-devkit/build-angular:application",
      "options": {
        "outputPath": "dist/apps/my-app",
        "index": "apps/my-app/src/index.html",
        "browser": "apps/my-app/src/main.ts",
        "polyfills": ["zone.js"],
        "tsConfig": "apps/my-app/tsconfig.app.json",
        "assets": [
          "apps/my-app/src/favicon.ico",
          "apps/my-app/src/assets"
        ],
        "styles": ["apps/my-app/src/styles.scss"],
        "scripts": []
      }
    }
  }
}

Build Modes

Development Build

npx nx build my-app --configuration=development

Production Build

npx nx build my-app --configuration=production

Bundle Analysis

# Analyze bundle size
npx nx build my-app --stats-json
npx webpack-bundle-analyzer dist/apps/my-app/stats.json

Testing Strategy

Unit Testing with Jest

Configuration

All projects use Jest with Angular preset:

// jest.config.ts
export default {
  displayName: 'project-name',
  preset: '../../jest.preset.js',
  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
  coverageDirectory: '../../coverage/libs/project-name',
  transform: {
    '^.+\\.(ts|mjs|js|html)$': [
      'jest-preset-angular',
      {
        tsconfig: '<rootDir>/tsconfig.spec.json',
        stringifyContentPathRegex: '\\.(html|svg)$',
      },
    ],
  },
  transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
  snapshotSerializers: [
    'jest-preset-angular/build/serializers/no-ng-attributes',
    'jest-preset-angular/build/serializers/ng-snapshot',
    'jest-preset-angular/build/serializers/html-comment',
  ],
};

Test Commands

# Run tests for specific project
npx nx test project-name

# Run tests with coverage
npx nx test project-name --coverage

# Run tests in watch mode
npx nx test project-name --watch

# Run all tests
npx nx run-many -t test

# Run affected tests only
npx nx affected:test

Component Testing Example

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyComponent } from './my-component.component';

describe('MyComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [MyComponent] // For standalone components
    }).compileComponents();

    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

Service Testing Example

import { TestBed } from '@angular/core/testing';
import { MyService } from './my-service.service';

describe('MyService', () => {
  let service: MyService;

  beforeEach(() => {
    TestBed.configureTestingModule({});
    service = TestBed.inject(MyService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});

E2E Testing with Cypress

Configuration

E2E tests are configured per application:

// cypress.config.ts
import { defineConfig } from 'cypress';
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';

export default defineConfig({
  e2e: {
    ...nxE2EPreset(__filename, {
      cypressDir: 'src',
      bundler: 'vite',
      webServerCommands: {
        default: 'nx run my-app:serve',
        production: 'nx run my-app:preview',
      },
    }),
    baseUrl: 'http://localhost:4200',
  },
});

E2E Test Commands

# Run E2E tests
npx nx e2e my-app-e2e

# Open Cypress UI
npx nx open-cypress my-app-e2e

# Run E2E tests in CI mode
npx nx e2e-ci my-app-e2e

E2E Test Example

describe('My App', () => {
  beforeEach(() => cy.visit('/'));

  it('should display welcome message', () => {
    cy.contains('Welcome');
    cy.get('h1').should('contain', 'Welcome to my-app!');
  });

  it('should navigate to about page', () => {
    cy.get('[data-cy=nav-about]').click();
    cy.url().should('include', '/about');
  });
});

Linting

ESLint Configuration

Workspace-wide ESLint configuration with project-specific overrides:

{
  "extends": ["@nx/eslint-plugin/base"],
  "ignorePatterns": ["**/*"],
  "plugins": ["@nx"],
  "overrides": [
    {
      "files": ["*.ts", "*.tsx"],
      "extends": ["@nx/angular", "@nx/typescript"],
      "rules": {
        "@typescript-eslint/no-explicit-any": "error",
        "@angular-eslint/prefer-on-push-component-change-detection": "error"
      }
    },
    {
      "files": ["*.html"],
      "extends": ["@nx/angular-template"],
      "rules": {}
    }
  ]
}

Lint Commands

# Lint specific project
npx nx lint project-name

# Lint with auto-fix
npx nx lint project-name --fix

# Lint all projects
npx nx run-many -t lint

# Lint affected projects only
npx nx affected:lint

Caching and Performance

NX Cache

NX caches task results to improve performance:

# Clear cache
npx nx reset

# View cache info
npx nx show projects --affected

# Disable cache for specific command
npx nx build my-app --skip-nx-cache

Cache Configuration

Cache settings are configured in nx.json:

{
  "tasksRunnerOptions": {
    "default": {
      "runner": "@nx/workspace/tasks-runners/default",
      "options": {
        "cacheableOperations": ["build", "lint", "test", "e2e"],
        "runtimeCacheInputs": ["node -v"]
      }
    }
  }
}

Troubleshooting

Common Build Issues

1. Module Resolution Errors

Error: Cannot resolve module '@my-library'

Solution:

2. Circular Dependency Errors

Error: Circular dependency detected

Solution:

3. Angular Compilation Errors

Error: Component 'MyComponent' is not standalone

Solution:

4. Build Order Issues

Error: Cannot find module '@dependency-library'

Solution:

5. NX Command Not Found / TypeScript Dependency Corruption

Error: Command 'nx' not found. Did you mean 'ng'?
Error: Could not find Nx modules at '/workspace'. Have you run npm/yarn install?
Error: This app failed to build due to TypeScript dependency issues

Symptoms:

Root Cause:

Solution:

# 1. Reinstall all dependencies
yarn install

# 2. If issues persist, clear cache and reinstall
rm -rf node_modules yarn.lock
yarn install

# 3. Reset NX cache if needed
npx nx reset

# 4. Verify NX installation
npx nx --version

# 5. Test build functionality
npx nx build editor-web
npx nx build ux-test

Prevention:

Time to Resolution: ~2-3 minutes for dependency reinstallation

Common Test Issues

1. Test Setup Errors

Error: Cannot find module in test

Solution:

2. Component Test Errors

Error: 'my-component' is not a known element

Solution:

3. Service Injection Errors

Error: No provider for MyService

Solution:

Performance Issues

1. Slow Build Times

2. Large Bundle Sizes

3. Test Performance

Deployment

Build for Production

# Build all libraries for production
npx nx run-many -t build --configuration=production

# Build specific app for production
npx nx build my-app --configuration=production

# Build all apps for production
npx nx build-apps

Static Asset Handling

// angular.json build configuration
{
  "assets": [
    "apps/my-app/src/favicon.ico",
    "apps/my-app/src/assets",
    {
      "glob": "**/*",
      "input": "libs/shared-assets/src/assets",
      "output": "assets"
    }
  ]
}

Environment Configuration

// environment.ts
export const environment = {
  production: false,
  apiUrl: 'http://localhost:3000/api',
  appVersion: '1.0.0'
};

// environment.prod.ts  
export const environment = {
  production: true,
  apiUrl: 'https://api.example.com',
  appVersion: '1.0.0'
};

CI/CD Integration

GitHub Actions Example

name: CI
on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'yarn'
      
      - run: yarn install --frozen-lockfile
      
      - run: npx nx affected:lint --parallel=3
      - run: npx nx affected:test --parallel=3 --coverage
      - run: npx nx affected:build --parallel=3
      - run: npx nx affected:e2e --parallel=2

Pre-commit Hooks

{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{ts,js,html}": ["npx nx affected:lint --fix", "git add"],
    "*.{ts,js}": ["npx nx affected:test --bail=1"]
  }
}

Best Practices

1. Build Process

2. Testing

3. Code Quality

4. Performance

This comprehensive guide ensures efficient development, testing, and deployment workflows across our entire monorepo.