Привет, Хабр! Сегодня рассмотрим как автоматизировать тестирование React-приложений с инструментом Cypress.
Для начала работы с Cypress React-проекте, первым делом нужно установить сам пакет. Это можно сделать с помощью npm или Yarn:
npm install cypress --save-dev # или yarn add cypress --dev
После установки, нужно будет проинициализировать Cypress, что создаст базовую структуру папок и файлов конфигураций:
npx cypress open
Команда создат все необходимые файлы и откроет пользовательский интерфейс Cypress, где можно увидеть все тесты и управлять ими.
Структура будет выглядеть следующим образом:
-
cypress/fixtures/: папка для хранения фикстур — файлов с данными, которые могут быть использованы в тестах для имитации ответов сервера, загрузки данных и т. п
-
cypress/integration/: здесь располагаются тесты. Cypress автоматически поиск тестов в этой директории.
-
cypress/plugins/: папка для настройки плагинов, которые могут изменять поведение Cypress на более низком уровне, о них поговорим позже.
-
cypress/support/: содержит файлы, которые выполняются перед загрузкой тестов. Это идеальное место для размещения повторно используемых функций или настроек, доступных глобально во всех тестах.
-
cypress.json: файл конфигурации Cypress, где можно задать различные настройки, такие как базовые URL-адреса, время ожидания для тестов, переменные окружения и др.
-
package.json: стандартный файл Node.js, содержащий информацию о проекте и его зависимостях. В этом файле также можно настроить скрипты для запуска тестов.
Пример базовой конфигурации cypress.json:
{ "baseUrl": "http://example.com", "defaultCommandTimeout": 10000, "pageLoadTimeout": 30000, "viewportWidth": 1280, "viewportHeight": 720, "testFiles": "**/*.spec.js" }
Здесь:
-
baseUrl
задает базовый URL, к которому будут добавляться относительные URL в ваших тестах. -
defaultCommandTimeout
задает таймаут по умолчанию для команд Cypress в миллисекундах (в данном случае 10 секунд). -
pageLoadTimeout
задает максимальное время ожидания загрузки страницы (30 секунд). -
viewportWidth
иviewportHeight
задают ширину и высоту окна браузера для выполнения тестов. -
estFiles
указывает шаблон для файлов с тестами (в данном случае, все файлы с расширением .spec.js в любых подпапках).
Основной синтаксис и структура тестов в Cypress
Cypress использует цепочку команд. Тесты обычно организованы с помощью функций describe
и it
, которые являются частью глобального API Mocha.
Пример базового теста:
describe('Login Test', function() { it('Visits the login page', function() { cy.visit('https://example.com/login') // переход на страницу логина cy.get('input[name=username]').type('user1') // вводим имя пользователя cy.get('input[name=password]').type('password123') // вводим пароль cy.get('form').submit() // отправка формы cy.url().should('include', '/dashboard') // проверка URL после логина }) })
Поиск элементов осуществляется с помощью команды cy.get()
, которая принимает строку селектора. Cypress поддерживает большинство селекторов CSS.
Взаимодействие с элементами возможно через команды вроде .click()
, .type()
, .check()
для разных типов элементов.
Ассерты проверяют ожидаемое состояние или поведение элементов. Cypress интегрируется с Chai, предоставляя множество утверждений через .should()
или .expect()
.
Примеры:
cy.get('.list-item').should('have.length', 5) // проверка количества элементов cy.get('.alert').should('not.exist') // элемент не должен существовать
Cypress автоматически управляет асинхронностью, поэтому очень редко придется явно использовать async/await
. Например, если вы делаете запрос к API, Cypress дождется его завершения, прежде чем двигаться дальше:
cy.request('POST', '/api/users', {name: 'Alex'}).then((response) => { expect(response.body).to.have.property('name', 'Alex') // проверка ответа })
Cypress позволяет перехватывать HTTP-запросы, что делает возможным тестирование без реальных серверных ответов, используя моки:
cy.intercept('GET', '/api/users', {fixture: 'users.json'}).as('getUsers') cy.wait('@getUsers').its('response.statusCode').should('eq', 200)
Можно использовать псевдонимы для сохранения данных и их последующего использования в тестах:
cy.get('input[name=firstname]').type('Jane').as('firstname') cy.get('@firstname').should('have.value', 'Jane')
Cypress может делать снимки состояния приложения:
cy.visit('/settings') cy.get('.theme').click() cy.screenshot() // снимок изменённой темы
Примеры использования
Тестирование счётчика
Для компонента счётчика, который увеличивает или уменьшает значение при нажатии кнопок, тесты в Cypress могут проверять начальное состояние и реакцию на пользовательские действия:
describe('Counter Component', () => { beforeEach(() => { cy.visit('/'); }); it('should render the counter with initial value', () => { cy.get('h1').contains('Counter: 0'); }); it('should increment the counter when increment button is clicked', () => { cy.get('button').contains('Increment').click(); cy.get('h1').contains('Counter: 1'); }); it('should decrement the counter when decrement button is clicked', () => { cy.get('button').contains('Increment').click(); cy.get('button').contains('Decrement').click(); cy.get('h1').contains('Counter: 0'); }); });
Тест проверяет правильность начального отображения компонента и его изменение при взаимодействии пользователя с элементами управления.
Тестирование формы входа
Тестирование формы входа включает в себя проверку ввода данных пользователя и реакции формы на отправку:
describe('Login Form', () => { beforeEach(() => { cy.visit('/login'); }); it('should allow a user to type in the username and password', () => { cy.get('input[name="username"]').type('testuser'); cy.get('input[name="password"]').type('qwerty'); }); it('should show an error message for invalid credentials', () => { cy.get('input[name="username"]').type('invaliduser'); cy.get('input[name="password"]').type('wrongpassword'); cy.get('button[type="submit"]').click(); cy.get('.error-message').should('be.visible').and('contain', 'Invalid credentials'); }); it('should redirect to dashboard on successful login', () => { cy.get('input[name="username"]').type('testuser'); cy.get('input[name="password"]').type('qwerty'); cy.get('button[type="submit"]').click(); cy.url().should('include', '/dashboard'); }); });
Набор тестов проверяет как негативные, так и позитивные сценарии входа в систему.
Тестирование списка задач
Проверим добавление, удаление и валидацию элементов списка:
describe('Todo List Functionality', () => { beforeEach(() => { cy.visit('/todos'); }); it('displays the list of todos correctly', () => { cy.get('li').should('have.length', 2); // предположим, что уже есть два элемента в списке }); it('adds a new todo', () => { const newItem = 'Complete the test'; cy.get('.new-todo-input').type(`${newItem}{enter}`); cy.get('li').should('have.length', 3); }); it('deletes a todo', () => { cy.get('li').first().find('.delete-button').click(); cy.get('li').should('have.length', 1); }); });
Различные плагины
Cypress не только позволяет тестировать приложение, но и расширяет его возможности через плагины, рассмотрим мои любимые.
cypress-axe
Плагин cypress-axe
интегрирует инструменты доступности axe-core
с Cypress, позволяя тестировать веб-страницы на предмет соответствия стандартам доступности:
it('Tests accessibility on the page', () => { cy.visit('/your-page'); cy.injectAxe(); cy.checkA11y(); });
cypress-plugin-tab
Плагин добавляет поддержку событий клавиатуры, к примеру нажатие на клавишу Tab, что не поддерживается в базовой версии Cypress:
it('should be able to navigate fields with tab', () => { cy.get('#first-input').type('info').tab().type('more info'); });
cypress-graphql-mock
Плагин cypress-graphql-mock
позволяет мокать ответы GraphQL, что хорошо при разработке и тестировании клиентских приложений, которые используют GraphQL для взаимодействия с сервером:
it('mocks GraphQL data', () => { cy.mockGraphQL({ Query: { user: () => ({ id: 1, name: 'Artem' }) } }); cy.visit('/user-profile'); cy.contains('Artem'); });
Тест проверяет, что пользовательский интерфейс корректно отображает данные пользователя, мокая GraphQL запросы.
cypress-downloadfile
Плагин cypress-downloadfile
добавляет возможность скачивания файлов во время выполнения тестов:
it('downloads a file', () => { cy.downloadFile('http://example.com/file.pdf', 'mydownloads', 'example.pdf'); cy.readFile('mydownloads/example.pdf').should('exist'); });
Здесь скачивается файл PDF с предоставленного URL, после он сохраняется в директорию и далее проверяет наличие файла в системе.
cypress-localstorage-commands
Плагин cypress-localstorage-commands
добавляет команды для управления данными в localStorage во время тестирования:
beforeEach(() => { cy.restoreLocalStorage(); }); afterEach(() => { cy.saveLocalStorage(); }); it('tests local storage', () => { cy.setLocalStorage('testKey', 'testValue'); cy.getLocalStorage('testKey').should('eq', 'testValue'); });
Здесь перед каждым тестом восстанавливается состояние localStorage, а после теста — сохраняется.
Статья подготовлена в преддверии старта курса React.js Developer. В рамках запуска курса пройдут бесплатные вебинары, на которые могут зарегистрироваться все желающие:
-
Оптимизация работы компонентов в React.js. Зарегистрироваться
-
Эффективное управление состоянием в React.js: useState и useReducer. Зарегистрироваться
ссылка на оригинал статьи https://habr.com/ru/articles/831904/
Добавить комментарий