Спасательное автоматизированное тестирование интерфейсов для бизнес-проектов с помощью Cypress

CI/CD тестовое задание

cypress-cover

Некоторые теории о внешнем тестировании и основанные наCypressСпецифическая практика тестирования E2E.

Некоторые мысли об автоматизированном тестировании переднего плана

Одна из болевых точек ежедневной разработки бизнес-проектов — внешний интерфейс.回归测试, то неизбежно щелкнуть по нему вручную, но если вы измените общий компонент или функцию, вы должны щелкнуть на главной странице проекта повсюду, чтобы увидеть, есть ли какая-либо проблема. использованный проектGraphQLЕсли схема не будет обновлена ​​вовремя, страница, которую вы не заметите, зависнет, и тогда вы можете подождать, чтобы открыть проблему или сообщить об ошибке онлайн 😐

Щелкать вручную не только утомительно, но и ненадежно, и нет гарантии, что функции, требующие регрессионного тестирования, будут тестироваться каждый раз. Чтобы решить эту болевую точку, мы должны упомянуть前端的自动化测试. Было бы здорово запускать тесты через командную строку и интегрировать автоматизированное тестирование CI.

Однако отечественные заводы еще не сформировали хорошую практику автоматизированного тестирования фронтенда, когда речь заходит об автоматизированном тестировании, все думают о тестировании бэкенда. На нескольких технических конференциях (JSConf, GMTC и т. д.) очень мало тем, посвященных фронтенд-тестированию, и некоторые из них также обсуждаются иностранными фронтенд-инженерами или QA делятся созданием тестовых платформ.

По моему опыту,Фронтенд-тестирование для бизнес-проектовЭто все "неловко". Если это библиотека средств разработки, качество может быть гарантировано с помощью модульного тестирования, если это библиотека компонентов пользовательского интерфейса, это может быть достигнуто с помощьюStorybookдля визуального и моментального тестирования. Так что раньше, каждый раз, когда я думал о том, как интегрировать автоматизированное тестирование в бизнес-проекты, я чувствовал, что понятия не имею, с чего начать (и несколько раз меня пугало больше тестового кода, чем бизнес-кода).

Однако в бизнес-проекте не так много инструментальных функций, требующих модульного тестирования (большинство из них используют lodash или другие сторонние библиотеки для решения сложной логической обработки), а компоненты пользовательского интерфейса в основном напрямую используют более зрелый ant-mobile, ant -дизайн и др. В решении не так много компонентов UI, которые нужно разрабатывать в бизнес-проектах.Большинство из них представляет собой вторичную инкапсуляцию на основе сторонних компонентов UI в сочетании с бизнес-логикой (собственно, ant-design тоже ставит свои компоненты отдельно вGitHub.com/react-compo…сохраняется).

Сценарии, которые нуждаются в автоматизированном тестировании в бизнес-проектах, в основном хотят охватить основные пути использования пользователей, такие как вход и регистрация, добавление покупок в корзину, просмотр заказов, изменение личной информации и т. д., которые тесно связаны с логика рендеринга интерфейса UI.Необходимо проверить, являются ли отправка формы, автоматический переход и рендеринг данных этих страниц ненормальными.

Итак, здесь мы можем разобраться с нашими потребностями:

  1. Может имитировать операцию ввода щелчка пользователя, управляемую событиями, чтобы проверить, соответствует ли рендеринг страницы ожидаемому.
  2. Можно использовать командную строку для запуска тестов, можно интегрировать в CI
  3. Легкая и эффективная, среду легко построить, а тестовый код легко написать (в конце концов, это дополнение к гибкой разработке и непрерывной интеграции, а не тест в ссылке QA, поэтому его нельзя оставлять позади)

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

Cypress

Cypress — это готовый фреймворк для E2E-тестирования, разработанный на основе API Mocha. Он не зависит от интерфейсных фреймворков или других библиотек инструментов для тестирования. автоматически захватывать и записывать скриншоты экрана, реализовывать путешествия во времени и отлаживать в процессе тестирования и т. д.

Подводя итог, преимущества Cypress:

  1. Простая настройка и быстрая интеграция в существующие проекты
  2. Поддерживает все уровни тестирования (т. е. вышеупомянутые тесты e2e, интеграционные тесты, модульные тесты и т. д.)
  3. Моментальные снимки могут быть созданы для каждого шага теста, легко отлаживать
  4. Все узлы DOM на веб-странице могут быть получены и обработаны
  5. Функция автоматического повтора, Cypress несколько раз повторит попытку на текущем узле, а затем сделает вывод, что тест не пройден.
  6. Легко интегрируется в системы CI

