Искусство тестирования макета с помощью Galen Framework

Опубликовано: 2022-03-10
Краткое резюме ↬ При разработке графического пользовательского интерфейса всегда остается открытым вопрос: как мы можем автоматизировать его тестирование? И как нам убедиться, что макет веб-сайта остается отзывчивым и правильно отображается на всех типах устройств с различными разрешениями? Добавьте к этому сложности, возникающие из-за динамического контента, требований к интернационализации и локализации, и это станет настоящим испытанием. В этой статье я познакомлю вас с новой интересной техникой тестирования макета. Используя Galen Framework , я предоставлю подробное руководство по написанию осмысленных обобщенных тестов компоновки, которые можно выполнять в любом браузере и на любом устройстве и в то же время использовать как единый источник достоверности в вашей проектной документации.

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

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

Дальнейшее чтение на SmashingMag:

  • Визуальная разработка через тестирование для адаптивного дизайна интерфейса
  • Основы автоматизации тестирования приложений, игр и мобильной сети
  • Разнообразные среды автоматизации тестирования для приложений React Native

Я также покажу, как я разработал оптимизированный тест для страницы обмена сообщениями на нашем сайте объявлений Marktplaats. Мы узнаем, как расширить синтаксис Галена с помощью нашего собственного языка, как улучшить тестовый код и как превратить процедуру тестирования макета в искусство.

Еще после прыжка! Продолжить чтение ниже ↓

Введение в фреймворк Galen

Год назад Galen Framework был рассмотрен в статье «Визуальная разработка через тестирование для адаптивного дизайна интерфейса». В то время его синтаксис был ограничен. С тех пор он значительно улучшился и получил много новых функций, которые мы рассмотрим здесь.

Если вы не знакомы с Galen Framework, это инструмент для адаптивного и кросс-браузерного тестирования макета и функционального тестирования с собственным языком тестирования под названием Galen Specs. Он основан на Selenium WebDriver, а также имеет богатый API JavaScript, который позволяет вам напрямую работать с WebDriver. Поскольку у вас есть контроль над WebDriver, вы можете запускать тесты в любом браузере, в облаке (SauceLabs, BrowserStack, PerfectoMobile и т. д.) или на реальных мобильных устройствах с помощью Appium.

Установка и выполнение

Настроить Galen Framework очень просто. Просто выполните следующую команду, чтобы установить его через npm:

 npm install -g galenframework-cli

Если вы не используете npm, просто скачайте последний архив Galen Framework, распакуйте пакет и следуйте инструкциям по установке.

После установки Galen Framework можно запускать различными способами. Например, вы можете использовать команду check , чтобы запустить быстрый тест одной страницы. Для этой команды вам нужно предоставить файл .gspec с проверками вашего макета, а затем вы можете вызвать его следующим образом:

 galen check loginPage.gspec --url https://example.com --size 1024x768 --include desktop --htmlreport reports

Эта команда запустит браузер, откроет указанный URL-адрес, изменит размер окна браузера до 1024 × 768 пикселей и выполнит все проверки, объявленные в файле loginPage.gspec . В результате вы получите подробный отчет в формате HTML.

Управление наборами тестов

В реальном мире реальное веб-приложение состоит не только из статических страниц. Довольно часто вам придется выполнять какие-то действия, чтобы добраться до места, которое вы хотите проверить. В этом случае Galen предлагает наборы тестов JavaScript и API-интерфейс GalenPages JavaScript для реализации объектной модели страницы. Вот простой пример JavaScript-теста Галена:

 test("Home page", function() { var driver = createDriver("https://galenframework.com", "1024x768"); checkLayout(driver, "homePage.gspec", ["desktop"]); });

