Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)
Я не думаю, что мне нужно убеждать вас, что тестирование кода JavaScript - хорошая идея. Но тестирование JavaScript-кода, требующего DOM, иногда может оказаться весьма утомительным занятием. Это означает, что вам нужно проверить свой код в браузере и не использовать терминал, верно? Неправильно, на самом деле можно использовать PhantomJS.
Что такое PhantomJS? Ну, вот видео с сайта PhantomJS:
PhantomJS является WebKit без онка с API JavaScript.
Как вы знаете, Webkit - это механизм компоновки, который используют Chrome, Safari и несколько других браузеров. Итак, PhantomJS - это браузер, но без активного окна. Это означает, что просматриваемые веб-страницы никогда не отображаются. Это может показаться вам странным; поэтому рассматривайте его как программируемый браузер для терминала. Мы совсем скоро рассмотрим простой пример, но сначала нам нужно установить PhantomJS.
Установка PhantomJS
Установка PhantomJS на самом деле довольно проста: это всего лишь один бинарный файл, который вы загружаете и вставляете в свой path. На странице загрузки PhantomJS выберите свою операционную систему и загрузите необходимый пакет. Затем переместите двоичный файл из загруженного пакета в каталог внутри вашего path (я хотел бы поместить это в ~/bin
).
Если вы работаете в Mac OS X, существует более простой способ установки PhantomJS (и на самом деле это метод, который я использовал). Просто используйте Homebrew, вот так:
brew update && brew install phantomjs
Теперь вы должны установить PhantomJS. Вы можете дважды проверить свою установку, выполнив следующие действия:
phantomjs --version
Я вижу 1.7.0; а вы?
Маленький пример
Начнем с небольшого примера.
simple.js
console.log("we can log stuff out."); function add(a, b) { return a + b; } conslole.log("We can execute regular JS too:", add(1, 2)); phantom.exit();
Продолжайте и запустите этот код, выполнив следующую команду:
phantomjs simple.js
Вы должны увидеть выходные данные из двух строк console.log
в окне терминала.
Конечно, это просто, но это хороший момент: PhantomJS может выполнять JavaScript так же, как браузер. Однако в этом примере нет никакого кода, специфичного для PhantomJS ... ну, кроме последней строки. Это важная строка для каждого скрипта PhantomJS, потому что она завершает сценарий. Это может не иметь смысла здесь, но помните, что JavaScript не всегда выполняется линейно. Например, вы можете поместить вызов exit()
в функцию обратного вызова.
Давайте рассмотрим более сложный пример.
Загрузка страниц
Используя API PhantomJS, мы можем загрузить любой URL-адрес и работать со страницей с двух точек зрения:
- как JavaScript на странице.
- как пользователь, просматривающий страницу.
Начнем с загрузки страницы. Создайте новый файл сценария и добавьте следующий код:
script.js
var page = require('webpage').create(); page.open('http://net.tutsplus.com', function (s) { console.log(s); phantom.exit(); });
Мы начинаем с загрузки модуля PhantomJS webpage
и создания объекта веб-страницы. Затем мы вызываем метод open
, передавая ему URL-адрес и функцию обратного вызова; внутри этой функции обратного вызова мы можем взаимодействовать с фактической страницей. В приведенном выше примере мы просто регистрируем статус запроса, предоставляемый параметром функции обратного вызова. Если вы запустите этот скрипт (phantomjs script.js
), вы должны получить «success», напечатанный в терминале.
Но давайте сделаем пример еще более интересным, загрузив страницу и выполнив над ней JavaScript код. Начнем с приведенного выше кода, но затем мы вызываем page.evaluate
:
page.open('http://net.tutsplus.com', function () { var title = page.evaluate(function () { var posts = document.getElementsByClassName("post"); posts[0].style.backgroundColor = "#000000"; return document.title; }); page.clipRect = { top: 0, left: 0, width: 600, height: 700 }; page.render(title + ".png"); phantom.exit(); });
PhantomJS - браузер, но без окна.
Функция, которую мы передаем на page.evaluate
, выполняется как JavaScript на загруженной веб-странице. В этом случае мы находим все элементы с классом post
; затем мы устанавливаем фон первого поста в черный. Наконец, мы возвращаем document.title
. Это удобная возможность - возвращать значение из нашего обратного вызова evaluate
и присваивать его переменной (в данном случае, title
).
Затем мы устанавливаем clipRect
на странице; это размеры экрана, который мы снимаем с помощью метода render
. Как вы можете видеть, мы устанавливаем top
и left
значения для установки начальной точки, а также устанавливаем width
и height
. Наконец, мы вызываем page.render
, передавая ему имя для файла (переменная title
). Затем завершаем вызовом phantom.exit()
.
Теперь запустите этот скрипт, и у вас должно получиться изображение, которое выглядит примерно так:

