Click the Real Buttons in a Real Browser
End-to-End Testing
Angular's old Protractor is gone — modern projects use Cypress or Playwright. Both have first-party schematics that drop straight into an Angular workspace.
What you'll learn
- Install @cypress/schematic or @playwright/test
- Run e2e in CI against a built app
- Stub network calls in e2e for stable tests
End-to-end tests boot your app in a real browser and drive it like a user would — useful for smoke tests, critical flows, and regression coverage that unit tests can’t reach.
Pick a Runner
# Cypress
ng add @cypress/schematic
# Playwright
npm install -D @playwright/test
npx playwright install Both add scripts and config. Run them with ng e2e (Cypress integrates with the Angular builder) or npx playwright test directly.
A Cypress Test
describe('Login', () => {
it('logs in', () => {
cy.visit('/login');
cy.get('input[type=email]').type('ada@example.com');
cy.get('input[type=password]').type('secret');
cy.contains('Sign in').click();
cy.url().should('include', '/dashboard');
});
}); A Playwright test looks similar — await page.goto(), await page.getByLabel().fill(), await expect(page).toHaveURL(...).
Stub the Network
Real APIs are flaky. Intercept them so tests are deterministic.
// Cypress
cy.intercept('GET', '/api/users', { fixture: 'users.json' });
// Playwright
await page.route('/api/users', r => r.fulfill({ path: 'fixtures/users.json' })); Wire It Into CI
In GitHub Actions: build the app once, serve the dist/ output, then run the e2e command against it. Avoid running ng serve in CI — it rebuilds on every change, which is slower and less representative of production.