How can Playwright be used effectively for testing WebSocket-based pages, particularly for intercepting and asserting messages, when it lacks native WebSocket support?

@ivanc brought a technical challenge to our AMA on Playwright with @utchbe:

“In Playwright, what’s the best approach for testing pages primarily using the WebSocket protocol, including intercepting, sending, and asserting messages, especially when there’s no native WebSocket support?”

This question not only seeks to uncover advanced techniques in Playwright for WebSocket interactions but also opens the floor for shared experiences. If you’ve navigated similar challenges or have insights into this area, your contributions would greatly enrich our understanding of effective strategies in similar scenarios.

1 Like

Hi Sarah, Haven’t done that with playwright but In cypress we used a websocket server. I don’t have example code in public to share but see if these help.

const WebSocketServer = require(‘ws’);

We have the websocket server running as part of the test, the app is configured to use it and we have custom commands which broadcast messages to the websocket server.

You would need to understand your websocket to mock it.

The server is configured to listen for messages and returns certain responses:

ws.on(‘message’, async (data) => { …

eg const connectionStatusSuccess = {
jsonrpc: ‘2.0’,
result: {
ipAddress: ‘’,
port: ‘45678’,
connected: true,
success: true,
reason: ‘CONNECTED’,
},
};

Example custom command

const sendToWebSocket = (url: string, json: any): Promise<void> => {
  return new Promise((resolve, reject) => {
    const ws = new WebSocket(url);
    const timer = setTimeout(() => {
      reject(new Error('Timed out connecting to websocket server'));
      ws?.close();
    }, 5000);

    ws.onopen = () => {
      ws.send(JSON.stringify(json));
      ws.close();
      clearTimeout(timer);
      resolve();
    };
    ws.onerror = (error) => {
      // eslint-disable-next-line no-console
      console.log('Error connecting to websocket server');
      clearTimeout(timer);
      reject(error);
    };
  });
};

Cypress.Commands.add('broadcastMsg', async (call) => {
  actionBroadcastMsgJson.networkCall = call;
  await sendToWebSocket(serverURL, actionBroadcastMsgJson);
});
2 Likes

@ivanc Looks like playwright have just released ws support: https://www.youtube.com/watch?v=VGlkSBkMVCQ

Sample code below

test('ws test', async ({ page }) => {
        await page.routeWebSocket(/echo\.websocket\.org/, ws => {
            ws.send('Hello 2, server!');
            ws.send('Hello 3, server!');
            ws.onMessage(message => {
                console.log('Received message: ', message);
                ws.send('Hello, friend!');
            })
            const server = ws.connectToServer();
        
            server.onMessage(message => {
                ws.send('Hello 4, server!');
                console.log('Received Server: ', message);
            })
        })
        page.goto('https://echo.websocket.org/.ws');

        // Interact with the page's UI to send a WebSocket message
        await page.getByRole('button', { name: 'Pause Messaging' }).click();  // Clicking a button.
        await page.locator('#content').fill('Hello chatbot');  // Filling input with a message.
        await page.getByRole('button', { name: 'Send Message' }).click();  // Sending the message.

    });
1 Like