Cypress — это инструмент для end-to-end (E2E) тестирования, который также отлично подходит для интеграционного тестирования Angular приложений. Он позволяет запускать тесты в реальном браузере, взаимодействовать с компонентами и проверять их поведение на уровне пользовательского интерфейса.
Для интеграции Cypress в Angular проект используется стандартная установка через npm:
npm install cypress --save-dev
После установки Cypress создаёт структуру папок
cypress/, включающую fixtures,
integration, support и plugins. В
Angular проектах важно правильно настроить baseUrl в
cypress.config.js для корректной работы с локальным
сервером:
import { defineConfig } from 'cypress'
export default defineConfig({
e2e: {
baseUrl: 'http://localhost:4200',
supportFile: 'cypress/support/e2e.js'
}
})
Тесты в Cypress пишутся с использованием синтаксиса Mocha
(describe, it) и Chai для ассертов. Для
Angular компонентов важно использовать селекторы, которые устойчивы к
изменениям структуры DOM. Наиболее надёжным подходом является
использование data-testid атрибутов:
<button data-testid="submit-btn">Отправить</button>
В тесте:
describe('Компонент кнопки', () => {
it('должен корректно реагировать на клик', () => {
cy.visit('/');
cy.get('[data-testid="submit-btn"]').click();
cy.get('.notification').should('contain', 'Данные отправлены');
});
});
Angular активно использует реактивные формы и
FormControl. Cypress позволяет эмулировать пользовательский
ввод и проверять реакцию компонентов:
describe('Форма авторизации', () => {
it('валидирует поля ввода', () => {
cy.visit('/login');
cy.get('[data-testid="username"]').type('testuser');
cy.get('[data-testid="password"]').type('wrongpassword');
cy.get('[data-testid="login-btn"]').click();
cy.get('.error-message').should('contain', 'Неверный пароль');
});
});
Ключевой момент — Cypress ждёт элементы автоматически до заданного таймаута, что упрощает работу с асинхронными обновлениями Angular.
Для тестирования взаимодействия с сервером в Angular используется
HttpClient. Cypress позволяет перехватывать и мокать
HTTP-запросы через cy.intercept():
describe('Загрузка данных пользователей', () => {
it('отображает список пользователей', () => {
cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers');
cy.visit('/users');
cy.wait('@getUsers');
cy.get('.user-item').should('have.length', 3);
cy.get('.user-item').first().should('contain', 'Иван Иванов');
});
});
Использование фикстур позволяет создавать стабильные тестовые сценарии без зависимости от реального API.
Angular часто использует внутреннее состояние для отображения данных. Cypress позволяет проверять наличие классов, атрибутов и текста для подтверждения корректного состояния компонента:
describe('Компонент переключателя', () => {
it('должен менять состояние при клике', () => {
cy.visit('/toggle');
cy.get('[data-testid="toggle-btn"]').click();
cy.get('[data-testid="toggle-btn"]').should('have.class', 'active');
cy.get('[data-testid="toggle-btn"]').click();
cy.get('[data-testid="toggle-btn"]').should('not.have.class', 'active');
});
});
Cypress поддерживает динамическое создание тестов с использованием
forEach или cy.each(), что полезно для Angular
компонентов с множеством состояний:
const roles = ['admin', 'user', 'guest'];
roles.forEach(role => {
it(`проверяет доступ для роли ${role}`, () => {
cy.visit(`/dashboard?role=${role}`);
cy.get('.dashboard').should('contain', `Роль: ${role}`);
});
});
Компоненты Angular Material часто используют тени DOM и динамические
шаблоны (mat-select, mat-dialog). Cypress
может взаимодействовать с ними через стандартные селекторы и
события:
describe('Диалог Material', () => {
it('открывает и закрывает диалог', () => {
cy.visit('/dialogs');
cy.get('[data-testid="open-dialog"]').click();
cy.get('mat-dialog-container').should('exist');
cy.get('mat-dialog-container button.close').click();
cy.get('mat-dialog-container').should('not.exist');
});
});
Важно учитывать задержки анимаций и применять
{ force: true } для клика по элементам, если они временно
перекрыты.
Для уменьшения дублирования кода можно создавать собственные команды
в cypress/support/commands.js:
Cypress.Commands.add('login', (username, password) => {
cy.visit('/login');
cy.get('[data-testid="username"]').type(username);
cy.get('[data-testid="password"]').type(password);
cy.get('[data-testid="login-btn"]').click();
});
После этого команды можно использовать в тестах многократно:
describe('Проверка авторизации', () => {
it('успешный вход', () => {
cy.login('admin', 'admin123');
cy.get('.dashboard').should('contain', 'Добро пожаловать, admin');
});
});
Angular приложения активно используют асинхронные операции. Cypress
по умолчанию ждёт до 4 секунд (defaultCommandTimeout) на
каждый элемент. Для сложных компонентов можно задавать индивидуальные
таймауты:
cy.get('.loading-indicator', { timeout: 10000 }).should('not.exist');
Тесты Cypress легко интегрируются с системами CI/CD, такими как GitHub Actions, GitLab CI или Jenkins. Для Angular проектов обычно используют команду:
npx cypress run --headless
Это позволяет запускать E2E тесты на каждом коммите, обеспечивая стабильность компонентов и предотвращая регрессии.
Тщательная структура тестов, использование data-testid,
перехват HTTP-запросов и создание пользовательских команд позволяет
построить надёжную стратегию тестирования Angular компонентов с помощью
Cypress.