Cypress. Тестируем JavaScript-приложение легко

В данный момент уже трудно представить себе веб-приложение без автоматических тестов. Они позволяют нам сохранять уверенность в том, что приложение работает после изменений. Делегирование процесса тестирования машине позволяет сэкономить время не уменьшив при этом объем проводимых проверок.

Существуют разные виды автоматических тестов. Это отдельная большая тема. Данная статья будет сфокусирована на сквозных (end-to-end или e2e) тестах при помощи Cypress.

Содержание

Сквозное тестирование

Сквозное тестирование — это вид тестирования, который проверяет работу приложения в процессе от начала до конца. При нем происходит имитация реального пользовательского сценария и проверка правильности поведения системы. Такой вариант максимально приближен к реальной работе приложения, а поэтому его результат наиболее достоверен.

К минусам, однако, можно отнести более медленную работу такого варианта. И действительно, чтобы провести тест по реальному пользовательскому сценарию необходимо запустить приложение в браузере, произвести действия при помощи мыши или клавиатуры, дождаться реакции приложения в виде отправки и получения данных, смены одних элементов другими на странице.

Как происходит тестирование в Cypress

Cypress умеет открывать нужные URL в браузере, производить клики по элементам, заполнение полей, а также проводить необходимые проверки. Например, мы можем проверить, что элемент с тем или иным классом появился на странице после действий пользователя, проверить, что в определенном месте выведен нужный текст.

Еще одним важным умением Cypress является возможность перехвата запросов к backend и отправка ответов вместо него. Можно даже разрабатывать ваше приложение, не имея рабочего backend, а просто договорившись о формате взаимодействия между backend и frontend. Приложение в тесте работает точно также, как если бы оно работало с настоящим backend. Это делает тесты наиболее достоверными.

Cypress имеет режим, при котором вы видите все, что происходит в тесте, что удобно для отладки. Экран Cypress состоит из нескольких фреймов: в одном фрейме открывается приложение, которое мы тестируем, в другом фрейме запускаются тесты. Код тестов пишется на JavaScript, поэтому они могут выполняться непосредственно в браузере.

Так же есть безголовый (headless) режим, при котором вы видите только результаты. Этот вариант удобен при автоматическим запуске тестов в CI-CD.

Cypress не использует Selenium WebDriver, который обращается к браузеру по WebDriver-протоколу и накладывает ограничения на работу с браузером в рамках протокола.

Установка и запуск Cypress

Какое веб-приложение вы будите подвергать сквозному тестированию через Cypress, в общем-то, не важно. Все равно оно будет открываться в браузере. Можете создать его на Vue, React, голом JavaScript или вообще без JavaScript.

Рассмотрим пример с Vue приложением. Сначала создадим его используя команду npm create vue@latest. Не принципиально использовать именно такой способ. Чтобы не привязываться к данному установщику не будем выбирать установку Cypress при запросе, а поставим его отдельно.

Перейдя в папку созданного проекта добавим нужный пакет:

npm install cypress --save-dev

При использовании Linux нужно, чтобы в системе были установлены некоторые зависимости. Они могут быть уже установлены у вас. Если это не так, то воспользуйтесь командами из документации.

Когда вы запускаете тест в Cypress, то для его работы нужно, чтобы уже было запущено ваше приложение (dev-сервер должен работать). Дело в том, что тест будет открывать страницы приложения в браузере используя URL. Если приложение не будет запущено, то все тесты провалятся, даже если нет ошибок.

Теперь для запуска Cypress нам нужна эта команда:

npx cypress open

Вывод будет примерно следующий:

Need to install the following packages:
cypress@13.13.3
Ok to proceed? (y) 
It looks like this is your first time using Cypress: 13.13.3

✔  Verified Cypress! /home/igor/.cache/Cypress/13.13.3/Cypress

Opening Cypress...

DevTools listening on ws://127.0.0.1:44579/devtools/browser/7a3c8f51-0a4c-49c2-adcc-3fc8432ac024
(node:11535) ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
(node:11535) ExperimentalWarning: The Node.js specifier resolution flag is experimental. It could change or be removed at any time.

И откроется следующее окно:

Окно Cypress при первом запуске
Окно Cypress при первом запуске

Нажав на кнопку E2E Testing вы увидите следующее:

Экран с созданными конфигурационными файлами
Экран с созданными конфигурационными файлами

После этого вам необходимо внести некоторые изменения в файл cypress.config.js. В секцию e2e нужно добавить specPattern и baseUrl:

import { defineConfig } from "cypress";

export default defineConfig({
  e2e: {
    specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}',
    baseUrl: 'http://localhost:5173'
  },
});

