Основы тестирования React-приложений через Cypress

от автора

Привет, Хабр! Сегодня рассмотрим как автоматизировать тестирование 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. В рамках запуска курса пройдут бесплатные вебинары, на которые могут зарегистрироваться все желающие:


ссылка на оригинал статьи https://habr.com/ru/articles/831904/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *