How to test your react websocket implementation with cypress

3 minutes read

Set up demo application

I scaffold a standard react application

$ npx create-react-app ws-demo

Clean up and update app.js to set up a websocket client.

app.js
import React, { useState } from "react";

const App = () => {
  const [message, setMessage] = useState("websocket is closed");

  return (
    

{message}

); }; export default App; // WebsocketHandler does what the name suggests - launch/close websocket client and receive messages const websocketUrl = "ws://127.0.0.1:5000"; const WebsocketHandler = ({ setMessage }) => { const ws = new WebSocket(websocketUrl); ws.onopen = () => { console.log("conn open"); ws.send("connection is open"); }; ws.onmessage = (message) => { setMessage(message.data); console.log("onmessage triggered", message); ws.send("message received"); }; ws.onclose = () => { console.log("connection closed"); }; return null; };

As highlighted, I have a WebsocketHandler component which handles websocket and sets state in app.js when it receives the message.

Set up and scaffold Cypress

Cypress is a fantastic testing framework. It is easy to set up and can be picked up pretty quickly.

Setting up Cypress is pretty straight forward - just run:

$ npm install cypress
or
$ yarn add cypress

I will also install the recommended dependency

$ npm install -D start-server-and-test

start-server-and-test is a cool tool that basically

Starts server, waits for URL, then runs test command; when the tests end, shuts down server

as explained on their github repo.

I install that package and use it in the package.json script -

package.json
"cy:test": "start-server-and-test start http://localhost:3001 cy:open"

Install the manual-web-socket package

I am going to install a websocket testing package manual-web-socket ( github ) and use it.

Writing the test

My Cypress test will follow the following steps-

  • Require manual-web-socket package
  • Use the nifty onBeforeLoad to access websocket services and attach them to our beloved win object in cypress
  • Finally, set up a mock connection
    • Change connection status to OPEN
    • send a message, and assert that it shows up in our react app

The test itself (with comments) -

cypress/integration/websocket-testing.js
/// 

const manualWebSocket = require("manual-web-socket"); // import the package

describe("Tests websocket", () => {
  it("Successfully processes websocket message from server", () => {
    cy.visit("/")
      .get("[id=websocket]")
      .should("have.text", "websocket is closed");

    cy.visit("/", {
      onBeforeLoad(win) {
        var script = win.document.createElement("script");
        script.innerText = manualWebSocket.getScript();
        win.document.head.appendChild(script);
        win.mws.track(["ws://127.0.0.1:5000"]); // we start tracking ws connection here
      },
    }).then((win) => {
      const mws = win.mws;
      const trackedConnection = mws.trackedConnections.getByUrl(
        // get connection by URL
        "ws://127.0.0.1:5000"
      );
      trackedConnection.readyState = mws.readyState.OPEN; // set the ws state to OPEN
      const connOpenMessage = "connection open with client";
      const payload = { data: "Cypress is connected via websocket" };
      trackedConnection.addServerScenario(
        // addServerScenario to mock ws server on the other side
        "connection open with client",
        (connection, message) => {
          connection.reciveMessage(payload);
        }
      );
      trackedConnection.send(connOpenMessage); // send message to ws client
      cy.get("[id=websocket]").should(
        "have.text",
        "Cypress is connected via websocket" // Assert the change in client state
      );
      trackedConnection.readyState = mws.readyState.CLOSED; // close ws connection
    });
  });
});

The test goes green.