Уже из названия понятно, что headless-браузер — это нечто без головы. В контексте фронтенда — это незаменимый инструмент разработчика, с помощью которого можно тестировать код, проверять качество и соответствие верстке. Виталий Слободин на Frontend Conf решил, что необходимо познакомиться с устройством этого инструмента поближе.

Под катом компоненты и особенности работы Headless Chrome, интересные сценарии использования Headless Chrome. Вторая часть про Puppeteer — удобную Node.js-библиотеку для управления Headless-режимом в Google Chrome и Chromium.


О спикере: Виталий Слободин — бывший разработчик PhantomJS — тот, кто закрыл его и похоронил. Иногда помогает Константину Токареву ( annulen) в «воскрешенной» версии QtWebKit — том самом QtWebKit, где есть поддержка ES6, Flexbox и многие других современных стандартов.

Виталий любит исследовать браузеры, в свободное время копаться в WebKit, Chrome и прочее, прочее. Про браузеры сегодня и поговорим, а именно про безголовые браузеры и всю их семейку призраков.

Что такое безголовый браузер?


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

  1. У него нет реальной отрисовки содержимого, то есть он все отрисовывает в памяти.
  2. За счет этого он потребляет меньше памяти, потому что не нужно отрисовывать картинки или гигабайтные PNG, которые люди пытаются при помощи бомбы положить в бэкенд.
  3. Он работает быстрее, потому что ему ничего не нужно отрисовывать на реальном экране.
  4. Имеет программный интерфейс для управления. Вы спросите — у него же нет интерфейса, кнопочек, окошек? Как же им управлять? Поэтому конечно же он имеет интерфейс для управления.
  5. Немаловажное свойство — возможность установки на «голый» Linux-сервер. Это нужно для того, что, если у вас есть свежеустановленная Ubuntu или Red Hat, вы можете просто туда закинуть бинарник или поставить пакет, и браузер будет работать из коробки. Никакого шаманства или вуду-магии не понадобится.

Так схематично выглядит обычной браузер на основе WebKit. Вы можете не вчитываться в компоненты — это просто наглядное изображение.



Нас интересует только верхний компонент Browser UI. Это тот самый интерфейс пользователя — окошки, меню, всплывающие уведомления и все остальное.



Так выглядит безголовый браузер. Заметили разницу? Мы полностью убираем интерфейс пользователя. Его больше нет. Остается только браузер.

Сегодня мы будем говорить именно про Headless Chrome (). В чем между ними разница? На самом деле, Chrome — это брендированная версия Chromium, у которой есть проприетарные кодеки, тот же самый H.264, интеграции с сервисами Google и все остальное. Chromium — это просто открытая реализация.



Дата рождения Headless Chrome: 2016 год. Если вы сталкивались с ним, то можете задать мне каверзный вопрос: «Как так, я помню новость 2017 года?» Дело в том, что команда инженеров из Google связывалась с разработчиками PhantomJS еще в 2016 году, когда они только-только начинали реализовывать Headless-режим в Chrome. Мы писали целые гуглдоки, как мы будем реализовывать интерфейс и прочее. Тогда Google хотели сделать интерфейс, полностью совместимый с PhantomJS. Это уже потом команда инженеров пришла к решению не делать таковую совместимость.

Об интерфейсе для управления (API), в качестве которого выступает Chrome DevTools protocol, поговорим позже и посмотрим, что с его помощью можно делать.

Эта статья будет строится по принципу пирамиды Puppeteer (с англ. кукловод). Хорошее название выбрано — кукловод — тот, кто управляет всеми остальными!



В основании пирамиды лежит Headless Chrome — безголовый Chrome — что это такое?

Headless Chrome




В центре — Headless browser — тот самый Chromium или Chrome (обычно Chromium). У него есть так называемые отрисовщики (RENDERER) — процессы, которые отрисовывают содержимое страницы (ваше окно). Причем, каждой вкладке нужен свой отрисовщик, поэтому, если открыть много вкладок, то Chrome запустит столько же процессов для отрисовки.

Поверх всего этого — ваше приложение. Если мы берем Chromium или Headless Chrome, то поверх него будет Chrome, либо какое-то приложение, в которое вы можете встроить его. Ближайшим аналогом можно назвать Steam. Все знают, что по сути Steam — это просто браузер к сайту Steam. Он, конечно, не headless, но похож на эту схему.

