Complete Guide to Testing in NX: Building Reliable Angular Applications

Complete Guide to Testing in NX: Building Reliable Angular Applications

Hello developers! ?? This week, we're diving deep into testing strategies for your NX workspace. Let's explore how to build robust, reliable applications with comprehensive testing practices.


?? Unit Testing in NX

Setting Up Your First Test

// libs/shared/ui/src/lib/button/button.component.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ButtonComponent } from './button.component';

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

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [ButtonComponent]
    }).compileComponents();

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

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

  it('should emit click event', () => {
    // Arrange
    const spy = jest.spyOn(component.clicked, 'emit');
    
    // Act
    component.onClick();
    
    // Assert
    expect(spy).toHaveBeenCalled();
  });
});
        


Running Unit Tests

# Run tests for a specific project
nx test my-app

# Run tests with coverage
nx test my-app --coverage

# Watch mode for development
nx test my-app --watch        

?? E2E Testing with Cypress

Basic Configuration

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

export default defineConfig({
  e2e: {
    ...nxE2EPreset(__dirname),
    baseUrl: 'https://localhost:4200',
    specPattern: './src/e2e/**/*.cy.{js,jsx,ts,tsx}',
    supportFile: './src/support/e2e.ts'
  }
});        


Writing E2E Tests

// apps/my-app-e2e/src/e2e/login.cy.ts
describe('Login Flow', () => {
  beforeEach(() => {
    cy.visit('/login');
  });

  it('should successfully log in', () => {
    cy.get('[data-testid="username"]').type('testuser');
    cy.get('[data-testid="password"]').type('password123');
    cy.get('[data-testid="login-button"]').click();
    cy.url().should('include', '/dashboard');
  });

  it('should show error for invalid credentials', () => {
    cy.get('[data-testid="username"]').type('wrong');
    cy.get('[data-testid="password"]').type('wrong');
    cy.get('[data-testid="login-button"]').click();
    cy.get('[data-testid="error-message"]')
      .should('be.visible')
      .and('contain', 'Invalid credentials');
  });
});        

?? Best Testing Practices

1. Test Data Management

// libs/shared/testing/src/lib/test-data.ts
export const mockUser = {
  id: 1,
  name: 'Test User',
  email: '[email protected]'
};

export const mockProducts = [
  { id: 1, name: 'Product 1', price: 99.99 },
  { id: 2, name: 'Product 2', price: 149.99 }
];        

2. Custom Test Utilities

// libs/shared/testing/src/lib/test-utils.ts
export function createMockStore() {
  return {
    select: jest.fn(),
    dispatch: jest.fn()
  };
}

export function mockHttpResponse<T>(data: T) {
  return of(data);
}        


3. Component Testing Strategy

describe('ComplexComponent', () => {
  // Arrange
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ComplexComponent],
      providers: [
        { provide: UserService, useValue: mockUserService },
        { provide: Store, useValue: createMockStore() }
      ]
    });
  });

  // Test different states
  it('should show loading state', () => {});
  it('should show error state', () => {});
  it('should show success state', () => {});
});        

?? Test Coverage and Reporting

Coverage Configuration

{
  "test": {
    "options": {
      "coverage": {
        "reporter": ["text", "html"],
        "exclude": ["**/test-setup.ts"],
        "thresholds": {
          "global": {
            "statements": 80,
            "branches": 80,
            "functions": 80,
            "lines": 80
          }
        }
      }
    }
  }
}        

?? CI/CD Integration

GitHub Actions Example

name: Test
on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Install dependencies
        run: npm ci
      - name: Run unit tests
        run: nx run-many --target=test --all
      - name: Run e2e tests
        run: nx run-many --target=e2e --all        

?? Pro Testing Tips

  1. Use Data Test Attributes

<button data-testid="submit-button">
  Submit
</button>        

2. solate Network Requests

// Cypress example
cy.intercept('GET', '/api/users', { fixture: 'users.json' });        

3. Group Related Tests

describe('UserComponent', () => {
  describe('initialization', () => {
    // Setup tests
  });

  describe('user interactions', () => {
    // Interaction tests
  });

  describe('error handling', () => {
    // Error tests
  });
});        

?? Common Testing Patterns

1. Component Testing

it('should render user details', () => {
  // Arrange
  component.user = mockUser;
  
  // Act
  fixture.detectChanges();
  
  // Assert
  const nameElement = fixture.debugElement.query(
    By.css('[data-testid="user-name"]')
  );
  expect(nameElement.nativeElement.textContent)
    .toContain(mockUser.name);
});        

2. Service Testing

it('should fetch user data', (done) => {
  const service = TestBed.inject(UserService);
  service.getUser(1).subscribe(user => {
    expect(user).toEqual(mockUser);
    done();
  });
});        


#Angular #NX #Testing #WebDevelopment #QualityAssurance #Frontend #JavaScript #TypeScript #Cypress #Jest


?? Remember: Tests are an investment in your application's future. They help you catch bugs early and refactor with confidence!

Need help implementing these testing strategies in your NX workspace? Drop a comment below! ??



要查看或添加评论,请登录

Dhruv Patel的更多文章