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
- ux-test: 5300 (
npx nx serve ux-test) - editor-web: 5200 (
npx nx serve editor-web) - space-map: 4600+ (
npx nx serve space-map) - docs: 5010 (
npx nx serve docs-angular)
Development Environment
Node.js Requirements
Current Version: Node.js 24.7.0 (LTS)
Our workspace requires Node.js 24+ for full compatibility with:
- Angular 20
- Latest NX features
- Modern TypeScript compilation
- Enhanced build performance
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:
- Dependency Graph: NX analyzes project dependencies to determine build order
- Task Caching: Results are cached based on inputs to avoid unnecessary rebuilds
- Affected Detection: Only builds projects affected by changes
- Parallel Execution: Runs tasks in parallel when possible
Build Targets
Standard Targets
- build: Compiles the project for production
- build-deps: Builds project dependencies first
- watch-deps: Watches dependencies for changes
- serve: Starts development server
- test: Runs unit tests
- lint: Runs ESLint
- e2e: Runs end-to-end tests (apps only)
Custom Targets
- build-libs: Builds all libraries
- build-apps: Builds all applications
- build:dev: Development build
- build:prod: Production build
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
- Source maps included
- Faster compilation
- No optimization
- Larger bundle size
Production Build
npx nx build my-app --configuration=production
- Optimized and minified
- Tree-shaking enabled
- Source maps excluded
- Smaller bundle size
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:
- Check
tsconfig.base.jsonpath mappings - Verify library is built:
npx nx build my-library - Clear NX cache:
npx nx reset
2. Circular Dependency Errors
Error: Circular dependency detected
Solution:
- Move shared types to
@core-types - Avoid importing from peer libraries
- Review dependency hierarchy
3. Angular Compilation Errors
Error: Component 'MyComponent' is not standalone
Solution:
- Ensure components use
standalone: true - Add required imports to component
importsarray - Check Angular version compatibility
4. Build Order Issues
Error: Cannot find module '@dependency-library'
Solution:
- Build dependencies first:
npx nx build dependency-library - Use build with dependencies:
npx nx build my-project --with-deps - Use automated build commands:
yarn build:libs
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:
- Applications showing "Build Error" messages in production
nxcommand not recognized in terminal- TypeScript compilation failures
- Missing or corrupted node_modules
Root Cause:
- Corrupted or missing node_modules directory
- Incomplete dependency installation
- NX tooling not properly installed
- Package manager cache issues
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:
- Always run
yarn installafter pulling changes - Use
yarnconsistently (notnpm) - Monitor for peer dependency warnings during installation
- Keep dependencies up to date with
yarn upgrade
Time to Resolution: ~2-3 minutes for dependency reinstallation
Common Test Issues
1. Test Setup Errors
Error: Cannot find module in test
Solution:
- Check
test-setup.tsconfiguration - Verify jest configuration in
jest.config.ts - Add required imports to test file
2. Component Test Errors
Error: 'my-component' is not a known element
Solution:
- Import component in test:
imports: [MyComponent] - Use TestBed for standalone components
- Mock external dependencies
3. Service Injection Errors
Error: No provider for MyService
Solution:
- Provide service in test:
providers: [MyService] - Use
TestBed.inject()to get service instance - Mock dependencies as needed
Performance Issues
1. Slow Build Times
- Use
--parallelflag for multi-project builds - Enable caching with proper
nx.jsonconfiguration - Build only affected projects:
npx nx affected:build
2. Large Bundle Sizes
- Analyze bundles:
--stats-jsonflag - Enable tree-shaking in production builds
- Review and optimize imports
3. Test Performance
- Use
--parallelfor test execution - Mock heavy dependencies
- Use
--maxWorkersto control Jest workers
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
- Always build dependencies before dependents
- Use caching for faster subsequent builds
- Build only affected projects in CI
- Use parallel execution when possible
2. Testing
- Write unit tests for all public APIs
- Use TestBed for Angular component testing
- Mock external dependencies
- Maintain good test coverage (>80%)
3. Code Quality
- Use ESLint rules consistently
- Follow TypeScript strict mode
- Use
SafeAnyinstead ofany - Document complex logic
4. Performance
- Enable NX caching
- Use lazy loading for large features
- Optimize bundle sizes
- Monitor build performance
This comprehensive guide ensures efficient development, testing, and deployment workflows across our entire monorepo.