Теперь первый экран уже не будет показывать надпись Not configured для E2E. И при нажатии этой кнопки вы перейдете к экрану выбора браузера:

Экран выбора браузера в Cypress
Экран выбора браузера в Cypress

Если выбрать браузер и нажать кнопку старта, то мы пока не увидим тестов, так как их нет. Вместо них мы увидим сообщение об их отсутстувии:

Но это не проблема. Ведь в cypress очень легко создавать тесты. В тестовом репозитории вы можете найти тесты из этой статьи. Давайте рассмотрим их код.

Простые тесты

describe('My First Test', () => {

    it('visit the app root url', () => {
        cy.visit('/')
        cy.contains('h1', 'You did it!')
    })

    it('visit the about url', () => {
        cy.visit('/about')
        cy.contains('h1', 'This is an about page')
    })

    it('show hidden area', () => {
        cy.visit('/about')
        cy.get('[data-test=hidden-area]').should('not.exist')
        cy.get('[data-test=main-button]').click()
        cy.get('[data-test=hidden-area]').should('be.visible')
    })

    it('load data from backend', () => {
        cy.visit('/about')

        cy.intercept('GET', 'http://backend.test/api/some/url', {
            body: {
                message: 'Hello world',
            },
        })

        cy.get('[data-test=load-button]').click()
        cy.get('[data-test=message]').contains('Hello world')
    })
})

Здесь через блок describe описывается группа тестов с заголовком My First Test. Названием может быть любым, в том числе и на кириллице. В группе 4 теста, каждый из которых представлен блоком it со своим заголовком.

Первые 2 теста совсем простые. Даже не зная Cypress можно понять, что там происходит – открывается нужная страница и проверяется содержимое тега h1.

В следующем тесте уже есть интерактивность. Выражение cy.get служит для поиска нужных элементов. В этом тесте для поиска мы используем атрибут data-test.

Искать элементы можно используя любые селекторы (как в JQuery). Однако в документе с лучшими практиками Cypress рекомендуется не использовать для этого CSS-классы, а использовать специальные атрибуты data-test или data-cy. Все дело в том, что при изменениях в оформлении CSS-классы могут меняться. Чтобы тесты при этом продолжили работать, нам нужен более надежный способ определить нужный элемент.

И так в этом тесте сначала с помощью should('not.exist') мы убеждаемся, что элемент отсутствует на странице, затем делаем клик по кнопке и убеждаемся, что элемент после этого видим.

В последнем тесте происходит перехват обращения к backend и подмена ответа. Так мы можем тестировать frontend не имея даже работающего backend. В начале теста мы прописываем нужный ответ, а далее так же – клик по кнопке и проверка, что блок содержит текст, который был получен в ответе.

Код компонента тестируемый страницы выглядит так:

<template>
  <main class="about">
    <div>
      <h1>This is an about page</h1>
      <div v-if="visible" data-test="hidden-area">
        <h2>Hidden area</h2>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc in nulla id mi sodales dapibus.
        </p>
      </div>
      <button v-else data-test="main-button" @click="visible = true">Show hidden area</button>
      <div class="backend-section">
        <p>Load data from backend: <span data-test="message" v-if="backendMessage">{{ backendMessage }}</span></p>
        <button v-if="!backendMessage" data-test="load-button" @click="load()">Load</button>
      </div>
    </div>
  </main>
</template>

<script setup>
import {ref} from 'vue'
import axios from '@/axios.js'

const visible = ref()
const backendMessage = ref()

async function load() {
  const result = (await axios.get('/some/url')).data
  backendMessage.value = result.message
}
</script>

Как мы видим здесь есть те самые 2 кнопки. Одна управляет видимостью определенного блока, а другая – запускает обращение серверу.

Сейчас запуск тестов покажет нам уже какое-то количество полезной информации:

Экран после запуска тестов Cypress
Экран после запуска тестов Cypress

Стоит отметить, что здесь не просто можно видеть какой тест прошел или провалился, но для каждого шага теста можно посмотреть состояние страницы. Это работает благодаря тому что, Cypress делает мгновенные снимки состояния. Благодаря этой информации гораздо легче искать причину падения теста.

Запуск без GUI

Для запуска в CI-CD, когда нам не нужна интерактивность служит команда npx cypress run:

Результат запуска headless-режима Cypress
Результат запуска headless-режима Cypress

Итоги

Как можно видеть на этих примерах, создать первые E2E-тесты в Cypress можно очень быстро и просто. Порог вхождения здесь не такой высокий.

Наиболее интересными свойствами инструмента можно назвать возможность смотреть состояние страницы на каждом этапе теста и возможность перехвата сообщений к backend.

Код примера – в репозитории.

Полезные ссылки

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии