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 (
<div className="App">
<p id="websocket">{message}</p>
<WebsocketHandler setMessage={setMessage} />
</div>
)
}
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-socket
package - Use the nifty
onBeforeLoad
to access websocket services and attach them to our belovedwin
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) -
/// <reference types="Cypress" />
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.