Статьи

Руководство по визуальному тестированию с Перси

Эта статья была создана в сотрудничестве с Перси . Спасибо за поддержку партнеров, которые делают возможным использование SitePoint.

Визуальное тестирование — это автоматизированный процесс проверки правильности вашего пользовательского интерфейса в разных браузерах и на разной ширине экрана.

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

В этом руководстве вы узнаете, как настроить и запустить визуальное тестирование для своего проекта с помощью Percy . В демонстрационных целях мы будем использовать одностраничное приложение, основанное на API, с использованием реальных данных. Вы узнаете, как визуально тестировать пользовательские интерфейсы, которые выводят динамические данные, а также о процессе визуального просмотра и утверждения Перси.

Предпосылки

Визуальное тестирование — тема для средних и продвинутых пользователей. Чтобы следовать этому уроку, вам должно быть удобно писать код в синтаксисе JavaScript ES6 +. Мы не будем заниматься реальной разработкой приложений, но вы должны по крайней мере иметь некоторый опыт использования следующих библиотек на тот случай, если вы захотите изменить что-то в демонстрационном проекте, который мы будем использовать:

  • Express.js + RESTful API
  • JQuery
  • Вардар
  • CSS фреймворки

Вы также должны быть знакомы с ветвлением Git и различными типами стратегий ветвления . Знание любой инфраструктуры тестирования также поможет вам легко понять концепции, обсуждаемые в этой статье. Вам нужно будет иметь учетную запись GitHub, прежде чем вы сможете продолжить изучение этого учебника. Мы будем использовать этот демонстрационный проект в качестве отправной точки.

О Перси

Percy предоставляет разработчикам платформу и рабочий процесс для проведения визуального тестирования и проверки веб-приложений, статических сайтов или библиотек компонентов. Есть бесплатный план, который поддерживает неограниченное количество членов команды, 5000 снимков в месяц (с историей за месяц) и неограниченное количество проектов.

Чтобы начать работу с Percy, установите один из его SDK в проект, который вы хотите визуально протестировать. Это то же самое, что установить среду тестирования, такую ​​как Mocha или Jest. Затем вы пишете скрипт и запускаете его так же, как при любом типе теста.

Однако в случае Перси снимки DOM вашего веб-приложения собираются и загружаются для рендеринга в инфраструктуре Перси. Затем Перси обнаруживает и выделяет визуальные различия между новыми и предыдущими снимками, также известными как базовые линии . Результаты отображаются в Percy, где вы можете просмотреть и определить, правильно ли выглядит пользовательский интерфейс или его нужно исправить.

Перси отображает каждый снимок в Chrome и Firefox и может отображать до десяти разных разрешений экрана. Это довольно впечатляюще, поскольку делать это вручную утомительно. Я призываю вас прочитать следующие документы, чтобы глубже понять:

Далее давайте углубимся в практическую реализацию процесса визуального тестирования. В этой статье мы будем:

  1. создать демонстрационный проект
  2. настроить панель инструментов проекта Percy
  3. генерировать снимки Перси
  4. обрабатывать динамические данные
  5. настроить рабочий процесс утверждения

Давайте начнем.

1. Настройка демонстрационного проекта

Мы собираемся провести визуальное тестирование в приложении на основе API, которое я создал ранее. Вы можете найти учебник по созданию этого приложения здесь, если вы заинтересованы.

В противном случае перейдите в этот репозиторий GitHub и подключите его к своей учетной записи GitHub. Затем откройте README.md для получения инструкций о том, как загрузить и настроить проект на жестком диске. Следуйте им, пока на вашем компьютере не запустится приложение.

Проект представляет собой одностраничное приложение на основе Express , jQuery и Handlebars . Вызовы AJAX с веб-страницы направляются на сервер Express, который, в свою очередь, направляет запросы сторонним поставщикам API валют. Приложение состоит из трех страниц:

Таблица курсов валют

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

Курс обмена: Биткойн на USD

Страница обменного курса позволяет вам конвертировать одну валюту в другую.

Таблица исторических курсов валют

Страница «Исторические курсы» аналогична странице «Курсы валют», за исключением того, что она позволяет отображать курсы за любую прошедшую дату, начиная с 1999 года.

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

2. Настройка панели проекта Перси

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

Страница регистрации Перси

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

Если вы чувствуете себя уверенно в навигации по панели инструментов, прокрутите вверх и нажмите кнопку « Создать проект» . Введите имя проекта на следующей странице: «Percy-Tutorial». Как только вы подтвердите имя, вы попадете на страницу Build, где вы можете настроить параметры визуального тестирования для вашего проекта.

Мы собираемся связать проект «Percy-Tutorial» с проектом, который вы ранее добавили в свою учетную запись GitHub. Во-первых, нам нужно дать Percy разрешение на доступ к нашим репозиториям GitHub. Хранилища в GitHub структурированы по организациям. Вы должны иметь роль «владелец», чтобы дать Percy разрешение на доступ к вашему хранилищу.

Перейдите на вкладку Integrations . В разделе «Связать репозиторий» вы получите сообщение с требованием «установить интеграцию» для вашей организации. Нажмите на него, и вы попадете на страницу со списком интеграций Перси. Следуйте инструкциям на экране, чтобы настроить интеграцию с GitHub и предоставить доступ ко всем репозиториям, на которых вы хотите выполнить визуальное тестирование. После того, как вы завершили шаги установки, вам нужно связать проект Percy-Tutorial

Связывание репозитория

Затем вернитесь к своему проекту Percy и перейдите на страницу Builds. Скопируйте PERCY_TOKEN Нам понадобится это для следующего шага.

3. Создание снимков Перси

Теперь, когда у нас есть проект Percy, готовый получать снимки, нам нужно сгенерировать и загрузить их в Percy для проверки. Мы будем использовать PercyScript для выполнения этой задачи. Перейдите в папку, в которой вы настроили демонстрационный проект. Откройте терминал и установите в него следующий пакет:

 npm install -D @percy/script

PercyScript использует Puppeteer , который является высокоуровневым API для управления браузером Chrome по протоколу DevTools. Короче говоря, Puppeteer позволяет нам взаимодействовать с веб-страницей так же, как люди, но используя код. Например, мы можем вводить текст и нажимать кнопки и ссылки. Обратите внимание, что браузер Chrome будет загружен в вашу папку node_modules

Затем создайте новый файл JavaScript в корне проекта, snapshots.js Этот скрипт создаст для нас три снимка, по одному для каждой страницы. Существует множество сценариев, по которым мы можем протестировать, но для простоты мы проверим только, чтобы убедиться, что каждая страница работает и правильно отображает результаты:

 const PercyScript = require('@percy/script');

PercyScript.run(async (page, percySnapshot) => {
    /**
    |---------------------------------------|
    | Generate Daily Rates Snaphsot         |
    |---------------------------------------|
    **/
    await page.goto('http://localhost:3000/');
    // wait for AJAX call to complete
    await page.waitForSelector('.loading', {
        hidden: true
    });
    // Take snapshot
    await percySnapshot('homepage');

    /**
    |---------------------------------------|
    | Generate Exchange Rate Snapshot       |
    |---------------------------------------|
    **/
    await page.goto('http://localhost:3000/exchange');
    // Wait for AJAX call to complete
    await page.waitForSelector('.loading', {
        hidden: true
    });
    await page.select('select#from', 'BTC'); // Select Bitcoin
    await page.select('select#to', 'USD'); // Select US Dollar
    await page.type('#amount', '1'); // Enter Amount
    await page.click('.submit'); // Hit the convert button
    // wait for AJAX call to complete
    await page.waitForSelector('.loading', {
        hidden: true
    });
    // Take snapshot
    await percySnapshot('exchange');

    /**
    |---------------------------------------|
    | Generate Historical Rates Snapshot    |
    |---------------------------------------|
    **/
    await page.goto('http://localhost:3000/historical');
    // wait for AJAX call to complete
    await page.waitForSelector('.loading', {
        hidden: true
    });
    // Set Calendar Date Input
    await page.evaluate(() => {
        document.getElementById('date').value = '2019-07-01';
    })
    // Click Fetch Rates Button
    await page.click('.submit');
    // wait for AJAX call to complete
    await page.waitForSelector('.loading', {
        hidden: true
    });
    // Take snapshot
    await percySnapshot('historical');
});

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

Одна вещь, которую я хотел бы уточнить, это то, что я использую Semantic UI Loader в проекте приложения Currency, чтобы указать пользователю, что запрос AJAX обрабатывается в фоновом режиме. Когда запрос завершен, загрузчик скрыт от просмотра с помощью CSS. В коде Puppeteer нам нужно дождаться исчезновения загрузчика, прежде чем мы сможем сделать снимок.

Перед запуском скрипта нам нужно запустить отдельный терминал для запуска нашего приложения с помощью команды npm start В противном случае Перси не сможет найти и взаимодействовать с нашим веб-приложением.

Давайте запустим скрипт. Если вы работаете в Windows, я рекомендую вам использовать Git Bash или любой Linux-терминал для выполнения следующей команды. Если вы настаиваете на использовании PowerShell или любого терминала на базе Windows, вам нужно будет использовать правильный синтаксис для установки переменных среды:

 $ export PERCY_TOKEN=aaabbbcccdddeee # Replace this with your project token
$ npx percy exec -- node snapshots.js

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

Первый запуск PercyScript в терминале

Ссылка на результаты будет создана для вас. Нажмите Alt + нажмите на ссылку, чтобы открыть страницу сборки панели инструментов. Вы также можете найти результаты непосредственно в Percy на вкладке Builds . После того, как вы откроете страницу, вам, возможно, придется немного подождать, пока результаты отобразятся; Первая сборка занимает больше времени, так как Перси собирает и отображает активы в первый раз. Так как это первые загруженные снимки, нет базовых данных, с которыми можно сравнивать, чтобы обнаружить визуальные различия.

Панель инструментов первой базовой сборки

Возможно, вы также заметили, что эти снимки были «автоматически одобрены». По умолчанию Перси автоматически одобряет любые тестовые сборки, выполненные в основной ветке. Вы можете изменить это в настройках вашего проекта.

Созданные снимки выглядят идеальными для использования в качестве основы для будущих испытаний. Однако есть проблема. Если вы сейчас поедете на ланч, а затем по возвращении снова запустите тесты, визуальный дифференциал будет обнаружен, несмотря на то, что ничего не изменится. Это будет происходить на страницах «Ежедневные курсы» и «Обменный курс». Страница истории не будет затронута, так как данные заморожены на определенную дату в прошлом.

Проблемный визуальный дифференциал

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

4. Обработка динамических данных

Если ваше приложение имеет дело с динамическими данными, вы можете запустить его в тестовой среде, где оно будет заполнять фиксированные данные. Для этих проектов можно использовать библиотеки генерации данных, такие как faker.js . В нашем случае мы имеем дело с динамическими данными, полученными из реального удаленного RESTful API. Чтобы решить эту проблему, нам нужно перехватить запросы HTTP API и заменить ответы нашими локальными данными. Puppeteer имеет функцию page.setRequestInterception (true), которая позволяет нам делать именно это.

Нам нужно будет перехватывать запросы на страницах «Ежедневные курсы валют» и «Обмен валют». Во время тестирования мы будем предоставлять запросы с нашими данными, чтобы моментальные снимки всегда были согласованными. Обновите snapshots.js Убедитесь, что размещаете макет данных и кода сверху, как показано ниже:

 const PercyScript = require('@percy/script');

const mockRates = {
  "success": true,
  "timestamp": 1563176645,
  "base": "EUR",
  "date": "2019-07-15",
  "rates": {
    "EUR": 1,
    "USD": 1.12805,
    "GBP": 0.897815,
    "AUD": 1.604031,
    "BTC": 0.00011,
    "KES": 116.200495,
    "JPY": 121.793281,
    "CNY": 7.75354
  }
};

const mockConvertRate = {
  "rate": 10244.442
}

PercyScript.run(async (page, percySnapshot) => {
  /**
  |---------------------------------------|
  | Mock Page Requests                    |
  |---------------------------------------|
  **/

  //Activate request interception
  await page.setRequestInterception(true);
  // Listen to each page request
  page.on('request', request => {
    // Mock Daily Rates API
    if (request.url().includes('/api/rates')) {
      request.respond({
        status: 200,
        contentType: "application/json; charset=utf-8",
        body: JSON.stringify(mockRates) // return mock rates data
      });
    }
    // Mock Convert/Exchange API
    else if (request.url().includes('/api/convert')) {
       request.respond({
         status: 200,
         contentType: "application/json; charset=utf-8",
         body: JSON.stringify(mockConvertRate) // return convert rate data
       });
    } else {
      request.continue();
    }
  });
}
//...

Еще раз запустите ваши тесты Percy: npx percy exec -- node snapshots.js Дайте это несколько минут. Вскоре у вас должна быть чистая сборка, которую мы будем использовать в качестве основы для будущего визуального тестирования.

5. Процесс утверждения

В ходе разработки проекта в приложение будет внесено много изменений. Некоторые изменения могут быть случайными, другие преднамеренными. В любом случае, изменения должны быть одобрены руководителем проекта или членом команды. Предполагая, что у вас есть стратегия ветвления Git, это краткое изложение того, как выглядит рабочий процесс утверждения:

  1. создать новую ветку
  2. вносить и фиксировать изменения в ветви функций
  3. создайте пул-запрос через панель инструментов GitHub
  4. запустить тесты Перси
  5. одобрить сборку в панели инструментов Percy
  6. объединить ветку
  7. создать новую базовую линию по мастеру

Давайте прыгнем и немного потренируемся. Начнем с создания новой функциональной ветви:

 git checkout -b feature-1

Далее давайте внесем некоторые визуальные изменения. Мы изменим цвет значка и кнопки. Откройте index.htmlorangegreenmenu Оставь этот апельсин. Только icons Затем передайте изменения и отправьте их в удаленное хранилище:

 git add .
git commit -m "Replaced Orange Color with Green"
git push -u origin feature-1

Затем перейдите на страницу репозитория GitHub и создайте новый пул-запрос:

Создание нового пул-запроса на GitHub

Вы также можете нажать на ссылку запроса на отправку, предоставленную вам после отправки ветки на удаленный сервер. Не стесняйтесь предоставить комментарий. После этого вы можете сгенерировать новую визуальную тестовую сборку: npx percy exec -- node snapshots.js

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

Не удалось проверить запрос

Нажав на кнопку « Детали» , вы попадете на Перси, чтобы просмотреть визуальные изменения.

Дневной курс визуального различия:

дневные ставки визуального различия

Курсы валют визуального различия:

обменные курсы визуальные различия

Исторические курсы визуальных различий:

исторические курсы визуального различия

Все выглядит отлично. Проверьте, чтобы увидеть изменения в браузерах и ширине устройства. Визуальные изменения должны быть такими, как ожидалось. Вы можете одобрить одно за другим или нажать кнопку « Подтвердить все» вверху. Быстро переключитесь на панель инструментов GitHub, и вы увидите обновление вашего запроса на извлечение:

Подтверждение запроса на перси

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

 git checkout master
git pull
npx percy exec -- node snapshots.js

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

базовая логика выбора

Запускать визуальные тесты каждый раз, когда мы нажимаем коммит или объединять ветки, утомительно. Хорошей новостью является то, что мы можем автоматизировать этот процесс с помощью платформы непрерывной интеграции. Запускать тесты локально — это хорошо, пока вы начинаете, но Percy предназначен для участия в автоматическом тестировании, запущенном вашей платформой CI. Перси поддерживает несколько :

  • AppVeyor
  • Лазурные Трубопроводы
  • Buildkite
  • CircleCI
  • CodeShip
  • трутень
  • GitLab CI
  • Дженкинс
  • семафор
  • Трэвис CI

Вы также можете разместить свой собственный сервер CI / CD в своей локальной сети; Перси тоже это поддерживает. Если вашего предпочтительного решения нет в списке, вы можете пообщаться со службой поддержки Percy или с вашим поставщиком CI / CD для настройки.

SDK Интеграция

Прежде чем мы закончим, я хотел бы упомянуть, что есть ряд SDK, которые позволяют вам использовать существующую платформу для создания снимков Percy. Например, если вы используете Cypress , вы используете Percy / Cypress SDK, чтобы использовать существующий пакет для визуального тестирования. Вот пример того, как мы можем использовать Cypress для создания снимков Percy:

 describe('CurrencySPA', () => {

    beforeEach(() => {
        cy.server();
        cy.route('GET', '/api/rates', 'fixture:rates.json'); // Mock Daily Rates Response

        cy.visit('localhost:3000');
    })

    it('Loads Daily Rates', () => {
        cy.get('#app > h1').should('have.text', 'Currency Rates'); // Confirm Page Header Title
        cy.get('.loading').should('not.be.visible');
        cy.get('tbody>tr').eq(0).should('contain', 'EUR');
        cy.get('tbody>tr').eq(1).should('contain', '1.12805');
        cy.percySnapshot();
    });

    it('Convert Currency', () => {
        cy.route('POST', '/api/convert', { // Mock Convert Currency Response
            "rate": 10244.442
        });
        cy.get('.menu > a:nth-child(3)').click(); // Click Exchange Rates Menu
        cy.get('#app > h1').should('have.text', 'Exchange Rate'); // Confirm Page Header Title
        cy.get('.loading').should('not.be.visible');
        cy.get('#from').select('BTC');
        cy.get('#to').select('USD');
        cy.get('#amount').type('1');
        cy.get('.submit').click();
        cy.get('#result').should('have.text', 'USD 10244.442');
        cy.percySnapshot();
    });

    it('Loads Historical Rates', () => {
        cy.get('.menu > a:nth-child(4)').click(); // Click Historicals Rates Menu
        cy.get('#app > h1').should('have.text', 'Historical Rates'); // Confirm Page Header Title
        cy.get('#date')
            .type('2019-07-02') // Will revert to 2019-07-01 (known bug)
            .blur();
        cy.get('.submit').click();
        cy.get('table').should('be.visible');
        cy.percySnapshot();
    });
});

Довольно аккуратно, правда?

Есть и другие комплексные тестовые интеграции, которые поддерживает Перси. Для полного списка интеграций, вы должны проверить страницу Percy SDK . Вы также можете создать свой собственный SDK, если нет альтернативы используемой вами технологии.

Резюме

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

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

Благодаря технологии визуального тестирования вы теперь можете получить 100% тестовое покрытие для своих проектов. Хотя Percy не гарантирует, что проблемы не исчезнут, Перси значительно снизит риск вашей команды по выпуску продуктов для конечных пользователей с дефектами.