По сравнению с другими аналогичными инструментами тестирования, такими как Selenium, Puppeteer и Nightwatch, синтаксис тестового кода Cypress проще и более удобен для интерфейсных инженеров, обеспечивая легкий вес и эффективность платформы.

cypress-gui

Кратко опишите, как им пользоваться (подробнее см.Руководство по официальному сайту):

Установить:

yarn add cypress --dev

Добавьте в скрипты npm вашего проекта:

{
  "scripts": {
    "cypress:open": "cypress open"
  }
}

Конфигурация в корневом каталогеcypress.json:

{
    "baseUrl": "http://localhost:8080", // 本地启动的 webpack-dev-server 地址
    "viewportHeight": 800, // 测试环境的页面视口高度
    "viewportWidth": 1280 // 测试环境的页面视口宽度
}
npm run cypress:open

Это открыло тестовый графический интерфейс локально, готовый к тестированию.

Используйте пример из официальной документации, чтобы проиллюстрировать, как написать тестовый код:

describe('My First Test', function() {
  it('Gets, types and asserts', function() {
    cy.visit('https://example.cypress.io')

    cy.contains('type').click()

    // Should be on a new URL which includes '/commands/actions'
    cy.url().should('include', '/commands/actions')

    // Get an input, type into it and verify that the value has been updated
    cy.get('.action-email')
      .type('fake@email.com')
      .should('have.value', 'fake@email.com')
  })
})

Это действительно было проверено:

  1. Откройте целевую страницу, вот образецexample.cypress.io, на самом деле это должна быть локально запускаемая серверная страница в проекте, напримерhttp://localhost:8080
  2. Найдите кнопку с текстовым содержимым «тип» в dom страницы и нажмите на нее (если кнопка не отображается на странице, тест не запускается)
  3. После нажатия кнопки страница должна перейти на страницу, содержащую «/commands/actions» в маршруте.
  4. В dom этой страницы вы можете найти поле ввода с именем класса ".action-email". После ввода в него "fake@email.com" значение поля ввода должно быть "fake@email.com". '

Семантика тестового кода лучше, объем кода невелик и нет необходимости писать много асинхронной логики.

До сих пор я испытал конфигурацию установки и локальное тестирование, все в порядке, много функций, относительно простое начало работы и несложная интеграция в проект.

Покрытие тестами и непрерывная интеграция (на примере Gitlab)

Любые тесты, не интегрированные в CI, просто игрушки и не в счет. Итак, давайте посмотрим на производительность Cypress.

Мы надеемся, что Cypress можно настроить для выполнения разных тестовых команд на разных этапах разработки. Например, когда вы инициируете PR для функциональной ветки, вы можете выполнить интеграционное тестирование в текущей ветке.Когда вы достигнете основной ветки, вам необходимо рассчитать тестовое покрытие и передать данные на платформу проверки качества, такую ​​​​как Sonar ( вы также можете установить тестовое покрытие, если тестовое покрытие не соответствует xx%), сбой теста и т. д.).

Итак, давайте сначала посмотрим, как рассчитывается тестовое покрытие. Вычисление тестового покрытия Cypress кажется функцией, которая была добавлена ​​позже, и конфигурация немного сложна.

еще можно уточнитьСправочный документ, просто краткое введение в блоге:

Сначала установите зависимости:

npm install -D @cypress/code-coverage nyc istanbul-lib-coverage

Затем настройте конфигурацию в Cypress:

// cypress/support/index.js
import '@cypress/code-coverage/support'

// cypress/plugins/index.js
module.exports = (on, config) => {
  on('task', require('@cypress/code-coverage/task'))
}

Документация здесь только представлена, если в проекте используется TypeScript, этого недостаточно, я просмотрела официальный пример на github и обнаружила, что нужно сделать еще несколько шагов:

npm i -D babel-plugin-istanbul

настроить его.babelrc

{
  "plugins": ["istanbul"]
}

Измените его сноваcypress/plugins/index.js

// cypress/plugins/index.js
module.exports = (on, config) => {
  on('task', require('@cypress/code-coverage/task'))
  on('file:preprocessor', require('@cypress/code-coverage/use-babelrc'))
}
"cy:run": "cypress run && npm run test:report",
"instrument": "nyc instrument --compact=false client instrumented",
"test:report": "npm run instrument && npx nyc report --reporter=text-summary",

пройти черезcypress runВы можете запускать тесты прямо в командной строке, не запуская GUI, эту команду следует использовать при использовании в CI.

Посмотрите на результаты, очень доволен.

coverage-result

