Друзья, сегодня я расскажу вам историю о том, как просто и изящно решить проблему еnd-to-еnd тестирования web-сервиса доставки кофе с помощью нового open source тестового фреймворка. Мы проведем проверку не только работы сайта, но и менеджеров и даже службы доставки, к тому же потратим на это минимум усилий и времени. А в качестве бонуса за приложенные усилия получим кружечку горячего кофе прямо в руки. Всех любителей приключений прошу под кат…
На сегодняшний день необходимость e2e web-тестирования уже ни для кого не новость. Вопрос о выборе сервиса для тестирования рано или поздно встает ребром для любого web-приложения. Широкой публике известны различные Selenium-производные решения, подавляющее большинство которых построено на использовании WebDriver. Мы же собираемся продемонстрировать работу с новым open source тестовым фреймворком TestCafe, построенным на совершенно ином принципе. Перейдем же, наконец, от разговоров к делу.
Установка TestCafe
Как всегда начинается все с установки продукта. Это конечно совсем скучно, но я вас обрадую, полная установка TestCafe выполняется всего одной командой консоли.
npm install -g testcafe
Если вам приходилось устанавливать Selenium или базирующиеся на нем фреймворки, то вы приятно удивитесь насколько просто и быстро это делать c TestCafe. Как вы могли заметить, TestCafe построен на Node.js, а это значит — никаких Java, никаких плагинов для браузера или привязок к операционной системе. Все, что вам необходимо, это иметь Node.js на своем компьютере.
Теперь создадим файл, в котором будет находиться наш тест, назовем его get-a-cup-of-coffee.js. В файле создадим fixture — набор тестов, укажем адрес страницы и создадим пустой тест.
fixture `Let's take a look at the new TestCafe`
.page `http://www.pitcofe.ru/`;
test(`Get a cup of coffee`, async t => {
// TODO: test
});
Одной из приятных особенностей TestCafe фреймворка является то, что в тесте вы можете использовать ES6 и ES7 синтаксис, независимо от того, поддерживает ли его браузер или ваша версия Node.js. TestСafe, с помощью Babel, транслирует весь код в синтаксис ES5.
Написание теста
Выполнение действий с элементами страницы
Приступим к написанию теста. Перейдем в раздел доставки горячего кофе. Все предельно просто — нажимаем на пункт "Меню" и выбираем пункт "Кофе".
test(`Get a cup of coffee`, async t => {
await t
.click(Selector('#nav').find('a').withText('меню'))
.click(Selector('#content').find('#smenu-150'));
});
Обратите внимание, во время теста произойдет несколько переходов на новые страницы. Но, как вы убедитесь сами, нигде в тесте мы не будем указывать в какой момент и как долго необходимо ожидать загрузку страницы, отправку формы или ответа на XHR запрос. TestCafe берет все эти обязанности на себя, вам больше не нужно беспокоиться об этом.
Для указания элементов, с которыми необходимо провести действия, мы воспользовались селекторами. Селекторы в TestCafe позволяют проделывать всю работу, связанную с DOM элементами. Для этого необходимо указать способ получения элемента на клиенте, например, css — селектор или функцию. А также TestCafe предоставляет API для создания составных селекторов, которые позволяют находить элемент по расположению в иерархии страницы или по заданным фильтрам (текст, индекс и любые кастомные фильтры).
После того как мы перешли в необходимое нам меню, добавим в корзину чашечку "классического Латте":
await t.click(Selector('.title').withText('Латте классический').sibling('.labels'));
Проверка состояния элементов страницы
Теперь нам необходимо убедиться, что товар добавлен в корзину. Перейдем на соответствующую страницу:
await t.click('.myShop-cartmini');
Для проверки используем предоставляемые TestCafe встроенные assertion-ы. А чтобы получить значение интересующего нас свойства элемента страницы снова воспользуемся селекторами. Селекторы содержат набор асинхронных свойств и методов, которые можно непосредственно исполнить в тесте или передать в assertion. Во втором случае assertion-ы активируют механизм ожидания. Ведь очень часто необходимо дождаться завершения анимации, или получения ответа на XHR запрос прежде, чем выполнять assertion.
Все существующие библиотеки assertion-ов подразумевают использование искусственных задержек, что сильно увеличивает время прохождения тестов и делает их нестабильными. TestCafe же заботится об этом сам. Если при использовании свойства и метода селектора проверка не проходит, тест не падает мгновенно. Assertion-ы вычисляется несколько раз, на каждой итерации получая актуальное значение и падает только в том случае, если достигнут таймаут и проверка так и не выполнилась успешно. Такой подход позволяет писать стабильные, быстрые и надежные тесты, не задумываясь о времени отклика тестируемой страницы.
Проверим число и наименование товаров в корзине.
const items = Selector('.myShop-cart-item');
await t
.expect(items.count).eql(2)
.expect(items.nth(0).innerText).contains('Латте классический')
.expect(items.nth(1).innerText).contains('Доставка');
Выполнение кода на клиенте
Мы также можем воспользоваться клиентской функцией для получения количества товаров в корзине. Исполняться такая функция будет на клиенте, а результат вернет на сервер. Внутри клиентской функции может быть использован любой js код, как если бы вы просто добавили его на страницу.
const getOderCount = ClientFunction(() => document.querySelectorAll('.myShop-cart-item').length);
let orderCount = await getOderCount();
Существует также способ немедленного исполнения кода на клиенте — использование метода t.eval.
orderCount = await t.eval(() => document.querySelectorAll('.myShop-cart-item').length);
Проверим, что полученные данные соответствуют нашим ожиданиям.
await t.expect(orderCount).eql(2);
Завершение и оформление заказа
Вернемся в меню выбора кофе и добавим в корзину чашечку “Флэт Уайт Попкорн”:
await t
.click('.myShop-cartmini')
.click(Selector('#content').find('#smenu-150'))
.click(Selector('.title').withText('Флэт уайт попкорн').sibling('.labels'));
Снова перейдем в корзину и проверим, что число и наименование товаров изменилось.
await t
.click('.myShop-cartmini')
.expect(Selector('.myShop-cart-item').count).eql(3)
.expect(Selector('.myShop-cart-item').nth(0).innerText).contains('Латте классический')
.expect(Selector('.myShop-cart-item').nth(1).innerText).contains('Флэт уайт попкорн')
.expect(Selector('.myShop-cart-item').nth(2).innerText).contains('Доставка');
Теперь завершим оформление заказа — перейдем на страницу заполнения контактных данных и адреса доставки. Заполнив необходимые поля останется только нажать кнопку "Отправить".
await t
.click('.myShop-button-order')
.typeText('#ffio', 'Ваше Имя')
.typeText('#ftel', '+79999999999')
.click('#fgorod')
.click(Selector('#fgorod > option').withText('Ростов-на-Дону'))
.typeText('#fulica', 'Ленина')
.typeText('#fdom', '1')
.click('input[type="submit"]');
Тест готов. В коде нет ничего лишнего, он содержит только список производимых действий и работу с элементами страницы, при этом остается понятным для чтения и сопровождения.
Запуск теста
Запустим тест следующей командой консоли:
testcafe chrome get-a-cup-of-coffee.js
TestCafe найдет установленный на машине браузер, сам запустит его и выполнит тест.
В консоль будет выдана подробная информация о результатах прохождения теста.
Тест упал из-за ошибки на сайте. В случае падения теста TestCafe предоставляет callsite и callstack, а, при указании соответствующей опции, еще и ссылку на скриншот, сделанный при падении. Таким образом благодаря TestCafe мы смогли найти ошибку написав всего один несложный тест. Обнаружив ошибку мы сообщили об этом владельцам сайта и посоветовали использовать TestCafe для тестирования, чтобы избежать появления ошибок в дальнейшем :).
Запустим выполнение теста без падения на ошибках страницы следующей командой консоли:
testcafe chrome get-a-cup-of-coffee.js --skip-js-errors
Отчеты о прохождении тестов могут быть представлены в различных форматах, для этого существуют набор соответствующих плагинов. Они позволяют настроить работу с основными системами непрерывной интеграции. Вы можете запускать тесты не только на локальных, но и на удаленных и облачных устройствах (например Sauce Labs). Для окончательной автоматизации нашего сервиса нам осталось интегрировать полученный результат в систему непрерывной интеграции. Кто знает, возможно в будущем нам захочется добавить проверку температуры кофе, времени его доставки или даже его вкуса. Про автоматизации и интеграцию этого процесса мы, пожалуй, напишем отдельную статью :).
Выводы
Как видите, мы добились первоначальной цели: одной командой мы заказали себе кофе прямо в офис и подтвердили эффективность работы сервиса. Конечно это шутливый пример, мы взяли компанию, которая осуществляет доставку кофе всего в четырех городах. Но вы можете написать простенький тест для любого подобного сервиса, находящегося у вас под боком.
Готовый пример можно найти здесь. Мы использовали методологию PageObject, которая позволяет сделать код теста более читаемым и понятным.
Надеюсь после прочтения вы заглянете к нам в TestCafe на чашечку кофе. Обсудить все интересующие вопросы можно в комментариях или на discuss. Кофейного вам дня!
Автор: elena_dikareva