Здесь вы можете увидеть обе стороны медали PhantomJS: мы можем выполнить JavaScript изнутри страницы, а также выполнить извне, над самим экземпляром страницы.
Это было весело, но не невероятно полезно. Давайте сосредоточимся на использовании PhantomJS при тестировании нашего JavaScript, связанного с DOM.
Тестирование с помощью PhantomJS
Yeoman использует PhantomJS в своей процедуре тестирования, и практически без проблем.
В большинстве случаев вы можете протестировать, не используя DOM, но есть моменты, когда ваши тесты должны взаимодействовать с элементами HTML. Если так же как и я предпочитаете запускать тесты в командной строке, это значит, что PhantomJS - как раз то что вам нужно.
Конечно, PhantomJS не является тестовой библиотекой, но многие другие популярные библиотеки тестирования могут работать поверх PhantomJS. Как видно на вики-странице PhantomJS о тестировании в браузере без окна, тестовые бегуны PhantomJS доступны практически для любой библиотеки тестирования, которую вы, возможно, захотите использовать. Давайте посмотрим, как использовать PhantomJS вместе с Jasmine и Mocha.
Во-первых, Jasmine: в настоящее время в Jasmine нет хорошего бегуна тестов для PhantomJS. Если вы используете Windows и Visual Studio, обратите внимание на Chutzpah, а разработчикам Rails следует попробовать guard-jasmine. В остальных же случаях поддержка Jasmine + PhantomJS довольно хорошая.
По этой причине я рекомендую использовать Mocha для тестов, связанных с DOM.
ОДНАКО.
Возможно, у вас уже есть проект с использованием Jasmine и вы хотите использовать его вместе с PhantomJS. Один проект, phantom-jasmine, требует немного работы для настройки, но в нем все запустится.
Начнем с набора тестов JasmineJS. Загрузите код для этого урока (ссылка вверху) и проверьте папку jasmine-starter
. Вы увидите, что у нас есть один файл tests.js, который создает элемент DOM, устанавливает несколько свойств и добавляет его в тело. Затем мы запускаем несколько тестов Jasmine, чтобы гарантировать, что процесс действительно работает правильно. Вот содержимое этого файла:
tests.js
describe("DOM Tests", function () { var el = document.createElement("div"); el.id = "myDiv"; el.innerHTML = "Hi there!"; el.style.background = "#ccc"; document.body.appendChild(el); var myEl = document.getElementById('myDiv'); it("is in the DOM", function () { expect(myEl).not.toBeNull(); }); it("is a child of the body", function () { expect(myEl.parentElement).toBe(document.body); }); it("has the right text", function () { expect(myEl.innerHTML).toEqual("Hi there!"); }); it("has the right background", function () { expect(myEl.style.background).toEqual("rgb(204, 204, 204)"); }); });
Файл SpecRunner.html
является довольно простым; единственное отличие состоит в том, что я переместил теги сценария в body, чтобы гарантировать, что DOM полностью загрузится до запуска наших тестов. Вы можете открыть файл в браузере и увидеть, что все тесты проходят просто отлично.
Давайте перейдем к проекту PhantomJS. Во-первых, клонируйте проект phantom-jasmine:
git clone git://github.com/jcarver989/phantom-jasmine.git
Возможно этот проект не так уж хорошо организован, но в нем есть две важные части:
- бегун PhantomJS (который заставляет Jasmine использовать PhantomJS DOM).
- репортер консоли Jasmine (который дает консольный вывод).
Оба этих файла находятся в папке lib
; скопируйте их в jasmine-starter/lib
. Теперь нам нужно открыть наш файл SpecRunner.html
и настроить элементы <script />
. Вот как они должны выглядеть:
<script src="lib/jasmine-1.2.0/jasmine.js"></script> <script src="lib/jasmine-1.2.0/jasmine-html.js"></script> <script src="lib/console-runner.js"></script> <script src="tests.js"></script> <script> var console_reporter = new jasmine.ConsoleReporter() jasmine.getEnv().addReporter(new jasmine.HtmlReporter()); jasmine.getEnv().addReporter(console_reporter); jasmine.getEnv().execute(); </script>
Обратите внимание, что у нас есть два репортера для наших тестов: репортер HTML и консольный репортер. Это означает, что SpecRunner.html
и его тесты могут выполняться как в браузере, так и в консоли. Это удобно. К сожалению, нам нужна переменная console_reporter
, потому что она используется внутри файла CoffeeScript, который мы собираемся запустить.
Итак, как мы можем начать выполнение этих тестов в консоли? Предполагая, что вы находитесь в папке jasmine-starter
, вот команда для запуска через терминал:
phantomjs lib/run\_jasmine\_test.coffee ./SpecRunner.html
Мы запускаем сценарий run\ _jasmine\ _test.coffee
с помощью PhantomJS и передаем наш файл SpecRunner.html
в качестве параметра. Вы должны увидеть что-то вроде этого:

Конечно, если тест не удался, вы увидите что-то вроде следующего:

