Знакомая история

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

Вы попадаете туда и начинаете вносить изменения. Бац! Бум! Хлопнуть! Готово, Тед!

Вы отправляете свой сайт обратно в Pantheon и снова принимаете участие в работе над другими вещами.

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

*Глоток*. Вы знаете, что не проверяли каждую страницу 85-страничного сайта на каждом размере устройства после того, как добавили важную функцию X. Это было бы непрактично для разработчика, работающего в маркетинговом отделе со 150 сайтами, которые они должны поддерживать. Похоже, ты у Теда!

Визуальное регрессионное тестирование спешит на помощь

Визуальное регрессионное тестирование позволяет автоматически проверять любую страницу вашего сайта на предмет визуальных изменений, показывая вам ТОЛЬКО то, что изменилось.

К счастью, с помощью нескольких инструментов мы можем довольно легко выполнить эту настройку!

Соберите свои инструменты вместе

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

  • Экземпляр WordPress в Пантеоне.
  • Замечательный инструмент командной строки Pantheon, Terminus.
  • Lando. Потрясающе простой, невероятно полезный фреймворк для локальных разработчиков, поддерживаемый Тандемом.
  • Актуальная версия NodeJS
  • BackstopJS, где происходит волшебство с нашим визуальным регрессионным тестированием.

После того, как вы загрузили, установили и запустили все это, раскрутите локальный экземпляр Lando сайта, который вы хотите протестировать, и приступим!

Где это установить

На данный момент Pantheon позволяет размещать файлы WordPress либо в корне сайта, либо в каталоге web/. Подробнее здесь, если вы не знакомы.

Если вы используете каталог web/, вам нужно настроить тестирование в корне сайта, а не в корне Интернета:

.
|- web
   |- wp-include
   |- wp-admin
   // etc...
|- test
   |- visual-testing

Если вы не используете эту структуру, я бы порекомендовал вам использовать папку private в корне сайта, чтобы эти тесты не были общедоступными после развертывания в реальном времени.

.
|- wp-includes
|- wp-admin
// etc...
|- private
   |- test
      |- visual-testing

test/visual-testing часть этого пути произвольна. Назовите эти папки как хотите.

Запустите BackstopJS

Откройте свой терминал и cd в новую папку visual-testing. Если вы настроили BackstopJS как глобальную команду, введите backstop init, чтобы начать вечеринку!

После инициализации ваш проект должен выглядеть так:

|- visual-testing
   |- backstop_data
   |- backstop.json

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

Организация вашего проекта

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

|- visual-testing
   |- .gitignore
   |- package.json
   |- backstop_data
   |- config
      |- local.js
      |- stage.js
      |- shared
         |- base-config.js
         |- base-scenario.js
         |- config-maker.js
         |- live-links.json
         |- paths.js
         |- scenarios.js
         |- viewports.js

Вы могли заметить, что мы удалили файл backstop.json из нашего проекта. Одна из лучших особенностей BackstopJS заключается в том, что вы можете использовать для настройки обычные файлы JavaScript вместо статического JSON. Это означает, что мы можем делать еще более изящные вещи, чтобы не повторяться!

Получить опубликованный список опубликованных страниц из Пантеона

Первая задача - убедиться, что у нас есть список сообщений, которые действительно публикуются в сети. Pantheon упрощает это с помощью инструмента командной строки Terminus. Запустите эту команду (заменив все в ‹угловых скобках› материалами из вашего конкретного проекта) в своей тестовой папке и посмотрите, что произойдет:

terminus remote:wp <site-slug>.live -- post list --fields=url,name --post_status=published --post_type=page,post

Вы должны увидеть в своем терминале таблицу всех опубликованных сообщений на вашем действующем сайте. АККУРАТНЫЙ! Теперь, как мы можем передать это BackstopJS? Давайте отформатируем его в JSON и выведем в файл, который мы сможем использовать!

terminus remote:wp <site-slug>.live -- post list --fields=url,name --post_status=published --post_type=page,post --format=json > ./config/shared/live-links.json

Большой! В результате должен получиться большой объект JSON, который мы сможем засосать с помощью BackstopJS. Но это много написания. Давайте сохраним это в разделе scripts в нашем package.json файле, чтобы упростить выполнение. Откройте package.json и сделайте так:

