Skip to content

Aditya Naik

How to test your react websocket implementation using cypress

React, Websocket, Cypress1 min read

Set up demo application

I scaffold a standard react application

1$ npx create-react-app ws-demo

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

app.js
1import React, { useState } from 'react'
2
3const App = () => {
4 const [message, setMessage] = useState('websocket is closed')
5
6 return (
7 <div className="App">
8 <p id="websocket">{message}</p>
9 <WebsocketHandler setMessage={setMessage} />
10 </div>
11 )
12}
13
14export default App
15
16// WebsocketHandler does what the name suggests - launch/close websocket client and receive messages
17
18const websocketUrl = 'ws://127.0.0.1:5000'
19const WebsocketHandler = ({ setMessage }) => {
20 const ws = new WebSocket(websocketUrl)
21 ws.onopen = () => {
22 console.log('conn open')
23 ws.send('connection is open')
24 }
25 ws.onmessage = (message) => {
26 setMessage(message.data)
27 console.log('onmessage triggered', message)
28 ws.send('message received')
29 }
30 ws.onclose = () => {
31 console.log('connection closed')
32 }
33 return null
34}

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:

1$ npm install cypress
2or
3$ yarn add cypress

I will also install the recommended dependency

1$ 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
1"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
1/// <reference types="Cypress" />
2
3const manualWebSocket = require('manual-web-socket') // import the package
4
5describe('Tests websocket', () => {
6 it('Successfully processes websocket message from server', () => {
7 cy.visit('/')
8 .get('[id=websocket]')
9 .should('have.text', 'websocket is closed')
10
11 cy.visit('/', {
12 onBeforeLoad(win) {
13 var script = win.document.createElement('script')
14 script.innerText = manualWebSocket.getScript()
15 win.document.head.appendChild(script)
16 win.mws.track(['ws://127.0.0.1:5000']) // we start tracking ws connection here
17 },
18 }).then((win) => {
19 const mws = win.mws
20 const trackedConnection = mws.trackedConnections.getByUrl(
21 // get connection by URL
22 'ws://127.0.0.1:5000'
23 )
24 trackedConnection.readyState = mws.readyState.OPEN // set the ws state to OPEN
25 const connOpenMessage = 'connection open with client'
26 const payload = { data: 'Cypress is connected via websocket' }
27 trackedConnection.addServerScenario(
28 // addServerScenario to mock ws server on the other side
29 'connection open with client',
30 (connection, message) => {
31 connection.reciveMessage(payload)
32 }
33 )
34 trackedConnection.send(connOpenMessage) // send message to ws client
35 cy.get('[id=websocket]').should(
36 'have.text',
37 'Cypress is connected via websocket' // Assert the change in client state
38 )
39 trackedConnection.readyState = mws.readyState.CLOSED // close ws connection
40 })
41 })
42})

The test goes green.

© 2020 by Aditya Naik. All rights reserved.