Есть 2 способа встраивать безголовый Chrome в ваше приложение (или его использовать):

  1. Стандартный, когда вы берете Puppeteer и используете Headless Chrome.
  2. Когда вы берете компонент Headless library, то есть библиотеку, которая реализует безголовый режим, и встраиваете в свое приложение, допустим, на языке C++.

Вы спросите, зачем C++ на фронтенде? Ответ — DevTools C++ API. Вы можете по-разному реализовывать и использовать возможности безголового Chrome. Если вы используете Puppeteer, общение с безголовым браузером будет осуществляться через веб-сокеты. Если вы встраиваете Headless library в десктопное приложение, то будете использовать нативный интерфейс, который написан на C++.

Но помимо всего этого у вас еще появляются дополнительные вещи, в том числе:

  • Custom networking — кастомная реализация взаимодействия с сетью. Допустим, вы работаете в банке или в госструктуре, которая состоит из трех букв и начинается на «Ф», и используете очень хитрый протокол аутентификации или авторизации, который не поддерживается браузерами. Поэтому вам может понадобиться кастомный обработчик для вашей сети. Вы можете просто взять вашу уже реализованную библиотеку и использовать ее в Chrome.
  • Mojo modules. Ближайшим аналогом Mojo являются нативные биндинги в Node.js к вашим нативным библиотекам, написанные в C++. Mojo делает то же самое — вы берете свою нативную библиотеку, пишите для нее Mojo-интерфейс, и потом можете в вашем браузере вызывать методы вашей нативной библиотеки.

Компоненты Chromium




Опять слышу каверзный вопрос: «Зачем мне эта страшная схема? Я пишу под (вставьте название любимого фреймворка)».

Я считаю, что разработчик должен знать, как устроен его инструмент. Если вы пишите под React, вы должны знать, как работает React. Если вы пишите под Angular, вы должны знать, что у Angular под капотом.

Потому что в случае чего, допустим, фатальной ошибки или очень серьезного бага на продакшене, вам придется разбираться с «кишками», и вы просто можете потеряться там — где, что и как. Если вы, например, будете писать тесты или использовать Headless Chrome, вы тоже можете столкнуться с некоторыми его странностями поведения и багами. Поэтому я вам вкратце расскажу, какие у Chromium есть компоненты. Когда вы увидите большой stack trace, вы уже будете знать, в какую сторону копать и как вообще это можно поправить.

Самый низкий уровень Platform layer. Его компоненты:

  • Ozone — абстрактный менеджер окон в Chrome — то, с чем взаимодействует оконный менеджер операционной системы. На Linux это либо X-server, либо Wayland. На Windows это менеджер окон Windows.
  • Scheduler — тот самый планировщик, без которого мы никуда, потому что мы все знаем, что Chrome — это многопроцессное приложение, и нам нужно как-то разруливать все потоки, процессы и все остальное.
  • Net — у браузера всегда должен быть компонент для работы с сетью, например, парсинг HTTP, создание заголовков, редактирование и т.д.

Уровень Content layer — самый большой компонент, который есть в Chrome. Он включает в себя:

  • Blink — веб-движок на основе WebCore из WebKit. Он может взять HTML в виде строки, распарсить, выполнить JavaScript — и все. Больше он вообще ничего не умеет: ни работать с сетью, ни отрисовывать — все это происходит поверх Blink.
    Blink в себя включает: сильно модифицированную версию WebCore — веб-движка для работы с HTML и CSS; V8 (JavaScript движок); а также API для всех расширений, которые мы используем в Chrome, например, блокировщик рекламы. Туда же входит DevTools protocol.
  • Content API — это интерфейс, при помощи которого можно очень легко использовать все возможности веб-движка. Поскольку внутри Blink так много всего (наверное, больше миллиона интерфейсов), то, чтобы не потеряться во всех этих методах и функциях, нужен Content API. Вы вводите HTML, движок его автоматически обработает, разберет DOM, построит CSS OM, выполнит JavaScript, запустит таймеры, обработчики и все остальное.

