Статьи

Быстрый совет: Начало работы с Headless Chrome в Node.js

Часто в нашей работе мы должны иметь возможность многократно повторять путешествие пользователя, чтобы обеспечить постоянную работу наших страниц при внесении изменений в наш сайт. Крайне важно иметь возможность последовательно и удобно выполнять эту задачу — библиотеки, которые позволяют нам создавать сценарии для этих типов тестов, чтобы мы могли проверять их и поддерживать документацию по результатам. Войдите в безголовые браузеры: инструменты командной строки, которые предоставляют вам возможность программно создавать сценарии взаимодействия пользователя с вашим сайтом и записывать результаты для использования в тестах.

Многие из нас годами используют 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 и вы должны увидеть вывод, подобный приведенному ниже:

Headless Chrome: вывод команды скриншота

Вывод

Если вы пишете автоматизированные сценарии, вы должны начать использовать браузер без браузера Chrome. Хотя он по-прежнему не полностью интегрирован с такими инструментами, как Selenium, преимущество симуляции движка рендеринга Chromes не следует недооценивать. Это лучший способ воссоздать опыт пользователей в полностью автоматическом режиме.

Я оставлю вас с дальнейшим чтением:

Дайте мне знать о вашем опыте с Headless Chrome в комментариях ниже.