phantomjs – Stepan Suvorov Blog https://stepansuvorov.com/blog Release 2.0 Thu, 22 Oct 2015 08:03:21 +0000 en-US hourly 1 https://wordpress.org/?v=6.3.1 phantomjs: error while loading shared libraries: libfontconfig.so.1 https://stepansuvorov.com/blog/2012/10/phantomjs-error-while-loading-shared-libraries-libfontconfig-so-1/ https://stepansuvorov.com/blog/2012/10/phantomjs-error-while-loading-shared-libraries-libfontconfig-so-1/#comments Mon, 22 Oct 2012 13:43:00 +0000 http://stepansuvorov.com/blog/?p=708 In case if you want to install phantomjs and you have just console OS without GUI you have to install additional libraries:

sudo apt-get install freetype-devel fontconfig-devel
]]>
https://stepansuvorov.com/blog/2012/10/phantomjs-error-while-loading-shared-libraries-libfontconfig-so-1/feed/ 6
Утилита для тестирования CasperJS https://stepansuvorov.com/blog/2012/10/%d1%83%d1%82%d0%b8%d0%bb%d0%b8%d1%82%d0%b0-%d0%b4%d0%bb%d1%8f-%d1%82%d0%b5%d1%81%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-casperjs/ https://stepansuvorov.com/blog/2012/10/%d1%83%d1%82%d0%b8%d0%bb%d0%b8%d1%82%d0%b0-%d0%b4%d0%bb%d1%8f-%d1%82%d0%b5%d1%81%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-casperjs/#comments Sun, 21 Oct 2012 15:41:18 +0000 http://stepansuvorov.com/blog/?p=704 Continue reading ]]>

CasperJS – вспомогательный инструмент написанный на JavaScript как обертка PhantomJS. На официальном сайте перечислены следующие основные возможности:

  • определение и порядок итераций браузера
  • заполнение и отправка форм
  • клик и переход по ссылкам
  • создание скриншотов страницы и ее части
  • удаленное тестирование DOM
  • логирование событий
  • загрузка ресурсов и подключение библиотек
  • написание функциональных тестов и сохранение в формате JUnit XML
  • Допиливание веб контента

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

Для начала немного о том, как нам установить CasperJS. Скачиваем архив с офсайта либо выкачиваем файлы с github. Создаем ссылку на исполняемый файл в /usr/local/bin:

$ ln -sf `pwd`/bin/casperjs /usr/local/bin/casperjs

После чего можно проверить работоспособность фантома(который как бы уже должен быть установлен) и каспера:

$ phantomjs
--version 1.7
$ casperjs
--version 1.0.0-RC2

* Еще плюс нужно проверить наличие Python на машине, так как исполняемый файл именно на нем.

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

var casper = require('casper').create();
 casper.start('http://ya.ru/', function(){ console.log("ya.ru OK!"); });
 casper.run();

Если все работает, то можно переходить к плюшкам.

Первая вкусная плюшка – это удобный синтаксис для работы с асинхронными методами. Для того чтобы в фантоме открыть несколько страниц последовательно нужно было делать так:

var page = require('webpage').create();
page.open(url1, function(status) {
  if (status == "fail") phantom.exit();
  page.open(url2, function(status) {
    if (status == "fail") phantom.exit();
    page.open(url3, function(status) {
      if (status == "fail") phantom.exit();
      page.open(url4, function(status) {
        if (status == "fail") phantom.exit();
        // И так далее...
      });
    });
  });
});

В свою очередь на CasperJS это выглядит так:

var casper = require('casper').create();
casper.start(url1);
casper.thenOpen(url2);
casper.thenOpen(url3);
casper.thenOpen(url4);
casper.run();

Согласитесь, что намного приятнее?

Следующая плюшка – это клики по DOM элементам, т.е. имитация пользовательских действий:

var casper = require("casper").create()

casper.start('https://stepansuvorov.com/blog/');
casper.thenClick('#site-title');
casper.thenClick('.page-item-2');
casper.then(function() {
    this.echo('Page url is ' + this.getCurrentUrl());
    this.echo('Page title is ' + this.getTitle());
});

casper.run();

Идем дальше. Плюшка номер три – это удобный интерфейс для заполнения форм:

var casper = require("casper").create()

casper.start('http://ya.ru/', function() {
  this.fill('form[action="http://yandex.ru/yandsearch"]', { text: 'casperjs' }, true);
});

casper.then(function() {
    this.echo('Page url is ' + this.getCurrentUrl());
    this.echo('Page title is ' + this.getTitle());
});

casper.run();

Четвертая плюшка – скрин определенного участка страницы, напомню: фантом умел только делать снимок всей страницы:

var casper = require("casper").create()

casper.start('https://www.google.com', function() {
    this.captureSelector('capture.png', '#hplogo');
});

casper.run();

Пятая плюшка – функциональные тесты – как объединение имитации действий пользователя и проверки соответствий состояний страницы:

var url = 'http://ya.ru/';
var casper = require('casper').create();
casper.start(url, function() {
  this.test.assert(this.getCurrentUrl() === url, 'url is the one expected');
});
casper.run();

И в завершение еще плюшка отслеживания подгрузки контента(в случае когда он грузится асинхронно)

var casper = require("casper").create();

casper.start('http://foo.bar/', function() {
  this.waitForResource("foobar.png");
}); 

casper.then(function() {
  this.echo('foobar.png has been loaded.');
}); 

casper.run();

Аналогичные методы:  wait, waitFor, waitForSelector, waitWhileSelector, waitForResource, waitUntilVisible, waitWhileVisible.

Можно сделать вывод что плюшки у CasperJS есть, и им в целом можно пользоваться.

Материалы, которые помогали трудится над статьей:

API документация с офсайта

CasperJS, a toolkit on top of PhantomJS – прекрасная статья от Nicolas Perriault, которая по сути послужила фундаментом для моей.

]]>
https://stepansuvorov.com/blog/2012/10/%d1%83%d1%82%d0%b8%d0%bb%d0%b8%d1%82%d0%b0-%d0%b4%d0%bb%d1%8f-%d1%82%d0%b5%d1%81%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-casperjs/feed/ 3
Создаем юнит-тесты с phantomjs https://stepansuvorov.com/blog/2012/09/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%b5%d0%bc-%d1%8e%d0%bd%d0%b8%d1%82-%d1%82%d0%b5%d1%81%d1%82%d1%8b-%d1%81-phantomjs/ https://stepansuvorov.com/blog/2012/09/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%b5%d0%bc-%d1%8e%d0%bd%d0%b8%d1%82-%d1%82%d0%b5%d1%81%d1%82%d1%8b-%d1%81-phantomjs/#comments Sat, 29 Sep 2012 14:12:07 +0000 http://stepansuvorov.com/blog/?p=646 Continue reading ]]>

Для начала скажу что 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){

 

Посмотрим как система покажет себя в бою…

 

]]>
https://stepansuvorov.com/blog/2012/09/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%b5%d0%bc-%d1%8e%d0%bd%d0%b8%d1%82-%d1%82%d0%b5%d1%81%d1%82%d1%8b-%d1%81-phantomjs/feed/ 4