Тестируем CSS в Selenium IDE

1ab002dd8d8ebd151e66cc7c1025b4e0

Я все больше в своей практике пытаюсь использовать автоматизированное тестирование. Стараюсь при этом не плодить инструменты и библиотеки, обходиться простыми подходами. Не так давно, я задумался о том, как протестировать CSS-файлы. Поиск по Интернету выявил следующие точки зрения на этот вопрос:

  1. Тестирование CSS не имеет смысла, так как это декларативный язык, а его результатом является сверстанное изображение страницы, которое можно оценить лишь визуально.
  2. Протестировать CSS можно с помощью снятия битмапов с сгенерированной страницы и сверка ее с эталонным изображением. Для этого даже есть некоторые инструменты.
  3. Нашлась некоторая библиотека CSS-Unit.

Должен сказать, что все варианты мне не понравились. В конечном итоге мне удалось протестировать CSS используя текстовый редактор, Firefox + Selenium IDE и… и больше ничего.

Немного теории

Наиболее конструктивные идеи мне принесла длительная медитация над вкладкой Firebag «Cкомпилированный стиль».

584c1c6ea92d15f764d0e7015a86da50

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

  1. Определение всех параметров всех элементов, на основе CSS
  2. Верстка страницы, на основе полученных значений

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

Все, что нам нужно – это получить доступ к значениям, показывающимся в закладке Firebag «Cкомпилированный стиль». Недолгое рыскание по Интернету привело к обнаружению функции:

var style = window.getComputedStyle(element[, pseudoElt]);

 

Название, говорит само за себя. Единственное, что можно пояснить – это второй параметр. Он может быть полезен, если мы захотим, например, узнать, какого цвета будет ссылка, если на нее наведут курсор. Осталось только вспомнить, что в Selenium IDE есть замечательное семейство функций xxxEval, которые могут вычислить любое JavaScript выражение. Теперь можно опробовать все это на практике.

Немного практики

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

project – корень проекта 
project/css – место для css 
project/tests – место для тестовой инфраструктуры 
project/tests/html-examples – место для тестовых примеров html-кода 
project/tests/selenium-tests – место для Selenium-тестов

 

Отдаем папку project под управление нашему любимому http-серверу, и настраиваем к нему доступ по адресуhttp://project.localhost.

В корне, по давно сложившейся привычке, заводим файл index.html, который делает наш проект похожим на реальный, а также символизирует исходный код проекта, безжалостно изменямый программистами независимо от нашей воли и желания. Одновременно заводим файл styles.css, который содержит css-код который мы будем разрабатывать и тестировать.

Предположим, в нашем проекте нам нужно выводить уведомляющие сообщения. Они должны выводится зеленым шрифтом. Сообщение состоит из заголовка <h1> и основного текста <p>. Шрифт заголовка 20px, основного текста 14px. Для размещения сообщений программисты зарезервировали контейнер <div>. В соответствии с этой ситуацией наши файлы index.html и styles.css на момент начала тестирования имеют следующий вид:

http://project.localhost/index.html 

<html>
<head> 
<link rel="stylesheet" type="text/css" href="/css/styles.css"> 
</head> 
<body>  
    <h1>Super project</h1>
    <p>It's really very big and complex project !</p> 
    <div class="notify-message"> 
       <h1>Hi,Guest</h1>
        <p>Welcome to our beautiful world!</p> 
    </div> 
</body> 
</html>

 

http://project.localhost/css/styles.css 

div.notify-message h1 { 
  color:green; 
  font-size: 20px; 
} 

div.notify-message p { 
  color:green; 
  font-size: 14px; 
}

 

Нам нужно протестировать styles.css. Велик соблазн написать тест сразу с использованием index.html. Но мы помним, что он может меняться (а может и вообще исчезнуть при очередной смене тим-лидера). Поэтому воспроизводим требуемую ситуацию в файле notify-message-example.html

http://project.localhost/tests/html-examples/notify-message-example.html 

