Веб-панель HootSuite довольно тяжелая. У нас есть большая кодовая база JavaScript, и большая ее часть была написана с использованием jQuery, причем большая часть кода так или иначе связана с DOM. Из-за связи кода с DOM модульное тестирование немного усложняется, поскольку для тестов должны быть предоставлены HTML-фикстуры. Это не невозможно, но немного больше работы, и опыт показывает, что разработчики чаще пишут тесты, когда это удобно. Мы решили использовать [CasperJS](http://casperjs.org/), чтобы заполнить пробелы в покрытии модульными тестами.

Я не буду описывать основы CasperJS, так как [документация] (http://docs.casperjs.org/en/latest/modules/index.html) довольно хороша; Я сразу перейду к нескольким ключевым вещам, которые помогают нам использовать CasperJS для тестирования.

#### Подпрограммы

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

var routine = {};
// define a routine function for login
routine.login = function(email, pass) {
casper.open(url);
casper.waitUntilVisible('form#loginForm', function() {
this.fill('form#loginForm', {
'loginInfo[email]': email,
'loginInfo[password]': pass
}, true);
});
casper.waitForSelector('#dashboard', function() {
this.echo('Logged in', 'COMMENT');
});
};

// then inside my test
casper.then(function() {
routine.login('[email protected]', 'secretpassword');
});
casper.then(function() {
// continue with test
});

#### Срывать

Бывают случаи, когда нам нужно выполнить некоторую очистку после запуска теста, особенно после выполнения определенных процедур. Например, у нас есть подпрограмма, которая добавляет социальную сеть Twitter в учетную запись HootSuite, но после теста мы хотим удалить добавленную социальную сеть, чтобы ее можно было добавить снова для другого теста.

У нас есть массив для хранения «шагов» разборки, которые мы должны выполнить, и мы добавляем шаги после выполнения определенных процедур.

var teardownSteps = [];

routine.addTwitterSocialNetwork = function(username, password) {
// add the social network...

// add a function to the teardown
teardownSteps.push(function() {
routine.removeSocialNetwork(username);
});
};

Функция, обрабатывающая этапы демонтажа, выглядит примерно так.

var doTeardown = function() {
var count = 1,
max = teardownSteps.length;
var fnDoStep = function() {
if (!teardownSteps.length) {
return;
}

var fnToRun = teardownSteps.shift();
casper.then(function() {
this.echo('Do teardown step '+count+' of '+max, 'COMMENT');
count++;
fnToRun.call(casper, null);
});

casper.then(function() {
fnDoStep();
});
};

// do the teardown steps in reverse order
// this is done so that we "undo" our test steps
teardownSteps.reverse();
fnDoStep();
};

Затем мы вызываем функцию doTeardown() по завершении тестов или при возникновении ошибки.

casper.test.on('fail', function() {
doTeardown();
});

**Примечание**: это было сделано до выпуска CasperJS 1.1, который теперь включает встроенный метод разрыва с помощью [begin()](http://docs.casperjs.org/en/latest/modules/tester.html #начинать). Мы перемещаем некоторые из наших тестов, чтобы использовать этот метод.

#### Скриншот при сбое/ошибке

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

casper.test.on('fail', function() {
casper.capture('screenshots/fail.png');
});

Хотя наша текущая установка функционального тестирования работает хорошо, есть несколько проблем, которые мы хотим решить. Они не имеют ничего общего с CasperJS, но я считаю, что о них стоит упомянуть.

#### Тестовое покрытие

Модульные тесты имеют покрытие кода, которое может показать, сколько строк кода было выполнено и протестировано. Поскольку в функциональном тестировании ничего подобного нет, обычно трудно оценить, какие области кода были охвачены тестами. Обычно это можно смягчить, правильно назвав тесты, но я рассматривал возможность использования комментариев [JSDoc](http://usejsdoc.org/) для создания списка пользовательских историй, которые были протестированы. Мы уже используем JSDoc для создания документации для нашего проекта, так что это может быть легко добавить при написании наших тестов.

#### Запуск тестов от разных авторов

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

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

— — — — — — — — -

Javascript профессиональный? Заинтересованы в создании потрясающих продуктов с помощью звездной команды? Подать заявку здесь!