Статьи

Phantom JS: альтернатива селену

PhantomJS — это безголовый браузер, основанный на встроенном веб-комплекте, который подходит для тестирования веб-приложений, использующих JavaScript, когда более простые инструменты его не обрезают
За этим инструментом стоят некоторые люди из Sencha (создатели Ext JS), и мой коллега недавно рассказал мне об этом. У нас были некоторые проблемы с использованием jsTestDriver, потому что он сфокусирован на модульных тестах, в то время как здесь нам потребовалось лишь некоторое пошаговое руководство для пользовательского интерфейса (сквозное тестирование): бизнес-логика тестируется в другом месте.

Он также скомпилировал его заранее, поэтому в этой статье я снова прохожу процесс установки самостоятельно. Не позволяйте слову compile пугать вас: в Linux это всего лишь пара строк без вторжения в вашу папку / usr.

Характеристики

Api Условного JS основан на JavaScript : как бы вы выполнить код в браузере? Код JavaScript веб-сайтов находится в « песочнице» , поэтому он не взаимодействует с основным инструментом. Ничего не отображается на экране, поскольку использование основано на командной строке.

Phantom JS — это настоящий браузер, поддерживающий манипуляции с DOM, Ajax-вызовы , элементы Canvas и многое другое; он может загружать целые HTML-страницы для сквозного тестирования, и только Selenium сравнивает его по функциональности.

Установка

Мне нужно было загрузить через apt около 50 МБ библиотек QT, но процесс компиляции проходит гладко. Существуют также двоичные файлы для систем Windows.

В Ubuntu вам нужны четыре команды:

sudo apt-get install libqt4-dev libqtwebkit-dev qt4-qmake
git clone git://github.com/ariya/phantomjs.git && cd phantomjs
git checkout 1.2
qmake-qt4 && make

После этого вы можете вырезать двоичный файл phantomjs из папки bin / в извлеченном хранилище и вставить его в любое место .

Сценарии

Тесты написаны как процедурные сценарии на JavaScript (или CoffeeScript, если хотите). Нет общих ресурсов между средой Phantom и оконной средой, в которую загружается код веб-приложений.

Давайте посмотрим на пример из документации, где мы читаем кучу твитов.

Прежде всего, создайте новый объект WebPage, который будет нашим фасадом для окна браузера.

var page = new WebPage();

console.log (), выполняемый в области действия Phantom, будет выводить на стандартный вывод. Вместо этого console.log (), выполняемая в среде браузера, будет просто записывать в свою консоль, которая не отображается. Это событие перенаправляет любой console.log (), выполненный в оконной среде, на метод console.log в Phantom, так что любой журнал в скрипте печатается.

page.onConsoleMessage = function(msg) {
    console.log(msg);
};

Метод page.open принимает URL-адрес для загрузки, а функция для выполнения — загрузка завершена. Обычно вы заинтересованы только в том, чтобы достичь успеха.

page.open("http://mobile.twitter.com/giorgiosironi", function (status) {
    if (status !== "success") {
        console.log("Unable to access network");
    } else {

page.evaluate выполняет закрытие в среде браузера. Важно понимать, что две области :

  • Фантом, содержащий объект страницы;
  • окно , содержащее код JavaScript, загруженный страницей;

полностью отключены и могут общаться только через page.evaluate (который может возвращать скалярные значения) и через page.onConsoleMessage, описанный ранее.

Сначала это может сбивать с толку, но вы можете думать, что page.evaluate () выполняет callback.toSource () и отправляет результат на загруженную страницу по сети.

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

        page.evaluate(function() {
            var list = document.querySelectorAll('span.status');
            for (var i = 0; i < list.length; ++i) {
                console.log((i + 1) + ": " + list[i].innerHTML.replace(/<.*?>/g, ''));
            }
        });
    }

Когда вызывается phantom.exit, выполнение останавливается, и элемент управления возвращается в терминал, где он был выполнен.

    phantom.exit();
});

Использование очень просто:

[13:17:45][giorgio@Desmond:~]$ phantomjs example.js
1: @felhobacsi I'am checking *everything*, actually I'm installing a VM just to play with it 🙂
2: @AnthonySterling it makes even more sense given the new type hint wiki.php.net/rfc/callable
...

Это были мои последние твиты при написании этой статьи. У нас простой

for i in $(find . -name '*.js'); do phantomjs $i; done;

запустить все наши скрипты самостоятельно.

В качестве инструмента тестирования

PhantomJS не отправляет утверждения, и вы не должны выбрасывать исключения из области окна, поскольку они, вероятно, будут проглочены браузером или платформой JavaScript. Мы регистрируем ошибки, выводя . или F с console.log при каждом утверждении. Эти методы утверждения не находятся на реальной веб-странице, но загружаются из файловой системы с помощью:

page.injectJs('filename.js')

или через тег <script>, который является самым простым решением.

Перенаправление console.log также можно использовать для завершения: в обработчике для page.onConsoleMessage вы можете вызвать phantom.exit в случае, если сообщение является специальным ключевым словом, например, «END_OF_TEST» .

Перенаправления и Ajax

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

page.onLoadFinished = function (status) { ... };

который будет работать для перенаправлений на стороне клиента или сервера.

Чтобы узнать, были ли Ajax-запросы завершены, вам придется полагаться на свою инфраструктуру JavaScript и на ее события (если вы не хотите просто ждать 2 секунды с setInterval или setTimeout). Для Ext JS обработчик может быть определен в области видимости окна:

Ext.Ajax.on('requestcomplete', function() { ... });

Вывод

Phantom JS является многообещающим, и кажется, что сквозное тестирование может быть эффективно выполнено: мы даже заставляем его компилировать форму и входить в систему перед каждым тестом и следовать перенаправлению; это как настоящий браузер.

Этот инструмент также принципиально отличается от Selenium 1.x, поскольку он предпочитает выполнять JavaScript внутри окна браузера, а не проводить тест через стандартный Api. Одним из примеров мощи этого подхода является то, что мы преобразовали тесты из асинхронных :

selenium.clickAndWait("Login", 60000);

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

Ext.Ajax.on('requestcomplete', function() {
    if (...) {
        console.log('F: failure in snafucating the grid');
    }
});