Тестирование маршрутов

Workbox предоставляет мощный набор инструментов для работы с сервис-воркерами, включая маршрутизацию запросов и кэширование ресурсов. Тестирование маршрутов — ключевой этап, позволяющий убедиться, что обработка сетевых запросов и кэширование происходят корректно в различных сценариях.

Создание тестовой среды

Для тестирования маршрутов необходимо имитировать поведение браузера и сети. Наиболее распространённый подход — использование ServiceWorkerGlobalScope в сочетании с библиотеками для мокирования fetch, например, с sinon или fetch-mock.

Пример настройки тестовой среды:

import { registerRoute } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';
import sinon from 'sinon';

let fetchStub;

beforeEach(() => {
  fetchStub = sinon.stub(self, 'fetch');
});

afterEach(() => {
  fetchStub.restore();
});

В этом коде fetchStub позволяет контролировать ответы на сетевые запросы, что критично для воспроизводимости тестов.

Тестирование маршрутов с конкретными стратегиями

Workbox позволяет назначать стратегии кэширования для отдельных маршрутов. Основные стратегии:

  • CacheFirst — сначала ищет ресурс в кэше, при отсутствии обращается к сети.
  • NetworkFirst — пытается получить ресурс из сети, при неудаче возвращает кэш.
  • StaleWhileRevalidate — возвращает кэш сразу, параллельно обновляя его через сеть.

Тестирование маршрута с CacheFirst:

registerRoute(
  ({url}) => url.pathname.startsWith('/images/'),
  new CacheFirst({
    cacheName: 'images-cache',
  })
);

it('должен возвращать кэшированный ресурс', async () => {
  const fakeResponse = new Response('image content');
  fetchStub.resolves(fakeResponse);

  const request = new Request('/images/photo.jpg');
  const response = await self.__WB_ROUTING__.handleRequest({request});

  sinon.assert.notCalled(fetchStub); // Проверка: fetch не вызван, ресурс из кэша
  const text = await response.text();
  assert.equal(text, 'image content');
});

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

Проверка условий маршрутов

Маршруты Workbox поддерживают гибкие условия выбора через функции-колбэки. Важно тестировать все возможные ветвления:

registerRoute(
  ({url, request}) => url.pathname.endsWith('.json') && request.method === 'GET',
  new NetworkFirst({cacheName: 'json-cache'})
);

it('не должен обрабатывать POST-запросы', async () => {
  const postRequest = new Request('/data/config.json', {method: 'POST'});
  const response = await self.__WB_ROUTING__.handleRequest({request: postRequest});
  assert.isUndefined(response); // POST запрос не подходит под маршрут
});

Это позволяет гарантировать, что маршруты не перехватывают нежелательные запросы.

Симуляция сетевых ошибок

Для стратегий NetworkFirst и StaleWhileRevalidate важно тестировать поведение при сбоях сети. Можно использовать мок-сервер или выбрасывать ошибки в fetchStub:

fetchStub.rejects(new Error('Network failure'));

const request = new Request('/data/info.json');
const response = await self.__WB_ROUTING__.handleRequest({request});

// Проверка fallback на кэш
assert.exists(response);

Тестирование таких сценариев предотвращает ошибки в реальных условиях, когда сеть нестабильна.

Валидация кэширования и очистки

Workbox предоставляет методы для управления кэшем (cacheName, expiration). Необходимо проверять, что ресурсы действительно попадают в кэш и корректно удаляются по условиям:

import { getCacheKeyForURL } from 'workbox-core';

it('должен сохранять ресурс в кэше', async () => {
  const request = new Request('/images/logo.png');
  await self.__WB_ROUTING__.handleRequest({request});

  const cache = await caches.open('images-cache');
  const cachedResponse = await cache.match(getCacheKeyForURL('/images/logo.png'));
  assert.exists(cachedResponse);
});

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

Интеграционное тестирование с Workbox Build

При использовании workbox-build можно создавать сервис-воркеры с предопределёнными маршрутизаторами. Тестирование таких воркеров требует симуляции полной среды браузера. Практически это делается через:

  • Workbox InjectManifest — интеграционные тесты на сгенерированном сервис-воркере.
  • Headless Browser (Puppeteer или Playwright) — проверка маршрутов в условиях настоящего браузера.

Пример интеграционного теста с Puppeteer:

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('http://localhost:3000');

const response = await page.evaluate(async () => {
  const res = await fetch('/images/banner.jpg');
  return res.text();
});

assert.equal(response, 'image content');
await browser.close();

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

Практические рекомендации

  • Всегда проверять как положительные, так и отрицательные сценарии маршрутов.
  • Разделять юнит-тесты стратегий и интеграционные тесты сервис-воркера.
  • Использовать мокирование сетевых запросов для детерминированности тестов.
  • Тестировать поведение при сбоях сети и истечении срока жизни кэша.

Тщательная проверка маршрутов обеспечивает стабильность кэширования и корректную работу сервис-воркера в различных условиях.