Уровень Headless layer — уровень безголового браузера:

  • Headless library.
  • Embedder API интерфейс для встраивания Headless library в приложение.
  • Client API — интерфейс, который использует Puppeteer.

Уровень приложения Application layer:

  • Ваше приложение (Embedding app);
  • Мини-приложения, например, Headless shell.

Теперь давайте поднимемся из глубин чуть выше, активизируемся — сейчас пойдет фронтенд.



Chrome DevTools protocol


Мы все сталкивались с Chrome DevTools protocol, поскольку пользуемся панелью разработчиков в Chrome или удаленным отладчиком — теми же самыми средствами разработки. Если вы запускаете средства разработчика в удаленном режиме, общение с браузером происходит при помощи именно DevTools protocol. Когда вы ставите debugger, смотрите code coverage, используете геолокацию или еще что-нибудь — все это управляется при помощи DevTools.



На самом деле сам DevTools protocol имеет огромное количество методов. Ваше средство разработчика не имеет доступа, наверное, к 80% из них. Реально там можно делать все!

Давайте разберем, что из себя представляет этот протокол. На самом деле он очень простой. В нем есть 2 компонента:

  1. DevTools target —вкладка, которую вы инспектируете;
  2. DevTools client — допустим, это панель разработчика, которая запущена в удаленном режиме.



Они общаются при помощи простого JSON:

  • Есть идентификатор команды, название метода, который нужно выполнить, и некоторые параметры.
  • Посылаем запрос и получаем ответ, который тоже выглядит очень просто: идентификатор, который нужен потому, что все команды, которые выполняются при помощи протокола, асинхронные. Для того, чтобы мы всегда могли сопоставить, какой ответ на какую команду нам пришел, нам и требуется идентификатор.
  • Есть результат. В нашем случае он представляет собой объект result со следующими атрибутами: type: «number», value: 2, description: «2», исключение брошено не было: wasThrown: false.

Но помимо всего прочего ваша вкладка может слать события вам обратно. Допустим, когда произошло какое-то событие на странице, или было исключение на странице, вы получите уведомление через этот протокол.





Puppeteer


Установить Puppeteer можно при помощи любимого пакетного менеджера — будь то yarn, npm или любой другой.

Использовать его тоже легко — просто запрашиваете его в своем Node.js-скрипте, и уже, по сути, можете использовать.



По ссылке https://try-puppeteer.appspot.com вы можете прямо на сайте написать скрипт, выполнить его и получить результат прямо в браузере. Все это будет реализовано при помощи Headless Chrome.

Рассмотрим простейший скрипт под Node.js:

const puppeteer = require('puppeteer');

(async() => {
  const browser = await puppeteer.launch() ; 
  const page = await browser.newPage();

  await page.goto('http://devconf.ru/') ; 
  await page.emulateMedia('screen') ; 
  await page.pdf({
    path: './devconf.pdf, 
    printBackground: true 
  });
await browser.close() ;
})();

Здесь мы просто открываем страничку и печатаем ее в PDF. Посмотрим работу этого скрипта в режиме реального времени:


Все будет классно, но непонятно — что там внутри. Конечно, у нас же headless-браузер, мы же ничего не видим. Поэтому у Puppeteer есть специальный флаг, который называется headless: false:

const browser = await puppeteer.launch({
  headless: false
});

Он нужен для запуска headless-браузера в режиме headful, когда вы сможете увидеть какое-то окно и посмотреть, что же происходит с вашей страницей в режиме реального времени, то есть как ваш скрипт взаимодействует с вашей страницей.



Так будет выглядеть тот же самый скрипт, когда мы добавим этот флаг. Слева появляется окно браузера — уже нагляднее.


Плюсы Puppeteer:

? + Это Node.js-библиотека для безголового Chrome.
? + Поддержка legacy-версий Node.js >= 6.
? + Легкая установка.
? + Высокоуровневый API для управления всей этой гигантской машиной.

Безголовый Chrome устанавливается легко и без вмешательства в систему. При первой установке Puppeteer скачивает версию Chromium и устанавливает ее прямо в папку node_modules именно под вашу архитектуру и ОС. Вам не нужно ничего скачивать дополнительно, он это делает автоматически. Вы также можете использовать и вашу любимую версию Chrome, которая установлена у вас в системе. Это тоже можно сделать — Puppeteer предоставляет вам такой API.