Если вы планируете использовать часто это запускать, может быть хорошей идеей переместить run\ _jasmine\ _test.coffee
в другое место (например, ~/bin/run\_jasmine\ _test.coffee
) и создать псевдоним терминала для всей команды. Вот как вы сделали бы это в оболочке Bash:
alias phantom-jasmine='phantomjs /path/to/run\_jasmine\_test.coffee'
Просто добавьте это в свой файл .bashrc
или .bash_profile
. Теперь вы можете просто запустить:
phantom-jasmine SpecRunner.html
Теперь ваши тесты Jasmine отлично работают и в терминале через PhantomJS. Вы можете увидеть окончательный код в папке jasmine-total
.
PhantomJS и Mocha
К счастью, гораздо проще интегрировать Mocha и PhantomJS с помощью mocha-phantomjs. Его очень просто установить, если у вас установлен NPM (что вам нужно):
npm install -g mocha-phantomjs
Эта команда устанавливает бинарный файл mocha-phantomjs
, который мы будем использовать для запуска наших тестов.
В предыдущем уроке я показал вам, как использовать Mocha в терминале, но вы будете делать что-то по-другому, когда используете его для тестирования кода DOM. Как и в случае с Jasmine, мы начнем с репортёра HTML-теста, который может работать в браузере. Красота этого заключается в том, что мы сможем запустить тот же файл на терминале для результатов консольных тестов с помощью PhantomJS; как мы могли с Jasmine.
Итак, давайте построим простой проект. Создайте каталог проекта и перейдите в него. Мы начнем с файла package.json
:
{ "name": "project", "version": "0.0.1", "devDependencies": { "mocha": "*", "chai" : "*" } }
Mocha - это тестовая среда, и мы будем использовать Chai в качестве нашей библиотеки утверждений. Мы устанавливаем их с помощью NPM.
Мы назовем наш тестовый файл test/tests.js
, и вот его тесты:
describe("DOM Tests", function () { var el = document.createElement("div"); el.id = "myDiv"; el.innerHTML = "Hi there!"; el.style.background = "#ccc"; document.body.appendChild(el); var myEl = document.getElementById('myDiv'); it("is in the DOM", function () { expect(myEl).to.not.equal(null); }); it("is a child of the body", function () { expect(myEl.parentElement).to.equal(document.body); }); it("has the right text", function () { expect(myEl.innerHTML).to.equal("Hi there!"); }); it("has the right background", function () { expect(myEl.style.background).to.equal("rgb(204, 204, 204)"); }); });
Они очень похожи на тесты Jasmine, но синтаксис утверждения Chai немного отличается (так что нельзя просто скопировать тесты Jasmine).
Последний фрагмент головоломки - файл TestRunner.html
:
<html> <head> <title> Tests </title> <link rel="stylesheet" href="./node_modules/mocha/mocha.css" /> </head> <body> <div id="mocha"></div> <script src="./node_modules/mocha/mocha.js"></script> <script src="./node_modules/chai/chai.js"></script> <script> mocha.ui('bdd'); mocha.reporter('html'); var expect = chai.expect; </script> <script src="test/test.js"></script> <script> if (window.mochaPhantomJS) { mochaPhantomJS.run(); } else { mocha.run(); } </script> </body> </html>
Здесь есть несколько важных факторов. Во-первых, обратите внимание, что достаточно работать в браузере; у нас есть CSS и JavaScript из модулей node, которые мы установили. Затем обратите внимание на тег script. Он определяет, загружен ли PhantomJS, и если это так, запускается функционал PhantomJS. В противном случае, он придерживается простой функциональности Mocha. Вы можете попробовать это в браузере и посмотреть, как это работает.
Чтобы запустить его в консоли, просто выполните это:
mocha-phantomjs TestRunner.html
Вуаля! Теперь вы запускаете тесты из консоли, и все это благодаря PhantomJS.
PhantomJS и Yeoman
Готов поспорить, что вы не знали, что популярный Yeoman использует PhantomJS в своей процедуре тестирования. Давайте посмотрим на простой пример. Я предполагаю, что у вас уже есть Yeoman.
Создайте новый каталог проекта, запустите yoman init
внутри и ответьте «Нет» на все параметры. Откройте файл test/index.html
, и вы найдете тег script внизу, где будет указано, что вы замените его своими спецификациями. Полностью игнорируйте этот хороший совет и помещайте его внутри блока it
:
var el = document.createElement("div"); expect(el.tagName).to.equal("DIV");
Теперь запустите yoman test
, и вы увидите, что тест работает нормально. Теперь откройте файл test/index.html
в браузере. Все работает! Отлично!
Разумеется, вы много еще чего можете сделать с Yeoman, поэтому ознакомьтесь с документацией.
Заключение
Используйте библиотеки, расширяющие PhantomJS, чтобы упростить тестирование.
Если вы используете PhantomJS самостоятельно, нет никаких оснований узнать о самом PhantomJS; вы можете просто знать, что он существует, и использовать библиотеки, расширяющие PhantomJS, чтобы упростить тестирование.
Надеюсь, этот урок побудил вас заглянуть в PhantomJS. Я рекомендую начать с файлов примеров и документации, предлагаемой PhantomJS; они действительно откроют вам глаза на то, что вы можете сделать с PhantomJS - все начиная от автоматизации страниц и заканчивая сетевым сниффингом.
Итак, можете ли вы подумать о проекте, который PhantomJS улучшит? Давайте узнаем об этом в комментариях!
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post