WebSockets предоставляют двусторонний канал связи между клиентом и сервером, что делает их популярными для приложений реального времени, таких как чаты, игровые платформы и торговые системы. В тестировании таких приложений стандартные методы работы с DOM и HTTP-запросами часто оказываются недостаточными, поэтому Protractor требует дополнительных подходов для взаимодействия с WebSocket-соединениями.
Protractor изначально предназначен для работы с Angular-приложениями
и синхронизации с Angular-зоной. Для тестирования WebSocket важно
убедиться, что асинхронные операции корректно обрабатываются. Основной
инструмент — использование async/await и вспомогательных
библиотек для работы с WebSocket, таких как ws или
socket.io-client.
Пример подключения к WebSocket через
socket.io-client:
const io = require('socket.io-client');
let socket;
beforeEach(async () => {
socket = io('http://localhost:3000');
await new Promise(resolve => socket.once('connect', resolve));
});
afterEach(() => {
if (socket.connected) {
socket.disconnect();
}
});
Ключевой момент — гарантировать установку соединения до выполнения
тестов. Protractor будет ждать завершения await и не
продолжит выполнение, пока соединение не установлено.
После установления соединения необходимо тестировать как отправку, так и получение сообщений. WebSocket-сообщения могут приходить с задержкой, поэтому важно использовать ожидания с тайм-аутами.
Пример проверки получения сообщения:
it('should receive a greeting message from the server', async () => {
socket.emit('hello', { name: 'Protractor' });
const message = await new Promise(resolve => {
socket.on('greeting', resolve);
});
expect(message.text).toEqual('Hello, Protractor!');
});
Здесь используется промис для ожидания события, что позволяет интегрировать WebSocket-логику в асинхронный поток теста.
В реальных приложениях WebSocket часто передаёт несколько типов событий одновременно. Для тестирования таких сценариев полезно реализовать хранилище полученных сообщений и фильтровать их по типу события:
let messages = [];
beforeEach(() => {
messages = [];
socket.on('update', msg => messages.push({ type: 'update', data: msg }));
socket.on('notification', msg => messages.push({ type: 'notification', data: msg }));
});
it('should handle multiple events correctly', async () => {
socket.emit('triggerEvents');
await browser.sleep(1000); // ожидание прихода событий
const updates = messages.filter(m => m.type === 'update');
const notifications = messages.filter(m => m.type === 'notification');
expect(updates.length).toBeGreaterThan(0);
expect(notifications.length).toBeGreaterThan(0);
});
Использование временной задержки (browser.sleep)
допускается для тестирования потоковых событий, но рекомендуется
минимизировать её и применять ожидания на основе фактического
события.
Для Angular-приложений важно, чтобы Protractor правильно
синхронизировал асинхронные операции WebSocket с зоной Angular. Если
события WebSocket изменяют состояние приложения, которое отображается в
DOM, нужно использовать browser.wait или
ExpectedConditions:
const EC = protractor.ExpectedConditions;
it('should update the DOM after receiving a WebSocket message', async () => {
socket.emit('updateDOM');
const elementToUpdate = element(by.id('status'));
await browser.wait(EC.textToBePresentInElement(elementToUpdate, 'Updated'), 5000);
const text = await elementToUpdate.getText();
expect(text).toEqual('Updated');
});
Такой подход обеспечивает корректное ожидание обновлений интерфейса без использования жёстких задержек и повышает стабильность тестов.
WebSocket-тесты часто сложно отлаживать из-за асинхронной природы. Рекомендуется логировать все события и отправляемые сообщения:
socket.onAny((event, payload) => {
console.log(`[WebSocket] Event: ${event}, Data:`, payload);
});
Это позволяет видеть последовательность событий и выявлять пропуски или задержки в тестируемой логике.
При запуске нескольких тестов параллельно важно закрывать все
WebSocket-соединения, чтобы избежать конфликтов и утечек памяти. Каждый
тест должен создавать отдельный экземпляр сокета и корректно его
отключать в afterEach. В сложных сценариях можно
использовать фабрики подключения, возвращающие уникальные сокеты для
каждого теста.
async/await вместо колбэков для читаемости
и стабильности тестов.Тщательная организация тестов WebSocket в Protractor позволяет проверять не только корректность обмена данными, но и интеграцию сообщений с DOM и бизнес-логикой приложения, обеспечивая высокое качество тестирования реального времени.