{
  "name": "visual-regression-testing",
  "version": "1.0.0",
  "scripts": {
    "get-live-paths":
      "terminus remote:wp <site-slug>.live -- post list --post_status=published --post_type=page,post --fields=url,name --format=json > ./config/shared/live-links.json",
    "reference": "backstop reference --config=config/stage.js",
    "test-stage": "backstop test --config=config/stage.js",
    "test-local": "backstop test --config=config/local.js"
  },
  "dependencies": {
    "backstopjs": "^3.0.32"
  }
}

Не забудьте поменять «угловые скобки» для вашего сайта. Запустите npm install, чтобы получить BackstopJS из репо.

После этого вы можете ввести npm run get-live-links из папки visual-testing, и он обновит ваш файл, добавив в него самые новые ссылки. Большой!

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

Несколько сред: один конфигуратор

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

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

local.js

const configMaker = require('./shared/config-maker')
const id = 'backstop_local',
const referenceDomain = 'https://live-<site-slug>.pantheonsite.io',
const testDomain = 'http://<site-slug>.lndo.site',
module.exports = configMaker({ id, referenceDomain, testDomain })

stage.js

const configMaker = require('./shared/config-maker')
const id = 'backstop_stage'
const referenceDomain = 'https://live-<site-slug>.pantheonsite.io'
const testDomain = 'https://test-<site-slug>.pantheonsite.io'
module.exports = configMaker({ id, referenceDomain, testDomain })

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

config-maker.js

const baseConfig = require('./base-config')
const paths = require('./paths')
const viewports = require('./viewports')
const scenarios = require('./scenarios')
const configMaker = ({ id, referenceDomain, testDomain }) => ({
  ...baseConfig,
  id,
  paths,
  viewports,
  scenarios: scenarios(referenceDomain, testDomain),
})
module.exports = configMaker

configMaker принимает входные данные из каждой среды и передает их объекту, который в конечном итоге отправляется аргументу Backstop --config. Теперь, чтобы показать вам, что происходит за этими другими require утверждениями:

paths.js

const dir = 'backstop_data'
const locations = [
  'bitmaps_reference',
  'bitmaps_test',
  'engine_scripts',
  'html_report',
  'ci_report',
]
const paths = locations.reduce((prev, curr) => {
  prev[curr] = `${dir}/${curr}`
  return prev
}, {})
module.exports = paths

Это просто устанавливает основные пути, по которым блокиратор обратного хода должен выводить данные. Большинство этих каталогов должны быть частью вашего .gitignore! Фактически, вот как для меня выглядит .gitignore в моем проекте:

node_modules/
backstop_data
!backstop_data/engine_scripts

viewports.js

module.exports = [
  {
    label: 'phone',
    width: 320,
    height: 480,
  },
  {
    label: 'tablet',
    width: 1024,
    height: 768,
  },
]

Здесь вы можете установить количество размеров устройств, которые вы хотите протестировать в каждом сценарии. Аккуратный!

базовый сценарий.js

module.exports = {
  cookiePath: 'backstop_data/engine_scripts/cookies.json',
  readyEvent: '',
  readySelector: '',
  delay: 0,
  hideSelectors: [],
  removeSelectors: [],
  hoverSelector: '',
  clickSelector: '',
  postInteractionWait: '',
  selectors: [],
  selectorExpansion: true,
  misMatchThreshold: 0.1,
  requireSameDimensions: true,
}

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

Секретный соус: сценарии.js

const links = require('./live-links.json')
const baseScenario = require('./base-scenario')
module.exports = (referenceDomain, testDomain) =>
  links
    .filter(item => !!item.post_name)
    .map(item => ({
      ...baseScenario,
      label: `${item.post_name} (${item.url})`,
      url: `${testDomain}${item.url}`,
      referenceUrl: `${referenceDomain}${item.url}`,
    }))

Здесь мы извлекаем объект JSON, предоставленный Terminus, отфильтровываем все элементы, у которых нет post_name, применяем файл base-scenario к каждому элементу и настраиваем соответствующий URL-адрес и referenceUrl для каждого элемента.

base-config.js

module.exports = {
  onBeforeScript: 'chromy/onBefore.js',
  onReadyScript: 'chromy/onReady.js',
  report: ['browser'],
  engine: 'chrome',
  engineFlags: [],
  asyncCaptureLimit: 5,
  asyncCompareLimit: 50,
  debug: false,
  debugWindow: false,
}

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

Заключение

Теперь у тебя нет оправдания Теду! Запускайте этого щенка после каждого изменения и убедитесь, что вы не испортили этот симпатичный маленький маркетинговый сайт, над которым так усердно работали!