А вот реализация объектной модели страницы для входа в систему, взятая из реального проекта.

 WelcomePage = $page("Welcome page", { loginButton: "#welcome-page .button-login" }); LoginPage = $page("Login page", { username: "input[name='login.username']", password: "input[name='login.password']", loginButton: "button.button-login" loginAs: loggedFunction ("Log in as ${_1.username} with password ${_1.password}", function(user) { this.username.typeText(user.username); this.password.typeText(user.password); this.loginButton.click(); }) }); test("Login page", function() { var driver = createDriver("https://testapp.galenframework.com", "1024x768"); var welcomePage = new WelcomePage(driver).waitForIt(); welcomePage.loginButton.click(); new LoginPage(driver).waitForIt(); checkLayout(driver, "loginPage.gspec", ["desktop"]); });

Для продвинутого использования советую посмотреть проект Galen Bootstrap. Это расширение JavaScript, созданное специально для Галена. Он предоставляет некоторые дополнительные функции для тестирования пользовательского интерфейса и более простой способ настройки браузеров и выполнения сложных наборов тестов.

Простой тест макета

Позвольте мне начать с простого теста макета в Galen Framework. Затем я перейду к расширенным вариантам использования и покажу, как расширить синтаксис Galen Specs. Для этого посмотрим на шапку со значком и подписью:

Значок и подпись
Значок и подпись (Посмотреть большую версию)

В HTML-коде это может выглядеть примерно так:

 <body> <!-- … --> <div> <img class="header-logo" src="/imgs/header-logo.png"/> <h1>My Blog</h1> </div> <!-- … --> </body>

Простейшая форма теста схемы Галена будет выглядеть примерно так: Во-первых, мы должны объявить объекты с помощью селекторов CSS.

 @objects header #header icon #header img caption #header h1

Затем мы объявляем тестовый раздел со значимым именем и помещаем все наши проверки под ним.

 = Icon and Caption = icon: left-of caption 10 to 15px width 32px height 32px inside header 10px top caption: aligned horizontally all header inside header

Здесь мы протестировали два элемента заголовка: значок и заголовок. Все проверки, перечисленные под элементами значка и заголовка, на самом деле являются стандартными спецификациями Galen. Эти спецификации являются фундаментальными строительными блоками, с помощью которых вы можете собрать собственное решение для тестирования компоновки. Каждая спецификация проверяет отдельное свойство (например, ширину, высоту, текст), относительное расположение (например, внутри, слева, сверху) или пиксели на снимке экрана (например, цветовую схему, изображение).

Тестирование нескольких элементов с использованием циклов forEach

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

Горизонтальное меню
Горизонтальное меню (Просмотреть увеличенную версию)

Начните с сопоставления нескольких элементов на странице. С помощью следующего кода мы указываем Галену искать элементы, соответствующие #menu ul li CSS.

 @objects menu #menu item-* ul li

Позже мы можем обращаться к этим элементам с такими именами, как menu.item-1 и menu.item-2 и перебирать все элементы меню, используя цикл @forEach .

 = Menu = menu.item-1: inside menu 0px top left bottom @forEach [menu.item-*] as menuItem, next as nextItem ${menuItem}: left-of ${nextItem} 0px aligned horizontally all ${nextItem}

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

Переосмысление тестирования макета

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

 = Menu = |first menu.item-* is in top left corner of menu |menu.item-* are aligned horizontally next to each other

На самом деле это реальный рабочий код, скопированный из моего проекта. В этих последних двух строках (начиная с вертикальной черты | ) мы вызываем пользовательские функции, которые собирают свои аргументы, анализируя эти два оператора. Конечно, приведенный выше пример не будет работать как есть. Чтобы он скомпилировался, нам нужно реализовать обработчики для этих двух операторов. Мы вернемся к этой реализации позже.

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

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

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

Как это работает

Позвольте мне объяснить механизм пользовательских выражений макета на этом простом примере:

Простой эскиз
Простой скетч (Просмотреть увеличенную версию)

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

 button: inside some_panel 0px left right

