How to test Websocket Client with Jest and react-testing-library
Asked Answered
G

2

9

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?

Girandole answered 29/11, 2019 at 8:29 Comment(1)
Great, this not being solves gives be great confidence...Telecommunication
O
3

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.

Ostensory answered 29/7, 2021 at 15:58 Comment(0)
B
0

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;

Buonaparte answered 31/3 at 16:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.