E2E тестирование React-приложения с Cypress

Фронтенд-разработка — это создание визуально приятных и функциональных клиентских приложений. Но важно не только написать код: приложение должно обеспечивать бесшовный пользовательский опыт.
Модульные и интеграционные тесты проверяют корректность реализации, однако они не всегда отражают поведение реального пользователя. Для этого нужны end-to-end (E2E) тесты: они повторяют пользовательские взаимодействия и проверяют приложение «с точки зрения пользователя» — от начала до конца.
Что такое E2E тестирование и зачем оно нужно
E2E тестирование проверяет поведение всей системы: сети, UI, взаимодействие компонентов и сторонних API. Коротко:
- Цель: подтвердить, что пользователь достигает ожидаемого результата, а не проверить внутреннюю реализацию.
- Пример: для формы логина важно, что экран отображается правильно и пользователь может зайти в систему; детали запроса — вторичны.
Определение: E2E тест — автоматизированный сценарий, который имитирует шаги реального пользователя (ввод, клики, ожидание ответов) и делает утверждения по итоговому состоянию страницы.

Cypress — популярный инструмент для E2E тестов на JavaScript. Его преимущества:
- Запуск тестов прямо в браузере и возможность интерактивной отладки.
- Простая и декларативная синтаксическая модель.
- Поддержка unit/integration/E2E подходов.
Ниже приведён пример приложения: простой React-компонент поиска товаров, который достаёт данные из DummyJSON API и отображает их.
Быстрый план работы (мини-методология)
- Создать проект React (Vite или CRA).
- Установить Cypress как dev-зависимость.
- Реализовать компонент, который делает fetch по поисковому запросу.
- Запустить dev-сервер и открыть Cypress.
- Написать и прогонять E2E тесты: рендер, ввод, запросы, обработка ошибок.
- Автоматизировать запуск тестов в CI и добавить стаб/интерсепты для стабильности.
В этой статье каждый шаг раскрыт подробно и с практическими советами.
Установка и настройка проекта
Создайте React-проект (Vite или create-react-app). Затем установите Cypress:
npm install cypress --save-devДобавьте скрипт в package.json для запуска клиентского интерфейса Cypress:
"test": "npx cypress open"Теперь можно открыть Cypress через npm run test и следовать установщику — он создаст папку cypress и файл cypress.config.js.
Создание функционального компонента
В папке src создайте components/products.jsx со следующим кодом:
import React, { useState, useEffect } from 'react';
import "./style.component.css"
export default function Products(prop) {
const [products, setProducts] = useState([]);
const [error, setError] = useState(null);
const { searchInput } = prop;
return (
{error ? (
Product not found
) : (
{products.slice(0, 6).map((product) => (
Title: {product.title}
Price: ${product.price}
))}
)}
);
}Реализуем useEffect, чтобы при изменении searchInput выполнялся fetch:
useEffect(() => {
const fetchProducts = async () => {
if (searchInput) {
const apiUrl = `https://dummyjson.com/products/category/${searchInput}`;
try {
const response = await fetch(apiUrl);
if (!response.ok) {
throw new Error('Error fetching products');
}
const json = await response.json();
setProducts(json.products);
setError(null);
} catch (error) {
setError(error.message);
}
}
};
fetchProducts();
}, [searchInput]);Обновление App.jsx
В App.jsx подключим компонент и реализуем поле ввода и кнопку:
import React, { useState,useRef } from 'react'
import './App.css'
import Products from './components/Products'
function App() {
const [searchInput, setSearchInput] = useState('')
const searchInputRef = useRef('');
const handleSubmit = (e) => {
setSearchInput(searchInputRef.current.value);
}
return (
Cypress Testing Library tutorial
)
}
export default AppЗапустите dev-сервер:
npm run devЕсли всё сделано правильно, приложение может получать данные из DummyJSON API.
Настройка окружения тестирования
Запустите клиент Cypress:
npm run testОткроется интерфейс Cypress. Нажмите E2E Testing и затем Continue, чтобы добавить конфигурационные файлы. После этого появится папка cypress и cypress.config.js — вы можете в ней указать baseUrl, таймауты и другие параметры для удобства.