Приведенный выше код дает нам возможность объявлять произвольные поля по бокам, а также неявно проверяет, находится ли кнопка полностью внутри панели. Недостатком является то, что он не очень удобочитаем, поэтому я собираюсь поместить эту проверку за выражением button stretches to some_panel . Чтобы это работало, нам нужно написать собственное правило, подобное этому:

 @rule %{elementName} stretches to %{parentName} ${elementName}: inside ${parentName} 0px left right

Вот и все. Теперь мы можем поместить его в наш тест всего в одну строку:

 | button stretches to some_panel

Как видите, это правило принимает два аргумента: elementName и parentName . Это позволяет нам применять его и к другим элементам. Просто замените имена этих двух объектов.

 | login_panel stretches to main_container | header stretches to screen | footer stretches to screen # etc.

Внедрение собственного языка тестирования

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

 = Menu = | first menu.item-* is in top left corner of menu | menu.item-* are aligned horizontally next to each other

Мы можем реализовать первое правило следующим образом:

 @rule first %{itemPattern} is in %{cornerSides} corner of %{parentElement} @if ${count(itemPattern) > 0} ${first(itemPattern).name}: inside ${parentElement} 0px ${cornerSides}

При использовании в нашем примере он будет анализировать аргументы следующим образом:

  • itemPattern = menu.item-*
  • cornerSides = top left
  • parentElement = menu

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

  1. Найти все пункты меню.
  2. Перебрать все из них до предпоследнего элемента.
  3. Убедитесь, что элемент n расположен слева от элемента n+1 и что их верхнее и нижнее края совпадают.

Чтобы заставить его работать, нам нужно взять цикл @forEach и спецификации left-of aligned . К счастью, в Galen вы можете обратиться к предыдущему или следующему элементу в цикле. Если вы объявили ссылку на следующий элемент, он будет повторяться только до предпоследнего элемента, что нам и нужно.

 @rule %{itemPattern} are aligned horizontally next to each other @forEach [${itemPattern}] as item, next as nextItem ${item}: left-of ${nextItem} 0px aligned horizontally all ${nextItem}

Вы можете спросить: а что, если нам нужно указать отступ в нашем тесте (например, ~ 20px или 10 to 20px )? Затем я предлагаю либо реализовать отдельное правило, либо расширить существующее для поддержки аргумента %{margin} .

 @rule %{itemPattern} are aligned horizontally next to each other with %{margin} margin @forEach [${itemPattern}] as item, next as nextItem ${item}: left-of ${nextItem} ${margin} aligned horizontally all ${nextItem}

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

Кнопки формы
Кнопки формы (Просмотреть увеличенную версию)
 | menu.item-* are aligned horizontally next to each other with 0px margin | submit_button, cancel_button are aligned horizontally next to each other with 20px margin

Вы могли заметить, что в этих двух примерах мы объявили первый аргумент двумя разными способами. В первом выражении первый аргумент — “menu.item-*” , а во втором выражении он объявлен как “submit_button, cancel_button” . Это возможно, потому что цикл @forEach позволяет нам использовать список объектов, разделенных запятыми, вместе со звездочкой. Но мы еще не закончили рефакторинг. Мы могли бы улучшить код и сделать его более читабельным. Если мы создадим группы для пунктов меню и кнопок формы входа, мы могли бы сделать что-то вроде этого:

 @groups menu_items menu_item-* login_form_buttons submit_button, cancel_button = Testing login page = | &menu_items are aligned horizontally next to each other with 0px margin | &login_form_buttons are aligned horizontally next to each other with 20px margin

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

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

Динамические поля

Давайте рассмотрим еще один редкий шаблон макета, который вы можете иногда встретить на различных веб-сайтах. Что, если бы мы захотели проверить, что элементы имеют одинаковое расстояние друг от друга? Давайте попробуем реализовать другое правило для этого, но на этот раз с помощью реализации JavaScript. Предлагаю такое утверждение: “box_item-* are aligned horizontally next to each other with equal distance” . Это будет немного сложно, потому что мы не знаем отступа между элементами и не можем просто жестко запрограммировать значения пикселей. Следовательно, первое, что нам нужно сделать, — это получить фактическое расстояние между первым и последним элементами.

