Автор: Хью МакКэмфилл (Hugh McCamphill) Оригинал статьи Перевод: Ольга Алифанова
У Lighthouse теперь есть новый API пути пользователя, позволяющий тестировать в лабораторных условиях в любой момент, пока существует страница. Он поддерживает генерацию Lighthouse-отчета из сценария Puppeteer, но я хотел посмотреть, как это получится при помощи WebdriverIO!
Зачем это, однако, делать?
Возможно, вы знаете, что WebdriverIO немного поддерживает тестирование производительности, задействуя также Chrome Devtools, но я считаю, что одно из огромных преимуществ Lighthouse – это генерируемый отчет, а не только сами показатели.
К тому же мы можем воспользоваться существующим кодом WebdriverIO для замеров в моменте и на отрезке времени – это тоже важные аспекты производительности фронтэнда.
Все примеры в статье ссылаются на web.dev/lighthouse-user-flows/#timespans, где можно увидеть оригинальный код Puppeteer и полученные отчеты Lighthouse; статья концентрируется на использовании WebdriverIO с Lighthouse.
Для начала разберемся, как выглядит базовый сценарий Puppeteer, совмещенный с новым API пути пользователя. Вот что мы имеем в примере web.dev/lighthouse-user-flows для базового анализа производительности загрузки страницы:
import fs from 'fs'; import open from 'open'; import puppeteer from 'puppeteer'; import { startFlow } from 'lighthouse/lighthouse-core/fraggle-rock/api.js'; async function captureReport() { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); const flow = await startFlow(page, {name: 'Single Navigation'}); await flow.navigate('https://web.dev/performance-scoring/'); await browser.close(); const report = flow.generateReport(); fs.writeFileSync('flow.report.html', report); open('flow.report.html', { wait: false }); } captureReport();
Чтобы сделать то же самое в WebdriverIO, нужно только вызвать Puppeteer и перейти на первую страницу:
const puppeteerBrowser = await browser.getPuppeteer(); const page = (await puppeteerBrowser.pages())[0];
WebdriverIO можно запустить в автономном режиме – большинство из вас знает, как это выглядит в тесте:
import fs from 'fs'; import open from 'open'; import { startFlow } from 'lighthouse/lighthouse-core/fraggle-rock/api.js'; describe('Lighthouse Performance ', () => { it('Should be able to generate lighthouse report with Webdriverio', async () => { const puppeteerBrowser = await browser.getPuppeteer(); const page = (await puppeteerBrowser.pages())[0]; const flow = await startFlow(page, {name: 'Single Navigation'}); await flow.navigate('https://web.dev/performance-scoring/'); await browser.close(); const report = flow.generateReport(); fs.writeFileSync('flow.report.html', report); open('flow.report.html', {wait: false}); } }
Однако тут нет никаких преимуществ перед прямым использованием Puppeteer. Это стоит использовать для вышеупомянутых замеров производительности в моменте или на отрезке времени, что даст нам (что спорно) более приятный синтаксис, а в идеале – задействование уже существующего кода WebdriverIO, который осуществит необходимые взаимодействия и навигацию.
К примеру, вместо:
async function captureReport() { const browser = await puppeteer.launch({headless: false}); const page = await browser.newPage(); const flow = await startFlow(page, {name: 'Squoosh snapshots'}); await page.goto('https://squoosh.app/', { waitUntil: 'networkidle0'} ); // Дождаться первой кнопки демо-изображения и открыть его const demoImageSelector = 'ul[class*="demos"] button'; await page.waitForSelector(demoImageSelector); await flow.snapshot({ stepName: 'Page loaded' }); await page.click(demoImageSelector); // Дождаться кнопки дополнительных настроек, открыть их const advancedSettingsSelector = 'form label[class*="option-reveal"]'; await page.waitForSelector(advancedSettingsSelector); await flow.snapshot({ stepName: 'Demo loaded' }); await page.click(advancedSettingsSelector); await flow.snapshot({ stepName: 'Advanced settings opened' }); browser.close(); const report = flow.generateReport(); fs.writeFileSync('flow.report.html', report); open('flow.report.html', {wait: false}); } captureReport();
можно написать код ниже, используя WebdriverIO для навигации и взаимодействия:
import fs from 'fs'; import open from 'open'; import { startFlow } from 'lighthouse/lighthouse-core/fraggle-rock/api.js'; describe('Lighthouse Performance ', () => { it('Should be able to generate lighthouse report with Webdriverio', async () => { const puppeteerBrowser = await browser.getPuppeteer(); const page = (await puppeteerBrowser.pages())[0]; const flow = await startFlow(page, {name: 'Single Navigation'}); await browser.url('https://squoosh.app/'); // Дождаться первой кнопки демо-изображения и открыть его const demoImageSelector = await $('ul[class*="demos"] button'); await demoImageSelector.waitForDisplayed(); await flow.snapshot({ stepName: 'Page loaded' }); await demoImageSelector.click(); // Дождаться кнопки дополнительных настроек, открыть их const advancedSettingsSelector = $('label[class*="option-reveal"]'); await advancedSettingsSelector.waitForDisplayed(); await flow.snapshot({ stepName: 'Demo loaded' }); await advancedSettingsSelector.click(); await flow.snapshot({ stepName: 'Advanced settings opened' }); const report = flow.generateReport(); fs.writeFileSync('flow.report.html', report); open('flow.report.html', { wait: false }); } }
Навигация тут, конечно, тривиальная; далее приведу пример оценки производительности на отрезке времени, сделанной в моей компании, Glofox – тут мы используем API приложений для настройки и данных, и ряда высокоуровневых путей, которые используют WebdriverIO под капотом:
describe('Dashboard Performance', () => { it('Lighthouse flow for booking class for member', async () => { const { className } = fakeData(); const puppeteerBrowser = await browser.getPuppeteer(); const page = (await puppeteerBrowser.pages())[0]; const flow = await startFlow(page); await flow.startTimespan({ stepName: 'Login' }); // WebdriverIO код выполняет первоначальную навигацию browser.url, заполняя данные на двух страницах await Dashboard.login(); await flow.endTimespan(); await flow.snapshot({ stepName: 'Logged in' }); // создать "участника" через API const member = new Member(); const { id: memberId } = await DashboardAPICalls.Members.create({ member }); // создать класс для бронирования участником через API await DashboardAPICalls.Classes.createClass({ className }); await flow.startTimespan({ stepName: 'Book Class' }); // забронировать класс через WebdriverIO – участвует множество страниц и кликов await Dashboard.bookClass({ member, className }); await flow.endTimespan(); } }
Надеюсь, этот пример продемонстрировал, как мы используем существующий код WebdriverIO (и абстракции API для настройки данных!), чтобы осуществить навигацию и взаимодействия, а затем провести анализ пути Lighthouse.
Заключение
Новый Lighthouse API пути пользователя дает дополнительные возможности для анализа пользовательской производительности фронтэнда – как показано в статье, можно получить выгоду от существующего кода WebdriverIO, используя его для необходимой навигации и заполнения форм. Встает вопрос, как прогонять такие тесты в пайплайне – но это тема для отдельной статьи. ПриложениеЕсли вы хотите запустить тест на компьютере, его конфигурацию можно передать в метод startFlow:
const config = require('lighthouse/lighthouse-core/config/desktop-config.js'); const puppeteerBrowser = await browser.getPuppeteer(); const page = (await puppeteerBrowser.pages())[0]; const flow = await startFlow(page, { config }); Обсудить в форуме |