🚨 E2E Test Challenge: Verifying Real-time WebSockets with Playwright?
How do you ensure data integrity and timely delivery in high-concurrency environments without flaky tests?
📌 Problem Statement
Verifying real-time WebSocket notifications in E2E tests is tricky. Traditional UI polling often misses ephemeral messages or leads to flakiness. High-concurrency environments add complexity, demanding precise synchronization and robust data integrity checks.
- ❌ Polling UI elements: Inefficient, introduces delays, often misses transient states.
- ❌ Race conditions: Tests complete before WebSocket messages are received.
- ❌ Data integrity loss: Difficulty in capturing and validating the exact message payload.
💡 Solution & Code Walkthrough
A robust Playwright strategy leverages its powerful low-level API to directly intercept WebSocket traffic and implement event-driven synchronization.
• Strategy: Intercept WebSocket framereceived events, store relevant messages, then assert their presence and content.
import { test, expect } from '@playwright/test';
test('verify real-time WS notification data', async ({ page }) => {
const expectedMessageContent = 'OrderProcessed_#123';
let receivedNotification: any = null; // Stores the captured message
// ✅ Step 1: Listen for WebSocket frames
page.on('websocket', ws => {
ws.on('framereceived', frame => {
try {
const data = JSON.parse(frame.payload.toString());
// Filter for specific notification type/content
if (data.type === 'orderUpdate' && data.payload.id === '123') {
receivedNotification = data; // Store relevant data
}
} catch (e) {
// Ignore non-JSON or irrelevant frames
}
});
});
await page.goto('https://your-app.com/dashboard'); // Navigate to trigger WS connection
await page.locator('#process-order-button').click(); // Action that triggers WS notification
// ✅ Step 2: Event-driven synchronization - Poll until message is received
await expect.poll(() => receivedNotification, { timeout: 15000 })
.not.toBeNull();
// ✅ Step 3: Assert data integrity and timely delivery
expect(receivedNotification.payload.id).toBe('123');
expect(receivedNotification.payload.status).toBe('processed');
expect(typeof receivedNotification.timestamp).toBe('number');
// ... further payload validation as needed
});
🔑 Key Takeaways
- ✅ Direct Interception: Use
page.on('websocket')andws.on('framereceived')to capture raw WebSocket data. - ✅ Event-Driven Waits: Employ
expect.poll()orpage.waitForEvent()with custom logic to precisely wait for expected messages, reducing flakiness. - ✅ Data Validation: Parse and assert the full payload structure for complete data integrity.
- • Test Isolation: Ensure each test uses unique identifiers to prevent cross-test contamination, crucial in high-concurrency setups.
❓ Quick Summary Q&A
- Q: Why not just check the UI after an action?
- A: UI updates can be delayed or might not reflect all intermediate WebSocket states. Direct interception is more robust.
- Q: What Playwright API is crucial here?
- A:
page.on('websocket')and thews.on('framereceived')event listener are fundamental.
- A:
TAGS: playwright, websocket, e2e, testing, automation, real-time, qa, typescript
────────────────────────────────────────
Download our Mobile App Today!
────────────────────────────────────────
📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&𝐀𝐬
Practice real-world interview scenarios offline on the free QA Automation & SDET Prep app:
🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):
https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261022
🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):
https://apps.apple.com/app/id6786760948?pt=128640464&ct=devto_selenium_20261022&mt=8
────────────────────────────────────────
────────────────────────────────────────
Top comments (0)