Написание E2E тестов с Cypress
Выберите браузер в клиенте Cypress — инструмент запустит упрощённый тестовый браузер.

Создайте новый spec-файл через Create new spec или вручную. Пример простого теста App.spec.cy.js:
describe('App Tests', () => {
beforeEach(() => {
cy.visit('http://127.0.0.1:5173/');
});
it('Renders input field and submit button', () => {
cy.get('#text').should('exist').should('be.visible');
cy.get('#btn').should('exist').should('be.visible').contains('Submit');
});
it('Enters a search query', () => {
const searchQuery = 'laptops';
cy.get('#text').type(searchQuery);
});
});Этот набор тестов проверяет, что поле ввода и кнопка видимы и что в поле можно ввести поисковый запрос.

Выберите файл в списке тестов и запустите. Результаты отображаются в панели слева.


Тестирование полного пользовательского сценария
Создайте файл Products.spec.cy.js с тестом, который имитирует ввод запроса, клик и проверку, что продукты отображаются:
describe('Products Tests', () => {
it(' fetches and displays the data', () => {
const searchQuery = 'laptops';
cy.visit('http://127.0.0.1:5173');
cy.get('#text').type(searchQuery);
cy.get('#btn').contains('Submit').click();
cy.get('.product').should('have.length.greaterThan', 0);
cy.get('.product').first().should('contain', 'Title');
cy.get('.product').first().should('contain', 'Price: $');
});
});Тест симулирует полный путь: ввод → отправка → ожидание загрузки → проверка элементов.

