
Для начала скажу что phantomjs – это совсем не библиотека для юнит-тестов, как вы могли подумать; phantomjs – это возможность работать с WebKit из консоли используя JavaScript и без браузера.
Интересно? Тогда идем под кат.
Сначала проверим как работает phantomjs.
Для установки скачиваем программу с официального сайта. Стоит отметить что есть версии для Windows, Mac и Linux. Я буду описывать вариант для Linux, для которого можно запускать приложение(начиная с версии 1.5) из консоли. В скачанном архиве оказалось всего 2 папки – исполняемый файл и примеры.
В “быстром старте” нам предлагают создать hello.js со следующим содержанием
console.log('Hello, world!');
phantom.exit();
и выполнить его:
phantomjs hello.js
Очень важно в конце выполнения вызывать phantom.exit();
Попробуем разобрать более сложные пример с загрузкой страницы и получением ее скриншота:
var page = require('webpage').create();
page.open('http://google.com', function () {
page.render('google.png');
phantom.exit();
});
После чего в текущей директории должен появится файл google.png, в котором будет снимок сайта.
Далее рассмотрим скрипт для определения времени загрузки страницы:
var page = require('webpage').create(),
t, address;
if (phantom.args.length === 0) {
console.log('Usage: loadspeed.js <some URL>');
phantom.exit();
}
t = Date.now();
address = phantom.args[0];
page.open(address, function (status) {
if (status !== 'success') {
console.log('FAIL to load the address');
} else {
t = Date.now() - t;
console.log('Loading time ' + t + ' msec');
}
phantom.exit();
});
Кстати в официальной документации в этом скрипте ошибка: зачем-то в if блоке стоит return. Чтобы запустить скрипт вторым параметром(после имени скрипта) ставим адрес сайта, который хотим проверить (обязательно с http://)
По умолчанию JavaScript код страницы, которую мы загружаем не выполняется, но мы это можем сделать в режиме песочницы через метод evaluate:
var page = require('webpage').create();
url = phantom.args[0];
page.onConsoleMessage = function (msg) {
console.log(msg);
};
page.open(url, function (status) {
var title = page.evaluate(function () {
//return document.title;
console.log(some_variable);
});
phantom.exit();
});
Также мы можем просматривать запрашиваемые/получаемые страницей ресурсы задав callback методы onResourceRequested и onResourceReceived:
page.onResourceRequested = function (request) {
console.log('Request ' + request.contentType + ' ' + request.url);
};
page.onResourceReceived = function (response) {
console.log('Receive ' + response.contentType + ' ' + response.url);
};
Request и responce – json объекты, в которые хранятся данные о запросе и ответе.
С основами phantomjs разобрались, теперь определим, как он нам может помочь в написании тестов.
Есть 2 подхода: основной и тот, который мы только что придумали для решения своей частной задачи. Основной заключается в том, чтобы запустить на выполнение юнит тест страничку в phantomjs, а потом считать с результирующей таблички данные и как-то их обработать. Этот подход хорошо разобран тут, тут и тут оф пример. Поэтому на нем не останавливаемся, а переходим к нашему изощренному: мы хотим проверить правильно ли были применены стили и изменения структуры к документу. Для этого мы делаем снимок экрана эталонного варианта, потом применяем стили к базовой страничке, опять делаем снимок и сравниваем полученные скрины.
Логика на стороне phantomjs выглядит следующим образом:
//массив тестов
var tests = [ "test1", "test2", "test3", "test4", "test5"];
var pages = [];
// в цикле по ним проходим
for(var i in tests ){
// получаем ссылку на тест
var url = host + '#!runtest/' + tests[i];
page = require('webpage').create()
pages.push(page);
// открываем-выполняем страницу теста
pages[i].open(url,
(function(testName, page){
return function(){
setTimeout(function(){
// по таймауту ренедерим страницу в png-base64
// и сравниваем с эталонным значением
equal(page[i].renderBase64('PNG'), expected[testName], testName + " - OK");
}, 2000);
};
})(tests[i], pages[i])
);
}
попрошу обратить внимание так как мы используем цикл с внесением значений в callback-метод нам необходимо создать дополнительное замыкание для сохранения значений:
(function(testName, page){
Посмотрим как система покажет себя в бою…