Часто в нашей работе мы должны иметь возможность многократно повторять путешествие пользователя, чтобы обеспечить постоянную работу наших страниц при внесении изменений в наш сайт. Крайне важно иметь возможность последовательно и удобно выполнять эту задачу — библиотеки, которые позволяют нам создавать сценарии для этих типов тестов, чтобы мы могли проверять их и поддерживать документацию по результатам. Войдите в безголовые браузеры: инструменты командной строки, которые предоставляют вам возможность программно создавать сценарии взаимодействия пользователя с вашим сайтом и записывать результаты для использования в тестах.
Многие из нас годами используют PhantomJS , CasperJS и другие инструменты для этого. Но, как это часто бывает с любовью, наши сердца могут быть завещаны другому. Начиная с Chrome 59 (60 для пользователей Windows), Chrome поставляется с собственным безголовым браузером. И хотя в настоящее время он не предлагает поддержку Selenium, он использует Chromium и движок Blink, то есть имитирует реальный пользовательский опыт в Chrome.
Как всегда, код этой статьи можно найти в нашем репозитории GitHub .
Запустите Chrome без головы из командной строки
Запуск Headless Chrome из командной строки относительно прост. На Mac вы можете установить псевдоним для Chrome и запускать с помощью —headless
командной строки —headless
alias chrome="/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome” chrome --headless --disable-gpu --remote-debugging-port=9090 https://www.sitepoint.com/
В Linux это даже проще:
google-chrome --headless --disable-gpu --remote-debugging-port=9090 https://www.sitepoint.com/
-
--headless
: работает без пользовательского интерфейса или отображения серверных зависимостей -
--disable-gpu
: отключает аппаратное ускорение графического процессора. Это временно необходимо сейчас. -
--remote-debugging-port
: включает удаленную отладку по HTTP на указанном порту.
Вы также можете взаимодействовать с запрашиваемой страницей, например, распечатать document.body.innerHTML
на стандартный вывод, который вы можете сделать:
google-chrome --headless --disable-gpu --dump-dom http://endless.horse/
Если вам интересно, что еще возможно, полный список параметров можно найти здесь .
Запуск безголового Chrome в Node.js
Однако в центре внимания этой статьи не командная строка, а запуск Headless Chrome в Node.js. Для этого нам понадобятся следующие модули:
- chrome-remote-interface : JavaScript API обеспечивает простую абстракцию команд и уведомлений.
- Chrome-Launcher : это позволяет нам запускать Chrome изнутри Node на нескольких платформах.
Тогда мы можем настроить нашу среду. Это предполагает, что на вашей машине установлены Node и npm. Если это не так, ознакомьтесь с нашим руководством здесь .
mkdir headless cd headless npm init -y npm install chrome-remote-interface --save npm install chrome-launcher --save
После этого мы хотим создать сеанс с помощью headless-chrome. Начнем с создания файла index.js
в папке нашего проекта:
const chromeLauncher = require('chrome-launcher'); const CDP = require('chrome-remote-interface'); (async function() { async function launchChrome() { return await chromeLauncher.launch({ chromeFlags: [ '--disable-gpu', '--headless' ] }); } const chrome = await launchChrome(); const protocol = await CDP({ port: chrome.port }); // ALL FOLLOWING CODE SNIPPETS HERE })();
Во-первых, нам нужны наши зависимости, а затем мы создаем функцию, вызывающую себя, которая создает экземпляр сеанса Chrome. Обратите внимание, что флаг --disable-gpu
требуется на момент написания этой статьи, но может не потребоваться, когда вы читаете это, поскольку он требуется только в качестве обходного пути (как рекомендовано Google) . Мы будем использовать async / await
чтобы убедиться, что наше приложение ожидает запуска безголового браузера перед выполнением следующей серии шагов.
Примечание : мы собираемся работать с функциями, которые требуют выполнения действий перед переходом к последующим шагам. Это дает время для визуализации страниц, выполнения взаимодействий и т. Д., Прежде чем продолжить. Многие из этих шагов не блокируют, поэтому нам нужно полагаться на обещания приостановить выполнение. Более подробную информацию об асинхронной функции можно найти в Mozilla Developer Network или здесь, на SitePoint .
Далее нам нужно выставить домены, которые нам нужны для нашего тестирования:
const { DOM, Page, Emulation, Runtime } = protocol; await Promise.all([Page.enable(), Runtime.enable(), DOM.enable()]);
Наиболее важным здесь является объект Page
— мы будем использовать его для доступа к содержимому, отображаемому в пользовательском интерфейсе. Это также будет то, где мы будем указывать, куда мы перемещаемся, с какими элементами мы взаимодействуем и где мы будем запускать наши скрипты.
Изучение страницы
После инициализации сеанса и определения доменов мы можем начать навигацию по сайту. Мы хотим выбрать отправную точку, поэтому мы используем домен Page, который мы включили выше, чтобы перейти к:
Page.navigate({ url: 'https://en.wikipedia.org/wiki/SitePoint' });
Это загрузит страницу. Затем мы можем определить шаги, которые мы хотим запустить, используя метод loadEventFired
чтобы выполнить код для репликации нашего пользовательского пути. В этом примере мы просто собираем содержимое первого абзаца:
Page.loadEventFired(async() => { const script1 = "document.querySelector('p').textContent" // Evaluate script1 const result = await Runtime.evaluate({ expression: script1 }); console.log(result.result.value); protocol.close(); chrome.kill(); });
Если вы запустите скрипт, используя node index.js
вы должны увидеть что-то node index.js
на следующий результат:
SitePoint is a Melbourne, Australia-based website, and publisher of books, courses and articles for web developers. In January 2014, SitePoint.com had an Alexa ranking of 889,[1] and a Quantcast rating of 14,934.[2]
Идем дальше — захватывая скриншот
Это хорошо, но мы можем так же легко подставить любой код в это значение script1
чтобы щелкать ссылки, заполнять поля формы и запускать серии взаимодействий с помощью селекторов запросов. Каждый шаг может быть сохранен в файле конфигурации JSON и загружен в скрипт Node для последовательного выполнения. Результаты этих сценариев могут быть проверены с использованием платформы тестирования, такой как Mocha, что позволяет перекрестно ссылаться на то, что полученные значения соответствуют требованиям UI / UX.
В дополнение к вашим тестовым сценариям вы, вероятно, захотите делать скриншоты ваших страниц при навигации по сайту. К счастью, предоставленный домен имеет функцию captureScreenshot
которая делает именно это.
const chromeLauncher = require('chrome-launcher'); const CDP = require('chrome-remote-interface'); const file = require('fs'); (async function() { ... Page.loadEventFired(async() => { const script1 = "document.querySelector('p').textContent" // Evaluate script1 const result = await Runtime.evaluate({ expression: script1 }); console.log(result.result.value); const ss = await Page.captureScreenshot({format: 'png', fromSurface: true}); file.writeFile('screenshot.png', ss.data, 'base64', function(err) { if (err) { console.log(err); } }); protocol.close(); chrome.kill(); }); })();
Флаг fromSurface
— это другой флаг, который требуется для межплатформенной поддержки на момент написания этой статьи и может не потребоваться в будущих итерациях.
Запустите скрипт, используя node index.js
и вы должны увидеть вывод, подобный приведенному ниже:
Вывод
Если вы пишете автоматизированные сценарии, вы должны начать использовать браузер без браузера Chrome. Хотя он по-прежнему не полностью интегрирован с такими инструментами, как Selenium, преимущество симуляции движка рендеринга Chromes не следует недооценивать. Это лучший способ воссоздать опыт пользователей в полностью автоматическом режиме.
Я оставлю вас с дальнейшим чтением:
- Документы API: https://chromedevtools.github.io/devtools-protocol/
- Начало работы с Headless Chrome: https://developers.google.com/web/updates/2017/04/headless-chrome
Дайте мне знать о вашем опыте с Headless Chrome в комментариях ниже.