Моки для WebSocket

Cypress изначально ориентирован на тестирование веб-приложений через HTTP-запросы, однако современные приложения активно используют WebSocket для двусторонней коммуникации в реальном времени. Для полноценного тестирования необходимо уметь мокать WebSocket-соединения, контролировать входящие и исходящие сообщения и проверять реакцию интерфейса на события сервера.

Основные концепции мокирования WebSocket

WebSocket предоставляет постоянное соединение между клиентом и сервером, что отличается от привычного запроса-ответа HTTP. Мокирование WebSocket в Cypress включает несколько ключевых аспектов:

  • Перехват и подмена конструктора WebSocket. Вместо реального соединения используется объект-заменитель, который имитирует поведение сервера.
  • Отправка и получение сообщений. Тест должен контролировать, какие сообщения отправляются клиентом и какие приходят от «сервера».
  • События соединения: open, message, close, error. Они должны быть корректно вызваны мок-объектом для проверки реакций приложения.

Создание мок-объекта WebSocket

Для замены реального WebSocket в Cypress используется глобальная переопределение через cy.visit с опцией onBeforeLoad. Пример:

cy.visit('/app', {
  onBeforeLoad(win) {
    class MockWebSocket {
      constructor(url) {
        this.url = url;
        this.readyState = 1; // открытое соединение
        this.sentMessages = [];
        setTimeout(() => this.onopen && this.onopen(), 0);
      }

      send(message) {
        this.sentMessages.push(message);
        // Автоматический ответ сервера
        setTimeout(() => {
          if (this.onmessage) {
            this.onmessage({ data: `Echo: ${message}` });
          }
        }, 10);
      }

      close() {
        this.readyState = 3;
        if (this.onclose) this.onclose();
      }
    }

    win.WebSocket = MockWebSocket;
  }
});

Ключевые моменты:

  • Свойство readyState позволяет имитировать состояние соединения.
  • Массив sentMessages хранит все сообщения, отправленные клиентом, что облегчает проверку тестов.
  • Методы send и close вызывают соответствующие события onmessage и onclose, имитируя поведение настоящего WebSocket.

Тестирование отправки и получения сообщений

После подмены WebSocket можно писать тесты, проверяющие корректность работы интерфейса с реальным потоком сообщений:

it('Отправка и получение сообщений через WebSocket', () => {
  cy.get('#sendButton').click();
  cy.get('#messageInput').type('Hello{enter}');

  cy.window().then(win => {
    const ws = win.WebSocket.instances[0];
    expect(ws.sentMessages).to.include('Hello');
  });

  cy.get('#chatBox').should('contain.text', 'Echo: Hello');
});

Особенности подхода:

  • Хранение экземпляров WebSocket в win.WebSocket.instances позволяет тесту обращаться к конкретному соединению.
  • Асинхронные события message необходимо учитывать при проверках интерфейса, используя Cypress команды ожидания (should, then).

Симуляция ошибок и закрытия соединения

Для проверки устойчивости приложения важно уметь инициировать ошибки и закрытия соединения:

cy.window().then(win => {
  const ws = win.WebSocket.instances[0];
  ws.onerror && ws.onerror(new Event('error'));
  ws.onclose && ws.onclose({ code: 1006, reason: 'Server closed' });
});

cy.get('#status').should('contain.text', 'Disconnected');
  • onerror позволяет проверить обработку исключений.
  • onclose с кодом и причиной помогает тестировать восстановление соединения и уведомления пользователя.

Интеграция с существующими тестами Cypress

Мок WebSocket может быть интегрирован с другими Cypress инструментами:

  • cy.intercept для REST-запросов. Иногда необходимо одновременно мокировать HTTP и WebSocket.
  • Команды Cypress (cy.get, cy.contains, cy.wait) для проверки реакции UI на события WebSocket.
  • Комбинация нескольких мока для эмуляции сложной логики сервера, включая многократные ответы и задержки.

Рекомендации по организации моков

  • Создавать отдельный файл с классом MockWebSocket для переиспользования в разных тестах.
  • Вставлять мок до вызова приложения через onBeforeLoad, чтобы все соединения были перехвачены.
  • Для сложных сценариев использовать очередь событий и таймеры, имитируя реальные задержки сервера.
  • Проверять все пути событий: открытие соединения, получение сообщений, ошибки и закрытия.

Использование моков WebSocket в Cypress позволяет писать детальные, контролируемые и повторяемые тесты для приложений с реальным временем взаимодействия. Такой подход обеспечивает высокое покрытие тестами функционала, связанного с обменом данными в реальном времени, и помогает выявлять ошибки, которые не проявляются при простом тестировании через HTTP.