mock-socket icon indicating copy to clipboard operation
mock-socket copied to clipboard

Mock ws inside web worker

Open alexandrzavalii opened this issue 2 years ago • 3 comments

Currently mocking web sockets within web worker is not possible.

Window and global object within web worker is not shared

alexandrzavalii avatar Mar 21 '22 15:03 alexandrzavalii

What library do you use for testing workers? I can suggest creating another module for WebSocket (and import it from the worker) and trying to mock this module using jest or sinon if it works for you

Atrue avatar Mar 24 '22 14:03 Atrue

I am running the component in storybook and I do not mock workers. The only thing I need to be mocked is the websocket.

Window.WebSocket = WebSocket; will not mock the websocket inside worker.

So I wonder if there is a way around this problem.

I tried injecting WebSocket implementation from Window object to Worker but had no luck

alexandrzavalii avatar Mar 29 '22 11:03 alexandrzavalii

Anyway, it's not enough to mock the WebSocket, you need all the code inside the worker scope. So you need to have also a Server instance from this module and describe how it should work. So you can't manage it outside this worker. Just to note: when you create a Server instance the WebSocket is mocked automatically and is restored when you call server.stop()

You can try to inject some script using importScript that creates a Server instance from mock-socket (but you need to use importScript again for mock-socket). Or try worker modules to use es imports https://web.dev/module-workers/#enter-module-workers. But do not forget about the production, this code should not get there.

But I'd suggest changing the code a little bit to have the WebSocket in the main thread, so instead of sending and receiving the data to WebSocket it would send and receive events to the main thread. It'd have all the logic inside the worker, and it'd be possible to manage the WebSocket in the main thread, so you can mock it the same way:

/** 
 * main.js
 */
const worker = new Worker('...');
let websocket;

worker.onmessage = ({ data }) => {
    switch (data.type) {
        case 'connect': {
            websocket = new WebSocket(data.url);
            websocket.onmessage = msg => worker.postMessage({ type: 'message', data: msg.data });
            break;
        }
        case 'message': {
            websocket?.send(data.data);
            break;
        }
        case 'close': {
            websocket?.close();
            break;
        }
    }
}

/**
 * worker.js
 */
self.onmessage = ({ data }) => {
    if (data.type === 'message') {
        // handle websocket message;
    }
}
// create connection
self.postMessage({ type: 'connect', url: 'some-url '});

/**
 * test.js
 */
const mockServer = new Server('some-url');

mockServer.on('connection', socket => {
  socket.send('message');
});

Atrue avatar Apr 05 '22 08:04 Atrue