<html>
  <head>
    <link rel="stylesheet" type="text/css" href="/css/styles.css">
  </head>
  <body>
    <div class="notify-message">
       <h1 id="h1-test">Notify message</h1>
       <p id="p-test">It's notify message</p>
     </div>
  </body>
</html>

 

Для целевых объектов мы назначили id, чтобы быстрее их отыскать в DOM-структуре. Постфикс -test призван обозначить, что id предназначен лишь для целей тестирования. Открываем наш любимый Firefox с Selenium IDE и вводим следующий тест (исходники тестов, которые Selenium IDE сохраняет в HTML-формате, приводятся без тегов, чтобы улучшить читаемость):

http://project.localhost/tests/selenium-tests/notify-message-test.html

open
   /tests/html-examples/notify-message-example.html
verifyEval
  window.getComputedStyle(window.document.getElementById('h1-test'),null).getPropertyValue('color');
  green
verifyEval
  window.getComputedStyle(window.document.getElementById('p-test'),null).getPropertyValue('color');
  green
verifyEval
  window.getComputedStyle(window.document.getElementById('h1-test'),null).getPropertyValue('font-size');
  20px
verifyEval
  window.getComputedStyle(window.document.getElementById('p-test'),null).getPropertyValue('font-size');
  14px

 

Запускаем

648aea390033ea44f15d632fce8c9994
[error] Actual value 'rgb(0, 128, 0)' did not match 'green'
[error] Actual value 'rgb(0, 128, 0)' did not match 'green

Оказывается getComputedStyle() возвращает цвета в виде rgb(r,g,b). Наверное, это правильно. В тестах не будет путаницы, если верстальщик будет использовать разные обозначения для одного и того же цвета. Корректируем тест.

http://project.localhost/tests/selenium-tests/notify-message-test.html v2

open
   /tests/html-examples/notify-message-example.html
verifyEval
  window.getComputedStyle(window.document.getElementById('h1-test'),null).getPropertyValue('color');
  rgb(0, 128, 0)
verifyEval
  window.getComputedStyle(window.document.getElementById('p-test'),null).getPropertyValue('color');
  rgb(0, 128, 0)
verifyEval
  window.getComputedStyle(window.document.getElementById('h1-test'),null).getPropertyValue('font-size');
  20px
verifyEval
  window.getComputedStyle(window.document.getElementById('p-test'),null).getPropertyValue('font-size');
  14px

 

0228d78e65a647549d436ce6ca235008

Включаем режим паранойи

Естественно, к этому тесту наиболее въедливые тестировщики найдут что добавить. В частности, можно сделать проверку, что наши стили не затрагивают чистых <h1> и <p>.

http://project.localhost/tests/html-examples/clear-example.html 

<html>
  <head>
    <link rel="stylesheet" type="text/css" href="/css/styles.css">
  </head>
  <body>
    <h1 id="h1-test">Not message</h1>
    <p id="p-test">It is not message</p>
  </body>
</html>

 

http://project.localhost/tests/selenium-tests/clear-test.html 

open
  /tests/html-examples/clear-example.html
verifyEval
  window.getComputedStyle(window.document.getElementById('h1-test'),null).getPropertyValue('color');
  rgb(0, 0, 0)
verifyEval
  window.getComputedStyle(window.document.getElementById('p-test'),null).getPropertyValue('color');
  rgb(0, 0, 0)
verifyEval
  window.getComputedStyle(window.document.getElementById('h1-test'),null).getPropertyValue('font-size');
  32px
verifyEval
  window.getComputedStyle(window.document.getElementById('p-test'),null).getPropertyValue('font-size');
  16px

 

Запускаем.

ac582a16ce589877ce666bc310fa68f8

Будьте внимательны – тесты могут не пройти, в зависимости от настроек браузера, но ведь на то оно и тестирование.

Делаем рефакторинг

Тесты написаны, что дальше? Дальше – все преимущества разработки с применением автоматизированного тестирования. Например, рефакторинг. Посмотрев на наш CSS файл, мы видим, что две строчки, касающиеся зеленого цвета повторяются. Попробуем это исправить. Пусть мы не совсем уверены в знании правил CSS, которые запомнить еще труднее, чем понять. Теперь нас это не остановит. Ведь наш код под защитой тестов.

