fetch-network-simulator: стресс-тестируем фронтенд в неидеальных условиях

#frontend#testing#fetch#network#devtools

TL;DR

fetch-network-simulator — это инструмент для эмуляции нестабильного сетевого окружения прямо в dev-среде. Перехватывает fetch(), подмешивает латентность, потерю пакетов, ретраи, race conditions и bandwidth throttling. Незаменим для отлова timing-dependent багов, которые не проявляются при идеальном соединении.

Введение: зачем симулировать проблемы сети?

В 2024 году фронтенд-разработчики столкнулись с парадоксом:

Проблема в нелинейности сетевых условий. Традиционные моки и стабы не покрывают:

Основная часть: как работает симулятор

Перехват fetch()

Ядро системы — Proxy API для перехвата нативных запросов:

const originalFetch = window.fetch;
window.fetch = async (...args) => {
  if (shouldSimulateNetwork()) {
    return applyNetworkChaos(...args);
  }
  return originalFetch(...args);
};

Конфигурируемые параметры

NetworkSimulator.configure({
  latency: { min: 100, max: 2000 }, // ms
  packetLoss: 0.05, // 5% запросов теряются
  concurrencyLimit: 6, // HTTP/1.1-like limit
  retryPolicy: {
    maxAttempts: 3,
    backoff: 'exponential'
  }
});

Эмуляция race conditions

Симулятор вводит искусственную недетерминированность:

async function applyRaceConditions(responsePromise) {
  await randomDelay();
  if (Math.random() < config.raceProbability) {
    return simulateStaleResponse();
  }
  return responsePromise;
}

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

Тестирование Skeleton UI

Пример проверки загрузочных состояний:

describe('ProfilePage loading states', () => {
  beforeAll(() => {
    NetworkSimulator.configure({ latency: { min: 800, max: 1500 } });
  });

  it('shows skeleton for at least 500ms', async () => {
    const { queryByTestId } = render(<ProfilePage />);
    expect(queryByTestId('skeleton')).toBeInTheDocument();
    await act(async () => {
      await new Promise(r => setTimeout(r, 500));
    });
    expect(queryByTestId('skeleton')).toBeInTheDocument();
  });
});

Воспроизведение багов с конкурентными запросами

// Эмулируем HTTP/1.1 pipeline head-of-line blocking
NetworkSimulator.configure({
  concurrencyLimit: 2,
  requestQueue: 'fifo'
});

// Теперь можно отловить deadlock в цепочке запросов:
fetch('/api/user');
fetch('/api/posts');
fetch('/api/comments'); // Этот запрос заблокируется

Заключение

fetch-network-simulator закрывает критический gap в фронтенд-тестировании — невозможность воспроизвести сетевые аномалии в контролируемой среде. Инструмент особенно полезен для:

  1. Разработки resilient-архитектур
  2. Тестирования Progressive Enhancement стратегий
  3. Валидации UX в экстремальных условиях

Для глубокой интеграции рекомендую комбинировать с:

Просто помните: если ваш код работает под fetch-network-simulator, он с большой вероятностью выживет и в диком проде.


Источник: https://github.com/thisiskps/fetch-network-simulator