Тестирование обработки ошибок и стабирование сетевых запросов
Cypress позволяет интерсептировать сетевые запросы и подменять ответы. Это полезно для тестирования сценариев ошибок и для изоляции тестов от внешних API.
Пример Error.spec.cy.js:
describe('Error Handling Tests', () => {
it('Displays error message for incorrect search query', () => {
cy.intercept('GET', /https:\/\/dummyjson\.com\/products\/category\/.*/, {
statusCode: 404, // Not Found
body: 'Product not found'
}).as('fetchProducts');
cy.visit('http://127.0.0.1:5173');
const incorrectSearchQuery = 'rocket';
cy.get('#text').type(incorrectSearchQuery);
cy.get('#btn').click();
cy.wait('@fetchProducts');
cy.contains('Product not found').should('be.visible');
});
});Так мы проверяем, что приложение корректно отображает сообщение об ошибке при неудачном ответе от API.
Практические советы и эвристики
- Локальный baseUrl: задайте baseUrl в cypress.config.js, чтобы в тестах использовать cy.visit(‘/‘) вместо полного адреса.
- Таймауты: для медленных сетей увеличьте defaultCommandTimeout, но не делайте таймауты слишком большими.
- Интерсепты: стабьте (stub) ответы API для стабильных тестов и быстрых прогонов в CI.
- Чёткие селекторы: используйте data-testid или data-cy для надежной селекции элементов, вместо селекторов по css-классам или тексту.
- Idempotent действия: тесты должны быть повторяемыми и не менять состояние, которое мешает другим тестам.
Important: не полагайтесь на порядок отображения элементов в DOM, если он не гарантирован API.
Когда E2E тесты не подходят (контр-примеры)
- Для мелких юнитов логики: пишите unit-тесты, они быстрее и дешевле в поддержке.
- Для тестирования сложных внутренних алгоритмов: integration/unit-тесты более подходящие.
- Когда нужно протестировать привязку к конкретному браузерному API (например, WebGPU) — возможно потребуется отдельный набор интеграционных тестов и симуляция окружения.
Как интегрировать Cypress в CI (коротко)
- Запускайте тесты headless (npx cypress run) в контейнере/VM.
- Используйте стаб-режим для внешних API или мокируйте их на уровне сети.
- Сохраняйте видео и скриншоты по падениям для пост-мортема.
Чеклист для команды перед написанием E2E тестов
- Определены пользовательские истории (acceptance criteria).
- Есть договорённость по селекторам (data-cy / data-testid).
- Dev-сервер стабильно запускается в CI.
- Стаб-сценарии для внешних API подготовлены.
- Ограничено количество E2E тестов — фокус на критичных путях.
Критерии приёмки (Test cases / Acceptance criteria)
- Поле ввода и кнопка отображаются и доступны.
- При вводе допустимого запроса и отправке отображается список продуктов (>0).
- Первый продукт содержит заголовок и цену в формате “Price: $”.
- При получении 404 отображается сообщение “Product not found”.
- Тесты стабильны при повторном запуске без ручного вмешательства.
Роли и обязанности (role-based checklists)
- Разработчик:
- Добавляет data-testid в критические элементы.
- Обеспечивает стабильность локального dev-сервера.
- QA-инженер:
- Пишет и поддерживает E2E тесты.
- Настраивает интерсепты и мок-сервисы.
- DevOps:
- Встраивает прогон тестов в CI/CD и собирает артефакты (скриншоты, видео).
Отладка и распространённые ошибки
- Тесты зависают на cy.visit: проверьте baseUrl и запущен ли dev-сервер.
- Ожидание данных: убедитесь, что селектор ждёт загрузки (используйте cy.wait(‘@alias’) или assertions с .should).
- Изменение селекторов в UI ломает тесты: держите отдельные атрибуты для тестов.
Варианты альтернативных подходов
- Playwright: современная альтернатива с кросс-браузерной поддержкой и более низкоуровневым управлением контекстами.
- Puppeteer: если нужно управлять headless Chromium напрямую.
- Cypress + component testing: запуск тестов отдельных React-компонентов в изоляции.
Матрица зрелости E2E в проекте (кратко)
- Начальная: тесты покровительственно редки, покрывают 1–2 пути.
- Средняя: есть стабильные тесты для критичных путей, интеграция в CI.
- Продвинутая: быстрые стаб-тесты, автоматический rollback на сбоях, мониторинг flakiness.
Безопасность и конфиденциальность
- Никогда не хардкодьте секреты или токены в тестах. Используйте переменные окружения.
- Для тестовых ответов не отправляйте реальные персональные данные.
- Если в тестах используется внешнее API, мокируйте чувствительные данные.
Decision flowchart
flowchart TD
A[Запуск E2E тестов] --> B{Dev-сервер запущен?}
B -- Да --> C{Нужно мокать API?}
B -- Нет --> G[Запустить сервер]
C -- Да --> D[Добавить cy.intercept или локальный мок]
C -- Нет --> E[Запуск реального API]
D --> F[Прогнать тесты]
E --> F
G --> AМаленькая галерея edge-case’ов
- API отвечает успешно, но возвращает пустой массив — тест должен проверять поведение в этом случае.
- Частичные ошибки: часть запросов 200, часть 500 — проработайте fallback UX.
- Сетевые огрaничения и таймауты — используйте retry-политику на стороне клиента только там, где это оправдано.
1-строчный глоссарий
- E2E: end-to-end тестирование — проверка сценария с точки зрения пользователя.
- Intercept: перехват сетевого запроса для подмены ответа.
- Stub: заранее подготовленный ответ для теста.
- Base URL: базовый адрес приложения для удобства визитов в тестах.
Заключение
E2E тесты с Cypress дают уверенность, что пользователи проходят важные сценарии без сбоев. Используйте их разумно: фокусируйтесь на критичных пользовательских путях, стабьте внешние зависимости и интегрируйте прогон тестов в CI. Комбинируйте E2E с unit и integration тестами для полного покрытия.
Краткое резюме:
- Cypress удобен для интерактивной отладки и симуляции пользовательских сценариев.
- Интерсепты помогают эмулировать ошибки и добиться стабильности.
- Чёткие селекторы и договорённые практики делают тесты надёжными.
Спасибо за внимание — начните с простых тестов и постепенно усложняйте сценарии, опираясь на реальные пользовательские истории.
Похожие материалы
Подготовка к техническому собеседованию разработчика
Запуск мастера устранения неполадок в Windows
Как создать мем: полное руководство
Как устранить BSOD 0x0000003B в Windows
Clone Stamp в Photoshop — подробное руководство