http://project.localhost/css/styles.css v2

div.notify-message h1{
  color:green;
}

div.notify-message h1 {
  font-size: 20px;
}

div.notify-message p {
  font-size: 14px;
}

 

3fb95eb2e9b95768d43ecfde678643a0

[error] Actual value 'rgb(0, 0, 0)' did not match 'rgb(0, 128, 0)'

 

Ах, да!!! Забыли при копировании подправить селектор.

div.notify-message h1 {
color:green;
}

 

068fd742ae930b072b95bdf6da0b576c

Тест пройден.

Разработка CSS в стиле TDD

Теперь мы можем полностью применять концепции Test Driven Development. Предположим, что поздно вечером (как обычно, перед деадлайном) к web-верстальщику приходит web-программист и начинает что-то невнятно бормотать и делать руками неопределенные жесты. (Прошу программистов не обижаться – это камень и в мой огород, так как мне приходится быть и тем и тем). Из спутанного рассказа становится ясно, что нужно еще и выводить сообщения об ошибке, которые должны быть красного цвета. При просмотре файлов проекта оказывается, что теперь файл index.html имеет следующий, никем не предугаданный, вид:

http://project.localhost/index.html v2

<html>
  <head>
    <link rel="stylesheet" type="text/css" href="/css/styles.css">
  </head>
  <body>
    <h1>Super project</h1>
    <p>It's really very big and complex project !</p>
    <div class="notify-message">
       <h1>Hi,Guest !</h1>
       <p>Welcome to our beautiful word!</p>
     </div>
    <div class="error-message">
       <h1>You are not authorized.</h1>
       <p>Please login or register now.</p>
     </div>
  </body>
</html>

 

Оторвавшись от просмотра телесериала “Бэтмен навсегда”, засучив рукава, сохраняя по возможности хладнокровие, в соответствии с концепцией «сначала тесты», web–верстальщик создает файл:

http://project.localhost/tests/html-examples/error-message-example.html

<html>
  <head>
    <link rel="stylesheet" type="text/css" href="/css/styles.css">
  </head>
  <body>
    <div class="error-message">
       <h1 id="h1-test">Error message</h1>
       <p id="p-test">It's error message</p>
     </div>
  </body>
</html>

 

И добавляет в Selenium IDE еще один тест:

http://project.localhost/tests/selenium-tests/error-message-test.html

open
  /tests/html-examples/error-message-example.html
verifyEval
  window.getComputedStyle(window.document.getElementById('h1-test'),null).getPropertyValue('color');
  rgb(255, 0, 0)
verifyEval
  window.getComputedStyle(window.document.getElementById('p-test'),null).getPropertyValue('color');
  rgb(255, 0, 0)
verifyEval
  window.getComputedStyle(window.document.getElementById('h1-test'),null).getPropertyValue('font-size');
  32px
verifyEval
  window.getComputedStyle(window.document.getElementById('p-test'),null).getPropertyValue('font-size');
  16px

 

7858dc67c9a134a023f9cc9a0c1084cb
[error] Actual value 'rgb(0, 0, 0)' did not match 'rgb(255, 0, 0)'
[error] Actual value 'rgb(0, 0, 0)' did not match 'rgb(255, 0, 0)'
[error] Actual value '32px' did not match '20px'
[error] Actual value '16px' did not match '14px'

В соответствии с классикой TDD тест не проходит. Дорабатываем CSS.

http://project.localhost/css/styles.css v3

div.error-message {
  color:red;
}

div.notify-message {
  color:green;
}

div.notify-message h1, 
div.error-message h1  {
  font-size: 20px;
}

div.notify-message p, 
div.error-message p {
  font-size: 14px;
}

 

f76221c38f6256750d4d8fe86bf0dc9f

Тесты пройдены.

Развитие без препятствий

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

В заключение приведу девиз TDD-разработчиков, который мне очень нравится:

9efc513c9f2c162262f4eb3de948c8e3

Желаю Вам успешных проектов, красивых CSS-файлов и спокойного сна по ночам.