К сожалению, есть и минусы, если брать именно базовую инсталляцию.

Минусы Puppeteer:

? ? Нет top-level функций: синхронизации закладок и паролей; поддержки профилей; аппаратного ускорения и т.д.
? ? Программный рендеринг — наиболее весомый минус. Все вычисления и отрисовки происходят на вашем CPU. Но и тут инженеры Google нас скоро удивят — работы по реализации аппаратного ускорения уже ведутся. Уже сейчас можно попытаться его использовать, если вы смелы и отважны.
? ? До недавнего времени не было поддержки расширений — теперь ЕСТЬ! Если вы хитрый разработчик, можете взять ваш любимый AdBlock, указать, как Puppeteer’у его использовать, и вся реклама будет заблокирована.
? ? Нет поддержки аудио/видео. Потому что, ну зачем headless-браузеру аудио и видео.

Что может Puppeteer:

  • Изоляция сессий.
  • Виртуальные таймеры.
  • Перехват сетевых запросов.

И еще пара клевых вещей, которые я покажу чуть дальше.

Изоляция сессий


Что это такое, с чем ее едят, и не подавимся ли мы? — Не подавимся!

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

  • cookes;
  • local storage;
  • cache.

Все страницы будут жить независимо друг от друга. Это нужно, чтобы, например, поддерживать атомарность тестов.

Изоляция сессий позволяет сэкономить ресурсы и время при запуске параллельных сессий. Допустим, вы тестируете сайт, который собирается в development-режиме, то есть bundle не минимизированы, и весят 20 МБ. Если вы хотите просто его закэшировать, то можете указать Puppeteer использовать кэш общий для всех страниц, которые создаются, и этот bundle будет закэширован.

Можно сериализовать сессии для последующего использования. Вы пишите тест, который проверяет некое действие у вас на сайте. Но у вас есть проблема — сайт требует авторизацию. Вы же не будете в каждом тесте постоянно добавлять before для авторизации на сайте. Puppeteer позволяет залогиниться на сайте один раз, и потом переиспользовать эту сессию в дальнейшем.

Виртуальные таймеры


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

Браузер может использовать виртуальные таймеры вместо реальных, чтобы «прокрутить» время вперед для ускорения загрузки страницы или завершения анимации. Допустим, у вас тот же самый тест, вы заходите на главную страницу, а там анимация на 30 секунд. Никому не выгодно, чтобы тест ждал все это время. Поэтому вы можете просто ускорить анимацию, чтобы она была завершена мгновенно при загрузке страницы, и ваш тест продолжил работу.

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

На слайде ниже есть еще один вариант: остановить и продолжить работу отрисовщика (renderer). В экспериментальном режиме была возможность сказать браузеру не заниматься отрисовкой, а позже, если понадобится, запросить скриншот. Тогда бы безголовый Chrome все бы быстро отрисовал, выдал скриншот, и снова перестал бы отрисовывать что-либо. К сожалению, разработчики уже успели поменять принцип работы этого API и такой функции больше нет.

Схематичный вид виртуальных таймеров ниже.



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

Ускорение таймеров — они запускаются друг за другом. Когда мы их приостанавливаем, у нас появляется промежуток времени, после которого все таймеры стартанут.

Рассмотрим это на примере. Ниже обрезанный кусок кода, который по сути просто загружает страницу с анимацией с codepen.io и ждет:

(async() => {
  const browser = await puppeteer.launch(); 
  const page = await browser.newPage();

  const url = ‘https ://codepen.o/ajerez/full/EaEEOW/'; // # 1

  await page.goto(url, { waitUnitl: 'load' }); // # 2
})();


Это демонстрация выполнения в ходе доклада — просто анимация.

Теперь при помощи Chrome DevTools protocol отправим метод, который называется Animation.setPlaybackRate, передадим в качестве параметров ему playbackRate с значением 12:

const url = 'https://codepen.o/ajerez/full/EaEEOW/'; // # 1
await page._client.send('Animation.setPlaybackRate', { playbackRate: 12 }); // # 3
await page.goto(url, { waitUntil: 'load' }); // # 2

Загружаем ту же самую ссылку, и анимашка стала работать гораздо быстрее. Это происходит за счет того, что мы использовали виртуальный таймер и ускорили проигрывание анимации в 12 раз.