Одинаково далеко
Равноудалены (Просмотреть большую версию)

Как только мы получим этот запас, мы можем объявить его в цикле @forEach , аналогично тому, как мы это делали раньше. Я предлагаю реализовать это правило с помощью JavaScript API, потому что требуемая логика немного сложнее, чем во всех наших предыдущих примерах. Давайте создадим файл с именем my-rules.js и введем этот код:

 rule("%{objectPattern} are aligned horizontally next to each other with equal margin", function (objectName, parameters) { var allItems = findAll(parameters.objectPattern), distance = Math.round(Math.abs(allItems[1].left() - allItems[0].right())), expectedMargin = (distance - 1) + " to " + (distance + 1) + "px"; if (allItems.length > 0) { for (var i = 0; i < allItems.length - 1; i += 1) { var nextElementName = allItems[i + 1].name; this.addObjectSpecs(allItems[i].name, [ "aligned horizontally all " + nextElementName, "left-of " + nextElementName + " " + expectedMargin ]); } } });

В нашем тестовом коде мы будем использовать его следующим образом:

 @script my-rules.js # … = Boxes = | box_item-* are aligned horizontally next to each other with equal distance

Как видите, в Galen Framework мы можем выбирать между двумя языками при реализации правил: Galen Specs и JavaScript. Для простых выражений проще использовать Galen Specs, но для сложных я всегда выбираю JavaScript. Если вы хотите узнать больше о правилах JavaScript, обратитесь к документации.

Гален Дополнительные услуги

Наигравшись с различными паттернами компоновки, я понял, что все эти правила Галена можно легко применить в любом другом тестовом проекте. Это натолкнуло меня на мысль скомпилировать наиболее распространенные выражения макета в собственную библиотеку. Так я пришел к созданию проекта Galen Extras. Ниже приведены некоторые примеры того, на что способна эта библиотека:

 | header.icon should be squared | amount of &menu_items should be > 3 | &menu_items are aligned horizontally next to each other | &list_items are aligned vertically above each other with equal distance | every &menu_item is inside menu 0px top and has width > 50px | first &menu_item is inside menu 0px top left | &menu_items are rendered in 2 column table | &menu_items are rendered in 2 column table, with 0 to 1px vertical and 10px horizontal margin | &login_form_elements sides are vertically inside content_container with 20px margin login_panel: | located on the left side of panel and takes 70 % of its width # etc …

Библиотека Galen Extras содержит множество шаблонов макетов, которые вы обычно найдете на веб-сайтах, и я постоянно обновляю ее, как только обнаруживаю полезный шаблон. Как только эта библиотека была настроена, я решил попробовать ее на реальном тестовом проекте.

Тестирование приложения для обмена сообщениями

В настоящее время я работаю инженером-программистом в Marktplaats. В какой-то момент я решил применить весь полученный опыт в реальном проекте. Мне нужно было протестировать страницу обмена сообщениями на нашем сайте. Вот как это выглядит:

Страница обмена сообщениями
Страница обмена сообщениями (Посмотреть большую версию)

Честно говоря, реализация тестов для таких страниц всегда казалась мне немного пугающей, особенно тесты верстки. Но с библиотекой Galen Extras все прошло довольно гладко, и вскоре я смог придумать такой код:

 @import ../selected-conversation.gspec @groups (message, messages) messenger.message-* first_two_messages messenger.message-1,messenger.message-2 first_message messenger.message-1 second_message messenger.message-2 third_message messenger.message-3 (message_date_label, message_date_labels) messenger.date_label-* first_date_label messenger.date_label-1 second_date_label messenger.date_label-2 = Messages panel = = Messages and Date labels = |amount of visible &message_date_labels should be 1 |first &message_date_label has text is "17 november 2015" |amount of visible &messages should be 3 |&first_two_messages should be located at the left inside messenger with ~ 20px margin |&third_message should be located at the right inside messenger with ~ 20px margin |&messages are placed above each other with 10 to 15px margin |text of all &messages should be ["Hi there!", "I want to buy something", "Hello! Sure, it's gonna be 100 euros"] = Styling = |&first_two_messages should be styled as others message |&third_message should be styled as own message

