DEV Community

Styrow.dev
Styrow.dev

Posted on Originally published at styrow.dev

How would you design an E2E test with Playwright to verify real-time WebSocket notifications, ensuring data integrity an

🚨 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
});
Enter fullscreen mode Exit fullscreen mode

🔑 Key Takeaways

  • ✅ Direct Interception: Use page.on('websocket') and ws.on('framereceived') to capture raw WebSocket data.
  • ✅ Event-Driven Waits: Employ expect.poll() or page.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 the ws.on('framereceived') event listener are fundamental.

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)