Reputation: 3908
I'm using create-react-app, Jest and react-testing-library for the configuration of the chatbot project.
I have a React functional component that connects to a WebSocket server and DOM changes according to WebSocket messages, for example
const LiveChat = () => {
const [socket, setSocket] = useState(null)
useEffect(() => {
setSocket(new WebSocket('ws://localhost:1234'))
}, [])
useEffect(() => {
socket && socket.onmessage = message => { handleAgentMessages(message.data) }
}, [socket])
const handleAgentMessages = message => {
const { messageContent, messageType, secureKey } = JSON.parse(message)
if (messageType === TEXT && messageContent) {
alert(messageContent)
playChatMessageSound()
}
...
}
return (
<div className='live-chat' data-testid='live-chat'>
...
</div>
)
}
I want to test when a TEXT message comes, is alertbox appeared with conteining message etc. I have looked through the internet and I find jest-websocket-mock library, but it seems that I need to mock the client with this library as well, but I just want to mock server and expect the client to connect the mocked WebSocket server, do you have any ideas?
Upvotes: 9
Views: 6289
Reputation: 1337
Another way to do this is to inject the web socket server into a custom Jest environment. I had to do this due to Websocket is not a constructor
error.
In your jest.config.js file
...
testEnvironment: "./custom-dom-environment.",
...
custom-dom-environment.js
// my-custom-environment
const JsDomEnvironment = require('jest-environment-jsdom').TestEnvironment;
class CustomEnvironment extends JsDomEnvironment {
constructor(config, context) {
super(config, context);
}
async setup() {
await super.setup();
// Allow setting up a websocket server in jsdom environment
this.global.WebSocketServer = require('ws');
}
async teardown() {
await super.teardown();
}
getVmContext() {
return super.getVmContext();
}
}
module.exports = CustomEnvironment;
Upvotes: 0
Reputation: 584
I am not sure if this is the right way or not. But this works for me,
global.sendMsg = null;
global.WebSocket = class extends WebSocket {
constructor(url) {
super("wss://test");
global.sendMsg = null
}
addEventListener(event, cb) {
if (event === "open") {
cb();
} else if(event === "message") {
global.sendMsg = cb;
}
}
};
test("testing message",() => {
render(<LiveChat />);
global.sendMsg({data:"test-msg"});
expect....
})
Basically, I overwrote the WebSocket class and stored the message event callback to a constant, and trigger it on the tests to imitate the server message.
Upvotes: 4