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.
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 -
"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-socketpackage - Use the nifty
onBeforeLoadto access websocket services and attach them to our belovedwinobject 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) -
///
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.