Извлечение диапазонов пикселей

Тест выглядел нормально: он был компактным и читаемым, но все еще далек от совершенства. Мне не очень нравились все эти определения полей ( ~ 20px пикселей, 10 to 15px ). Некоторые из них повторялись, и было трудно понять, что означало каждое из них. Вот почему я решил скрыть каждое поле за значимой переменной.

 # ... @set messages_side_margin ~ 20px messages_vertical_margin 10 to 15px = Messages panel = = Messages and Date labels = |amount of visible &message_date_labels should be 1 |first &message_date_label has text is "17 november 2015" |amount of visible &messages should be 3 |&first_two_messages should be located at the left inside messenger with ${messages_side_margin} margin |&third_message should be located at the right inside messenger with ${messages_side_margin} margin |&messages are placed above each other with ${messages_vertical_margin} margin # ...

Как видите, я переместил поля на messages_vertical_margin и messages_side_margin . Я также объявил minimal поле, которое находится в диапазоне от 0 до 1 пикселя.

 # ... @set minimal 0 to 1px = Conversations Panel = | &conversations are aligned above each other with ${minimal} margin # ...

Проверка на основе изображений и пользовательские выражения

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

 @set OWN_MESSAGE_COLOR #E1E8F5 OTHERS_MESSAGE_COLOR white ERROR_MESSAGE_COLOR #FFE6E6 @rule %{item} should be styled as %{style} message ${item}: @if ${style === "own"} color-scheme > 60% ${OWN_MESSAGE_COLOR}, 0.2 to 20 % ${MAJOR_TEXT_MESSAGE_COLOR} @elseif ${style === "error"} color-scheme > 60% ${ERROR_MESSAGE_COLOR}, 0.2 to 20 % ${MAJOR_TEXT_MESSAGE_COLOR} @else color-scheme > 60% ${OTHERS_MESSAGE_COLOR}, 0.2 to 20 % ${MAJOR_TEXT_MESSAGE_COLOR}

Спецификация color-scheme проверяет пропорциональное распределение цветов внутри элемента. Он обрезает скриншот страницы и анализирует распределение цветов. Итак, чтобы проверить цвет фона элемента, мы просто проверяем, чтобы его распределение превышало 60% от общего цветового диапазона. В тесте это правило вызывается так:

 = Styling = |&first_two_messages should be styled as others message |&third_message should be styled as own message

Настройка наборов тестов

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

 // ... testOnAllDevices("Unselected 2 conversations", "/", function (driver, device) { mock.onGetMyConversationsReturn(sampleConversations); refresh(driver); new MessageAppPage(driver).waitForIt(); checkLayout(driver, "specs/tests/unselected-conversations.gspec", device.tags); }); testOnAllDevices("When clicking a conversation it should reveal messages", "/", function (driver, device) { mock.onGetMyConversationsReturn(sampleConversations); mock.onGetSingleConversationReturn(sampleMessages); refresh(driver); var page = new MessageAppPage(driver).waitForIt(); page.clickFirstConversation(); checkLayout({ driver: driver, spec: "specs/tests/three-simple-messages-test.gspec", tags: device.tags, vars: { expectedTextProvider: textProvider({ "messenger.message-1": "Hi there!\n11:02", "messenger.message-2": "I want to buy something\n12:02", "messenger.message-3": "Hello! Sure, it's gonna be 100 euros\n13:02" }) } }); }); // ...

Отлов ошибок

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

Проблема со стилем

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

Неправильный цвет фона сообщения
Неправильный цвет фона сообщения (Посмотреть большую версию)