Давайте теперь проведем эксперимент — передадим playbackRate: 0 — и посмотрим, что же будет. А будет вот что: анимации вообще нет, она не проигрывается. Нулевое и отрицательные значения просто приостанавливают полностью всю анимацию.

Работа с сетевыми запросами


Вы можете перехватывать сетевые запросы путем установки следующего флага:

await page.setRequestlnterception(true);

В таком режиме появляется дополнительное событие, которое срабатывает, когда отправляется или приходит какой-то сетевой запрос.

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

Это нужно для того, чтобы обрабатывать авторизацию или аутентификацию, в том числе базовую аутентификацию по HTTP.

Еще вы можете сделать покрытие кода (JS/CSS). При помощи Puppeteer можно все это автоматизировать. Все мы знаем утилиты, которые могут загрузить страничку, показать, какие классы в ней используются и т.д. Но довольны ли мы ими? Думаю, нет.

Браузер знает лучше, какие селекторы и классы используются — он же браузер! Он всегда знает, какой JavaScript выполнился, какой нет, какой CSS используется, какой нет.

Опять на помощь приходит Chrome DevTools protocol:

await Promise.all ( [
  page.coverage.startJSCoverage(), 
  page.coverage.startCSSCoverage()
]);

await page.goto(’https://example.com’);

const [jsCoverage, cssCoverage] = await Promise,all([ 
page.coverage.stopJSCoverage(), page.coverage.stopCSSCoverage()
]): 

В первых двух строчках запускаем сравнительно новую фичу, которая позволяет узнать покрытие кода. Запускаем JS и CSS, переходим на какую-то страничку, потом говорим — стоп — и можем посмотреть результаты. Причем это не какие-то мнимые результаты, а те, которые видит браузер именно за счет движка.

Помимо всего прочего, уже есть плагин, который для Puppeteer это все экспортирует в istanbul.

На вершине пирамиды Puppeteer находится скрипт, который вы написали на Node.js — он как крестный отец всем нижним пунктам.



Но… «не всё спокойно в датском королевстве...» — как писал Уильям Шекспир.

Что не так с безголовыми браузерами?


У безголовых браузеров есть проблемы несмотря на то, что все их крутые фичи могут так много.

Отличие в рендеринге страницы на разных платформах


Я очень люблю этот пункт и постоянно про это рассказываю. Давайте посмотрим на эту картинку.



Здесь обычная страничка с обычным текстом: справа — отрисовка в Chrome на Linux, слева — под Windows. Те, кто тестирует скриншотами, знают, что всегда устанавливается значение, называемое «порогом погрешности», которое определяет, когда скриншот считается идентичным, а когда нет.

На самом деле проблема в том, что как бы вы не старались установить этот порог, погрешность всегда будет выходить за эту грань, и вы все равно будете получать ложно позитивные результаты. Это связано с тем, что все страницы, и даже веб-шрифты рендерятся по-разному на всех трех платформах — на Windows по одному алгоритму, на MacOS по-другому, в Linux вообще зоопарк. Вы не можете просто взять и тестировать скриншотами.

Вы скажете: «Мне просто нужна эталонная машина, где я буду запускать все эти тесты и сравнивать скриншоты». Но на самом деле это дико неудобно, потому что вам придется ждать CI, а вы хотите здесь и сейчас локально на машине у себя проверить, не сломали ли вы что-нибудь. Если у вас эталонные скриншоты делаются на Linux-машине, а у вас Mac, то будут ложные результаты.

Поэтому я и говорю, что не тестируйте скриншотами вообще — забудьте это.

Кстати, если вы все-таки хотите тестировать скриншотами, есть замечательная статья Романа Дворнова "Unit-тестирование скриншотами: преодолеваем звуковой барьер". Это прямо детективное чтиво.

Блокировки


Многие крупные контент-провайдеры не любят, когда вы делаете scraping или получаете их контент нелегальным способом. Представим, что я крупный контент-провайдер, и хочу сыграть с вами в одну игру. Есть два GET-запроса в двух разных браузерах.


Сможете ли вы угадать, где здесь Chrome? Вариант «оба» не принимается — Chrome тут только один. Скорее всего, вы не сможете ответить на этот вопрос, а я, как крупный контент-провайдер, могу: справа — PhantomJS, а слева — Chrome.


Я могу дойти до такой степени, что буду обнаруживать ваши браузеры (что это именно — Chrome или FireFox) путем сопоставления порядка HTTP заголовков в ваших запросах. Если хост идет первым — я четко знаю — это Chrome. Дальше могу не сравнивать. Да, конечно, есть более сложные алгоритмы — мы проверяем не только порядок, но еще и значения, и т.д. и т.п. Но важен факт, что я могу слепками сравнивать ваши заголовки, проверять, кто вы есть, а потом просто блокировать вас или не блокировать.

Невозможно реализовать некоторые функции (Flash)


Вы когда-нибудь изучали углубленно, прямо хардкорно, Flash в браузерах? Как-то я заглянул — потом полгода не спал.

Все мы помним, как мы раньше смотрели YouTube, когда еще был Flash: ролик крутится, все хорошо. Но в тот момент, когда создается встраиваемый объект на странице типа Flash, он всегда запрашивает реальное окно у вашей ОС. То есть помимо окна вашего браузера, внутри YouTube-окошка Flash было еще одно окно вашей ОС. Flash не может работать, если вы не дадите ему реальное окно — причем не просто реальное окно, а окно, которое видно у вас на экране. Поэтому некоторые функции в безголовых браузерах реализовать невозможно, в том числе, Flash.

Полная автоматизация и боты


Как я уже сказал ранее, крупные контент-провайдеры очень боятся, когда вы пишите пауков или граббинги, которые просто крадут информацию, которая предоставляется платно.

В ход идут разные ухищрения. Есть статьи о том, как все-таки обнаруживать headless-браузеры. Могу сказать, что вы никак не сможете обнаружить headless-браузеры. Все методы, которые там описаны, обходятся. Например, там были способы обнаружения при помощи Canvas. Помню, даже был один скрипт, который смотрел, как движется мышка по экрану, и заполнял Canvas. Мы же люди и двигаем мышку довольно медленно, а Headless Chrome гораздо шустрее. Скрипт понимал, что слишком быстро заполняется Canvas — значит, это, скорее всего, безголовый Chrome. Мы это тоже обошли, просто замедлив браузер — не проблема.

Нет стандартного (единого) API


Если вы смотрели headless-реализации в других браузерах — будь это Safari или FireFox — там это все реализовано при помощи webdriver API. В Chrome есть Chrome DevTools protocol. В Edge вообще ничего не понятно — что там есть, чего нет.

WebGL?


Люди тоже просят WebGL в headless-режиме. По этой ссылке вы можете попасть на багтрекер Google Chrome. Там разработчики активно голосуют за реализацию headless-режима для WebGL, и уже он может что-то рисовать. Их сейчас просто сдерживает аппаратный рендеринг. Как только закончат реализацию аппаратного рендеринга, то и WebGL автоматически будет доступен, то есть что-то можно будет делать в фоне.

Но не все так плохо!

У нас появляется второй игрок на рынке — 11 мая 2018 была новость, что Microsoft в своем браузере Edge решил реализовать почти тот же самый протокол, который используется в Google Chrome. Они специально создали консорциум, где обсуждают протокол, который хотят довести до промышленного стандарта, чтобы вы могли взять свой скрипт и запустить его и под Edge, и под Chrome, и под FireFox.

Но есть одно «но» — у Microsoft Edge нет headless-режима, к сожалению. У них есть голосовалка, где люди пишут: «Дайте нам headless-режим!» — но они молчат. Наверное, что-то пилят втайне.

TODO (заключение)


Я рассказал это все для того, чтобы вы могли прийти к вашему менеджеру, или, если вы менеджер, к разработчику, и сказать: «Все! Мы не хотим больше Selenium — давайте нам Puppeteer! Будем в нем тестировать». Если это случится, я буду рад.

Но если вы сможете изучать, как и я, браузеры, используя Puppeteer, активно постить баги, или отправлять pull request, то я буду рад еще больше. Этот инструмент в OpenSource лежит на GitHub, написан на Node.js — вы можете просто в него брать и контрибьютить.

Случай с Puppeteer уникален тем, что в Google работает две команды: одна занимается именно Puppeteer, вторая — именно headless-режимом. Если пользователь находит баг, пишет о нем наа GitHub, то, если этот баг не в Puppeteer, а в Headless Chrome, баг переходит в команду Headless Chrome. Если они его там фиксят, то Puppeteer очень быстро обновляется. За счет этого получается единая экосистема, когда сообщество помогает улучшать браузер.

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

Контакты:

  • github.com/vitallium
  • vk.com/vitallium
  • twitter.com/vitalliumm

Frontend Conf Moscow — специализированная конференция фронтенд-разработчиков состоится 4 и 5 октября в Москве, в Инфопространстве. Список принятых докладов уже опубликован на сайте конференции.

В нашей рассылке мы регулярно делаем тематические обзоры выступлений, рассказываем о вышедших расшифровках и будущих мероприятиях — подписывайтесь, чтобы получать новости первым.

А это ссылка на наш Youtube-канал по фронтенду, там собраны все выступления, относящиеся к разработке клиентской части проектов.

Комментарии (11)


  1. x512
    05.09.2018 17:07

    Люди тоже просят WebGL в headless-режиме
    Он работает уже год в Headless без всяких проблем


  1. hdfan2
    05.09.2018 20:17

    У него нет реальной отрисовки содержимого, то есть он все отрисовывает в памяти.
    За счет этого он потребляет меньше памяти, потому что не нужно отрисовывать картинки или гигабайтные PNG

    Я не понял — так он отрисовывает в память или нет? Если да, то к чему тут пассаж про PNG?


    1. skoder
      05.09.2018 22:01

      Как я понимаю: он полностью размечает весь макет в памяти, размеры, шрифты. Все есть, все можно измерить. Но саму отрисовку всего этого он не делает, пока не запросишь метод скриншота


    1. petuhov_k
      06.09.2018 05:39

      И это утверждение тоже, мягко говоря, спорное:

      Он работает быстрее, потому что ему ничего не нужно отрисовывать на реальном экране.

      Отрисовка — копейки по сравнению с измерением текста и лэйаутом.


  1. skoder
    05.09.2018 22:04

    К тому же он знает размер картинок но распаковку jpeg в биты не производит


  1. Sadler
    06.09.2018 10:24
    +1

    Использую headless-режим через Selenium Python, переходить на Puppeteer не готов, т.к. не готов писать на языке, в котором количество async/await на строку > 0.5


    1. bro-dev0
      06.09.2018 17:33

      Можете колбэк хэлом писать по старинке, если я верно понял в питоне он и используется за неимением await.


  1. qwez
    06.09.2018 10:46

    Мы не хотим больше Selenium — давайте нам Puppeteer!

    Вот сделали бы сравнение — чем Puppeteer, по-вашему, лучше.
    Хотя, какие бы плюсы не нашлись, они вряд-ли перекроют эти два от Selenium: поддержка более одного браузера и громадное количество оберток для всех популярных ЯП.


    1. bro-dev0
      06.09.2018 17:34

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


  1. faiwer
    06.09.2018 11:00

    Вопрос к тем, кто активно использует Puppeteer: насколько сложно\тривиально с ним организовать тест для drag-n-drop? Можно написать что-нибудь вроде:


    mouse
      .mouseDown(...getNodeCoordinates(domNode))
      .mouseMove(deltaX, deltaY)
      .mouseUp()

    Ну и прочие хитрые штуки, вроде нативного drag-n-drop из ОС (типа перетаскивания файлов на панель). Есть ли поддержка zoom-а страницы? Удобно и вообще возможно работать с window.confirm, window.alert?


    1. Iqorek
      06.09.2018 16:44
      +1

      насколько сложно\тривиально с ним организовать тест для drag-n-drop?

      // Do drag-and-drop
      mouse.down(..);
      mouse.move(..);
      mouse.up(..);

      ©

      Ну и прочие хитрые штуки, вроде нативного drag-n-drop из ОС (типа перетаскивания файлов на панель).

      Вряд ли, все что там есть, это то что можно делать в хромиум.

      Есть ли поддержка zoom-а страницы?

      Можно задать deviceScaleFactor через page.setViewport(viewport)

      Удобно и вообще возможно работать с window.confirm, window.alert?

      Возможно