Интеграционные тесты с реальным браузером через Playwright

Web Vitals — это набор показателей, отражающих качество пользовательского опыта на веб-странице. В JavaScript их можно измерять с помощью официальной библиотеки web-vitals, которая предоставляет API для отслеживания ключевых метрик:

  • LCP (Largest Contentful Paint) — время рендеринга наибольшего блока контента.
  • FID (First Input Delay) — задержка между взаимодействием пользователя и обработкой события.
  • CLS (Cumulative Layout Shift) — суммарное смещение элементов страницы.
  • TTFB (Time to First Byte) — время до получения первого байта от сервера.
  • INP (Interaction to Next Paint) — измеряет задержку обработки всех взаимодействий страницы (новая метрика, расширяющая FID).

Библиотека Web Vitals экспортирует функции getLCP, getFID, getCLS, getTTFB, getINP, каждая из которых принимает callback, в который передаётся объект с данными метрики, включая значения в миллисекундах и дополнительные детали.


Установка и базовая интеграция

import { getLCP, getFID, getCLS } from 'web-vitals';

getLCP(metric => {
  console.log('LCP:', metric.value);
});

getFID(metric => {
  console.log('FID:', metric.value);
});

getCLS(metric => {
  console.log('CLS:', metric.value);
});

Функции автоматически начинают измерения при загрузке страницы и вызывают callback при получении данных. Для более сложного анализа можно собирать результаты в массив и отправлять на сервер аналитики.


Интеграционные тесты с Playwright

Playwright позволяет запускать полноценные браузерные сессии и взаимодействовать с реальным DOM, что делает его идеальным инструментом для интеграционных тестов Web Vitals.

Настройка окружения

  1. Установить Playwright и Web Vitals:
npm install playwright web-vitals
  1. Создать тестовую структуру:
// tests/webVitals.spec.js
const { test, expect } = require('@playwright/test');

test('измерение Web Vitals', async ({ page }) => {
  await page.goto('https://example.com');

  const metrics = await page.evaluate(() => {
    return new Promise(resolve => {
      const results = {};
      import('web-vitals').then(({ getLCP, getFID, getCLS }) => {
        getLCP(metric => { results.lcp = metric.value; checkComplete(); });
        getFID(metric => { results.fid = metric.value; checkComplete(); });
        getCLS(metric => { results.cls = metric.value; checkComplete(); });

        let count = 0;
        function checkComplete() {
          count++;
          if (count === 3) resolve(results);
        }
      });
    });
  });

  console.log('Web Vitals metrics:', metrics);
  expect(metrics.lcp).toBeGreaterThan(0);
  expect(metrics.fid).toBeGreaterThanOrEqual(0);
  expect(metrics.cls).toBeLessThan(0.25);
});

В этом примере создаётся асинхронный Promise, который ждёт все три метрики (LCP, FID, CLS) и возвращает их в тест. Это позволяет использовать реальные значения, полученные при рендеринге страницы.


Учет различных сценариев

При интеграционных тестах важно учитывать:

  • Асинхронную природу метрик: LCP и CLS могут обновляться несколько раз, необходимо аккуратно агрегировать данные.
  • Влияние динамического контента: элементы, добавленные через JavaScript после загрузки, могут увеличивать CLS.
  • Разные устройства и сети: тестирование Web Vitals на эмуляции медленного соединения или слабого процессора позволяет выявить реальные узкие места.
await page.emulateNetworkConditions({
  offline: false,
  downloadThroughput: 500 * 1024 / 8,
  uploadThroughput: 500 * 1024 / 8,
  latency: 200,
});

Сбор данных и аналитика

После получения метрик их можно сохранять для последующего анализа:

const metrics = await page.evaluate(() => window.__WEB_VITALS_METRICS__);
await saveMetricsToDB(metrics);

Рекомендуется хранить:

  • Значение метрики (value)
  • Тип метрики (name)
  • Время измерения (startTime)
  • Дополнительные детали (entries)

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


Тонкости тестирования

  • Совмещение Web Vitals и Playwright tracing: включение трейсинга (page.tracing.start() / page.tracing.stop()) помогает визуально анализировать проблемы рендеринга.
  • Динамическое ожидание: важно давать странице достаточно времени для рендеринга и взаимодействий перед завершением теста, иначе метрики LCP и CLS могут быть неполными.
  • Изоляция тестов: каждый тест должен запускаться на чистой сессии браузера, чтобы результаты не смешивались между страницами.
test.beforeEach(async ({ browser }) => {
  const context = await browser.newContext();
  const page = await context.newPage();
});

Продвинутая агрегация метрик

Для построения комплексных тестов можно комбинировать метрики:

  • Суммарный CLS на сессию: складывать CLS с разных страниц.
  • Средний LCP: вычислять среднее значение по нескольким заходам на страницу.
  • Сравнение FID и INP: выявлять страницы с плохой отзывчивостью интерфейса.
const aggregatedMetrics = metricsArray.reduce((acc, metric) => {
  acc.lcp += metric.lcp;
  acc.fid = Math.max(acc.fid, metric.fid);
  acc.cls += metric.cls;
  return acc;
}, { lcp: 0, fid: 0, cls: 0 });

Такой подход позволяет создавать систематическую базу данных по производительности интерфейса, пригодную для CI/CD тестов и мониторинга после релиза.