Тестирование Service Workers

Service Workers — это скрипты, работающие в фоновом режиме браузера, обеспечивающие функциональность оффлайн-приложений, кэширование ресурсов и управление сетевыми запросами. В контексте автоматизированного тестирования их присутствие создает дополнительные нюансы, которые необходимо учитывать при написании тестов на Protractor.


Подключение и настройка Protractor

Для тестирования приложений с Service Workers необходимо убедиться, что Protractor запускается с поддержкой современного браузера (Chrome, Edge), так как старые версии Selenium не полностью совместимы с Service Worker API. Конфигурация Protractor должна включать следующие параметры:

exports.config = {
    framework: 'jasmine',
    directConnect: true,
    capabilities: {
        browserName: 'chrome',
        chromeOptions: {
            args: ['--disable-web-security', '--allow-insecure-localhost']
        }
    },
    specs: ['tests/**/*.spec.js']
};

Важный момент: отключение некоторых механизмов безопасности может потребоваться для тестирования кэширования и оффлайн-режима без необходимости настройки HTTPS на локальной машине.


Проверка регистрации Service Worker

Service Worker регистрируется через navigator.serviceWorker.register(). В тестах важно проверить, что регистрация прошла успешно, прежде чем тестировать взаимодействие с кэшем или сетевыми запросами:

it('должен зарегистрировать Service Worker', async () => {
    await browser.get('http://localhost:4200');
    const isRegistered = await browser.executeScript(async () => {
        if ('serviceWorker' in navigator) {
            const registration = await navigator.serviceWorker.ready;
            return !!registration.active;
        }
        return false;
    });
    expect(isRegistered).toBe(true);
});

Ключевой момент: navigator.serviceWorker.ready возвращает промис, который разрешается только после полной активации Service Worker.


Тестирование оффлайн-режима

Service Workers позволяют симулировать оффлайн-режим. В Protractor это можно сделать через Chrome DevTools Protocol (CDP):

const cdp = await browser.driver.createCDPConnection('page');
await browser.driver.sendCDPCommand('Network.enable', {});
await browser.driver.sendCDPCommand('Network.emulateNetworkConditions', {
    offline: true,
    latency: 0,
    downloadThroughput: 0,
    uploadThroughput: 0
});

await browser.get('http://localhost:4200');
const offlineContent = await element(by.css('.offline-message')).getText();
expect(offlineContent).toContain('Вы оффлайн');

Особенность: обычный browser.get() при отключенном интернете может вызвать ошибку загрузки страницы. Service Worker должен быть активен для корректного отображения оффлайн-контента.


Очистка кэша и сброс Service Worker

Для стабильного тестирования важно уметь сбрасывать состояние Service Worker и кэша между тестами:

afterEach(async () => {
    await browser.executeScript(async () => {
        const registrations = await navigator.serviceWorker.getRegistrations();
        for (const reg of registrations) {
            await reg.unregister();
        }
        if (caches) {
            const cacheNames = await caches.keys();
            for (const name of cacheNames) {
                await caches.delete(name);
            }
        }
    });
});

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


Работа с сетевыми запросами и кэшированием

Service Worker может перехватывать сетевые запросы и отдавать кэшированные ответы. Для тестирования этого поведения можно использовать комбинацию browser.executeScript и стандартных методов Protractor для проверки DOM:

it('должен использовать кэш для запроса данных', async () => {
    await browser.get('http://localhost:4200/data-page');
    
    const dataText = await browser.executeScript(async () => {
        const response = await fetch('/api/data');
        return await response.text();
    });

    expect(dataText).toContain('Cached Data');
});

Важно: тест должен учитывать, что кэширование может быть асинхронным, поэтому ожидание через await обязательно.


Особенности взаимодействия с SPA

В одностраничных приложениях (SPA) Service Workers активно управляют маршрутами и ресурсами. Для Protractor это означает:

  • Проверка URL после навигации может не работать напрямую через browser.getCurrentUrl(), если Service Worker перехватывает запрос.
  • Для эмуляции перехода между страницами лучше использовать browser.executeScript(() => window.history.pushState(...)) и проверять DOM-элементы, а не URL.
  • Асинхронные события Service Worker могут требовать использования browser.wait для ожидания загрузки данных.

Логирование и отладка

Для сложных сценариев полезно логировать состояние Service Worker и кэша:

const logs = await browser.executeScript(async () => {
    const registrations = await navigator.serviceWorker.getRegistrations();
    return registrations.map(reg => ({
        scope: reg.scope,
        active: !!reg.active,
        installing: !!reg.installing,
        waiting: !!reg.waiting
    }));
});

console.table(logs);

Такой подход позволяет быстро выявлять проблемы с регистрацией или активацией Service Worker в тестовой среде.


Рекомендации по стабильности тестов

  • Использовать browser.wait для ожидания активации Service Worker перед выполнением теста.
  • Очистка кэша и перерегистрация Service Worker в beforeEach/afterEach.
  • Эмуляция сети через CDP вместо отключения интернета на уровне ОС.
  • Проверка асинхронного кэширования через промисы в executeScript.

Тщательное управление состоянием Service Worker и кэша обеспечивает надежное тестирование приложений с оффлайн-функциональностью, гарантируя воспроизводимость и независимость тестов при работе с Protractor.