Покрытие E2E-тестов Cypress также можно комбинировать с модульными тестами или с помощью тестов других фреймворков, таких как Jest.Конкретный метод можно найти на официальном сайте.

Давайте возьмем Gitlab CI runner в качестве примера, чтобы увидеть, как Cypress интегрируется в CI:

// .gitlab-ci.yml
variables:
  npm_config_cache: "$CI_PROJECT_DIR/.npm"
  CYPRESS_CACHE_FOLDER: "$CI_PROJECT_DIR/cache/Cypress"

stages:
  - test
  - sonar

cache:
  paths:
  - .npm
  - node_modules/
  - cache/Cypress

build:
  stage: sonar
  tags:
    - docker
  script:
    - yarn
    - sh ci/sonar.sh
    - yarn build
  artifacts:
    expire_in: 7 day
    paths:
      - codeclimate.json
      - build

cypress-e2e-local:
  image: cypress/base:10
  tags:
    - docker
  stage: test
  script:
    - unset NODE_OPTIONS
    - yarn
    - $(npm bin)/cypress cache path
    # show all installed versions of Cypress binary
    - $(npm bin)/cypress install
    - $(npm bin)/cypress cache list
    - $(npm bin)/cypress verify
    - npm run test
  artifacts:
    expire_in: 1 week
    when: always
    paths:
    - coverage/lcov.info
    - cypress/screenshots
    - cypress/videos

Здесь мы настраиваем два этапа CI, тестируем и собираем (сканирование с помощью Sonar, отчеты о данных и т. д.) и используем официальный образ Cypress на этапе тестирования.cypress/base:10. (Другие настройки переменных среды и зависимости, такие как сканирование Sonar, пряжа и т. д., находятся в нашем собственном образе Docker)

где CI выполняет командуnpm run testДа:

"test": "start-server-and-test start http://localhost:5000 cy:run"

Здесь для упрощения команды используется пакет npmstart-server-and-testРеализовать логику выполнения теста после запуска локального Сервера.

мы тоже.gitlab-ci.ymlустановить вartifacts:

  artifacts:
    expire_in: 1 week
    when: always
    paths:
    - coverage/lcov.info
    - cypress/screenshots
    - cypress/videos

Это из гитлабаjob artifactsФункция может быть настроена на загрузку содержимого определенной папки на сервер после завершения определенного шага, и в течение допустимого времени мы можем просматривать или загружать содержимое этих файлов на веб-странице. Таким образом, если тест CI не пройден, мы можем просмотреть видео и снимок провала теста в артефактах, чтобы избежать слепого угадывания Отладка.

artifacts

Их много в настройке CI, и управление тестовыми случаями может копнуть глубже. Например, тестовый дым в тесте, общий объем теста или тестирование на стороне клиента, тест уровня узла и тому подобное.

Cypress Применимые тестовые сценарии также больше, например, путем установки пользовательских разрешений Cookie разных тестов, введение случайных нажатий PERM.js достигают различных тестов вкладок, значения возврата интерфейсов MOCK, и так далее.

glebbahmutov.com/blog/Это блог главного мейнтейнера Cypress, в котором также записано множество неряшливых операций (таких как проверка контрастности веб-страницы на соответствие условиям и т. д.) Если вам интересно, можете копать дальше.

яма

Одна ошибка, которую я обнаружил в своей практике, заключается в том, что Cypress не поддерживаетfetchЗапросил поддержку (GitHub.com/cypress-IO/…Мок-запросы, решить которые можно только грязным взломом.

Внедрить в проектwhatwg-fetch, а затем изменитьcypress/support/command.js:

// cypress/support/command.js
Cypress.Commands.add('visitWithDelWinFetch', (path, opts = {}) => {
    cy.visit(
        path,
        Object.assign(opts, {
            onBeforeLoad(win) {
                delete win.fetch;
            },
        })
    );
});

Таким образом, мы можем проверить решение о перенаправлении входа в систему нашего проекта:

describe('Node server', function() {

  it('no cookie get 401', function() {
    cy.server()

    cy.clearCookies()

    cy.route('POST', '**/graphql').as('login')

    cy.visitWithDelWinFetch('/');

    cy.wait('@login').then((xhr) => {
      expect(xhr.status).to.eq(401)
    })
  })

  it('with cookie get 200', function() {
    cy.server()

    cy.route('POST', '**/graphql').as('loginWithCookie')

    cy.visitWithCookie('/');

    cy.wait('@loginWithCookie').then((xhr) => {
      expect(xhr.status).to.eq(200)
    })
    // login successfully, so display the content
    cy.get('.ant-layout-sider')
    cy.get('.ant-layout-content')
  })
})

aha~

sonar