End-to-end (E2E) testing is a crucial part of web application development. It ensures that your application works correctly from the user's perspective by testing real interactions with the UI, API, and database. For Angular applications, Cypress has become a popular E2E testing tool because of its simplicity, speed, and rich features.

In this article, we will explore Angular E2E testing with Cypress, covering everything from installation to writing and running advanced tests. This will be a complete guide, suitable for beginners and developers looking to implement robust testing strategies.

Table of Contents

  1. What is E2E Testing

  2. Why Use Cypress for Angular

  3. Setting Up Cypress in an Angular Project

  4. Writing Your First Cypress Test

  5. Organizing Tests and Test Data

  6. Advanced Cypress Features for Angular

  7. Best Practices for E2E Testing

  8. Integrating Cypress with CI/CD

  9. Conclusion

1. What is E2E Testing

End-to-end testing is a testing methodology that validates the entire application flow from start to finish. Unlike unit tests or component tests that check small parts of the code, E2E tests simulate real user behavior, including:

E2E testing ensures that all parts of the application work together correctly, preventing bugs that unit or integration tests might miss.

2. Why Use Cypress for Angular

Cypress is a modern E2E testing framework with several advantages for Angular applications:

Cypress is designed for developers and QA engineers to write maintainable, readable tests.

3. Setting Up Cypress in an Angular Project

Step 1: Create an Angular Project

If you don’t already have an Angular project:

ng new angular-cypress-demo
cd angular-cypress-demo

Step 2: Install Cypress

npm install cypress --save-dev

Step 3: Open Cypress

npx cypress open

The first time you open Cypress, it will create a cypress/ folder with example tests. The folder structure will look like this:

cypress/
 ├─ fixtures/
 ├─ integration/
 ├─ plugins/
 └─ support/

Step 4: Add a Script in package.json

"scripts": {
  "cypress:open": "cypress open",
  "cypress:run": "cypress run"
}

4. Writing Your First Cypress Test

Let’s create a simple test for Angular home page.

Step 1: Create a Test File

Create cypress/integration/home.spec.js:

describe('Home Page', () => {
  it('should display the welcome message', () => {
    cy.visit('http://localhost:4200');
    cy.contains('Welcome to angular-cypress-demo');
  });
});

Step 2: Run the Angular App

ng serve

Visit the application at http://localhost:4200.

Step 3: Run Cypress Test

npm run cypress:open

Click on home.spec.js in the Cypress GUI. Cypress will:

If the test passes, it confirms your first E2E test is successful.

5. Organizing Tests and Test Data

5.1 Using Fixtures

Fixtures store test data like JSON objects. Example:

cypress/fixtures/user.json:

{
  "username": "testuser",
  "password": "123456"
}

In your test:

describe('Login Test', () => {
  it('should login successfully', () => {
    cy.fixture('user').then((user) => {
      cy.visit('/login');
      cy.get('input[name="username"]').type(user.username);
      cy.get('input[name="password"]').type(user.password);
      cy.get('button[type="submit"]').click();
      cy.contains('Dashboard');
    });
  });
});

5.2 Custom Commands

You can create reusable Cypress commands in cypress/support/commands.js:

Cypress.Commands.add('login', (username, password) => {
  cy.visit('/login');
  cy.get('input[name="username"]').type(username);
  cy.get('input[name="password"]').type(password);
  cy.get('button[type="submit"]').click();
});

Then, in your test:

cy.login('testuser', '123456');
cy.contains('Dashboard');

This makes tests cleaner and more maintainable.

6. Advanced Cypress Features for Angular

6.1 Handling Angular Routing

Angular applications often use client-side routing. Cypress automatically waits for page transitions, but you can ensure elements exist using:

cy.url().should('include', '/dashboard');
cy.get('h1').should('contain', 'Dashboard');

6.2 Intercepting HTTP Requests

Cypress allows you to mock API responses:

cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers');
cy.visit('/users');
cy.wait('@getUsers');
cy.get('table').should('contain', 'John Doe');

6.3 Testing Forms

Angular forms can be template-driven or reactive. Cypress can handle both:

cy.get('input[name="email"]').type('[email protected]');
cy.get('input[name="password"]').type('123456');
cy.get('form').submit();
cy.contains('Login successful');

6.4 Assertions and Waits

Cypress automatically waits for elements, but you can add custom assertions:

cy.get('.notification')
  .should('be.visible')
  .and('contain', 'User created successfully');

7. Best Practices for E2E Testing in Angular

  1. Test real user scenarios: simulate actual user behavior

  2. Keep tests independent: avoid relying on previous tests

  3. Use fixtures and mocks: isolate frontend from backend

  4. Use custom commands: reduce code repetition

  5. Run tests headlessly in CI/CD: catch regressions automatically

  6. Focus on critical paths: don’t test every minor detail

8. Integrating Cypress with CI/CD

You can run Cypress tests in GitHub Actions, GitLab CI, or Jenkins. Example GitHub Actions workflow:

.github/workflows/cypress.yml:

name: Cypress E2E Tests
on: [push, pull_request]
jobs:
  e2e-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: 18
      - run: npm ci
      - run: npm run build
      - run: npm run start &   # start Angular server
      - run: npx cypress run

Cypress will run headlessly on every push or PR, ensuring continuous quality.

Conclusion

Angular E2E testing with Cypress is a powerful and easy-to-use solution for modern web applications. By following this guide, you can:

Benefits of using Cypress with Angular

With these techniques, your Angular application will not only work correctly but also deliver a high-quality user experience.