Если вы сравните этот снимок экрана с оригиналом, вы заметите, что последнее сообщение имеет белый фон, тогда как он должен быть светло-голубым. Давайте посмотрим, как Гален сообщает об этой проблеме:

Скриншот с сообщением об ошибке
Скриншот с сообщением об ошибке (Посмотреть большую версию)

Для выделенного объекта он отображает color #e1e8f5 on “messenger.message-3” is 0% but it should be greater than 60% . Честно говоря, это сообщение об ошибке выглядит не так уж и ясно, но поскольку эта проверка была сгенерирована из пользовательского правила, мы всегда можем найти его исходное имя в ветке отчета:

Сообщить о сбое теста
Сообщить об ошибке теста (Просмотреть большую версию)

Если вы прокрутите вверх, вы увидите, что исходное утверждение &third_message should be styled as own message . Это еще одно преимущество использования пользовательских выражений: они помогают понять причину сбоя и хорошо описывают все сгенерированные проверки.

Проблема позиционирования

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

Неверное положение сообщения
Неверная позиция сообщения (Посмотреть большую версию)

Давайте еще раз посмотрим на скриншот с сообщением об ошибке:

Неверное положение сообщения
Неверная позиция сообщения (Посмотреть большую версию)

На снимке экрана выделены контейнер сообщений и последний элемент сообщения. Вместе с этим он показывает следующее сообщение об ошибке: “messenger.message-3” is 285px right which is not in range of 22 to 28px . Веб-разработчику может быть непонятно, почему с правой стороны ожидается поле от 22 до 28 пикселей. Опять же, вам придется искать оператор проверки в ветке отчета:

Неверное положение сообщения
Неверная позиция сообщения (Посмотреть большую версию)

Исходное утверждение для этой проверки: &third_message should be located at the right inside messenger with ~ 25px margin . Это имеет гораздо больше смысла. Более того, другие фронтенд-инженеры поймут этот отчет о тестировании, даже если они не писали тесты.

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

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

  • Выявление шаблонов компоновки в дизайне.
  • Обобщить операторы проверки. Постарайтесь сжать большинство утверждений в отдельные предложения.
  • Компонентизируй! Всегда лучше перенести тесты повторяющихся элементов в отдельные компоненты.
  • Используйте осмысленные имена для разделов, правил и объектов.
  • Избегайте пикселей. Попробуйте заменить значения пикселей (будь то точные значения или диапазоны) значимыми переменными.
  • Измените код своего веб-сайта, чтобы его было легче тестировать. Это поможет вам структурировать и поддерживать как производственный, так и тестовый код.

Критерии приемки на помощь

Часто я получаю вопросы вроде: «Итак, насколько подробным должен быть тест макета? И что мы должны тестировать конкретно?» Общий ответ дать сложно. Проблема в том, что когда покрытие тестом небольшое, вы пропускаете ошибки. С другой стороны, если у вас слишком подробные тесты, вы можете получить много ложных срабатываний, и в будущем вы можете потеряться в обслуживании тестов. Итак, есть компромисс. Но общий принцип я для себя вывел. Если вы разделите работу на более мелкие пользовательские истории, вам будет проще структурировать дизайн страницы в виде критериев приемки. В конце концов, вы можете поместить этот самый критерий приемлемости прямо в свой тестовый код. Например, некоторые из этих операторов могут быть определены в виде пользовательских правил, как показано во всех предыдущих примерах кода. Хорошим примером критериев приемки может быть что-то вроде этого:

  • Всплывающие окна должны располагаться по центру экрана по вертикали и горизонтали.
  • Они должны быть шириной 400 пикселей.
  • Кнопки должны быть выровнены по горизонтали.
  • И так далее

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

Заключение

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

Ресурсы

  • Galen Framework (официальный сайт)
  • Гален Фреймворк, GitHub
  • Galen Extras (библиотека), GitHub
  • Гален Bootstrap, GitHub
  • «Учебники по Galen Framework», YouTube