最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How to mock websocket when using ws library in typescript? - Stack Overflow

programmeradmin0浏览0评论

I am using typescript "typescript": "^5.7.3" for a nodejs backend project

and

"ws": "^8.18.0"
"jest": "^29.7.0",
"ts-jest": "^29.2.5",

I tried using the testing library

jest-websocket-mock

used mocks under __tests__ folder with

ws.ts

export { WebSocket as default } from 'mock-socket';

This didn' work because on function doesn't exist on mock-socket Websocket

TypeError: ws_2.on is not a function

Any other ideas on the best way to mock when using ws library ?

My unfinished test code looked like

MyClient.test.ts this would listen to some price api in real life

import WS from 'jest-websocket-mock';

describe('test', () => {
    let server: WS;

    beforeEach(async () => {
        server = new WS('ws://localhost:1234');
    });

    afterEach(() => {
        WS.clean();
    });

    it('example test ws', async () => {
        myClient = new MyClient({
            socketUrl: 'ws://localhost:1234',
        });
        myClient.listenForPrices();
    });
});

and somewhere else MyClient.ts

import WebSocket from 'ws';

export default class MyClient {
    // eslint-disable-next-line no-useless-constructor
    constructor(private readonly config: { solanaWebsocketUrl: string }) {}

    async listenForPrice() {
        try {
            const ws = new WebSocket(this.config.solanaWebsocketUrl);

            ws.on('open', () => {
                const subscriptionMessage = JSON.stringify({
                    jsonrpc: '2.0',
                    id: 1,
                    method: 'listenPrice',
                });
                ws.send(subscriptionMessage);
            });

            ws.on('message', message => {
                const data = JSON.parse(message.toString());
                console.log('newMessage', message);
            });

            ws.on('error', error => {
                console.log(error);
            });

            ws.on('close', async () => {
                await setTimeout(() => {
                    this.listenForPrice();
                }, 5000);
            });
        } catch (error) {
            await setTimeout(() => {
                this.listenForPrice();
            }, 5000);
        }
    }
}

I am using typescript "typescript": "^5.7.3" for a nodejs backend project

and

"ws": "^8.18.0"
"jest": "^29.7.0",
"ts-jest": "^29.2.5",

I tried using the testing library

jest-websocket-mock

used mocks under __tests__ folder with

ws.ts

export { WebSocket as default } from 'mock-socket';

This didn' work because on function doesn't exist on mock-socket Websocket

TypeError: ws_2.on is not a function

Any other ideas on the best way to mock when using ws library ?

My unfinished test code looked like

MyClient.test.ts this would listen to some price api in real life

import WS from 'jest-websocket-mock';

describe('test', () => {
    let server: WS;

    beforeEach(async () => {
        server = new WS('ws://localhost:1234');
    });

    afterEach(() => {
        WS.clean();
    });

    it('example test ws', async () => {
        myClient = new MyClient({
            socketUrl: 'ws://localhost:1234',
        });
        myClient.listenForPrices();
    });
});

and somewhere else MyClient.ts

import WebSocket from 'ws';

export default class MyClient {
    // eslint-disable-next-line no-useless-constructor
    constructor(private readonly config: { solanaWebsocketUrl: string }) {}

    async listenForPrice() {
        try {
            const ws = new WebSocket(this.config.solanaWebsocketUrl);

            ws.on('open', () => {
                const subscriptionMessage = JSON.stringify({
                    jsonrpc: '2.0',
                    id: 1,
                    method: 'listenPrice',
                });
                ws.send(subscriptionMessage);
            });

            ws.on('message', message => {
                const data = JSON.parse(message.toString());
                console.log('newMessage', message);
            });

            ws.on('error', error => {
                console.log(error);
            });

            ws.on('close', async () => {
                await setTimeout(() => {
                    this.listenForPrice();
                }, 5000);
            });
        } catch (error) {
            await setTimeout(() => {
                this.listenForPrice();
            }, 5000);
        }
    }
}

Share Improve this question edited Feb 3 at 11:35 Kristi Jji asked Feb 2 at 17:53 Kristi JjiKristi Jji 1,7394 gold badges28 silver badges62 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

There is no library solution for mocking ws Websocket for nodejs and supporting on function.

I had to write a custom solution, a custom mock under __mocks__/ws.ts

import { WebSocket as MockWebSocket } from 'mock-socket';

class CustomMockWebSocket extends MockWebSocket {
    // Store event listeners
    listeners: { [key: string]: Function[] } = {};
    static sendMockFn = jest.fn();

    // eslint-disable-next-line no-useless-constructor
    constructor(url: string) {
        super(url);
    }

    // Override the `on()` method to support custom event listeners
    public on(event: string, callback: Function): void {
        // Initialize the event listener array if not already present
        if (!this.listeners[event]) {
            this.listeners[event] = [];
        }
        // Add the event listener
        this.listeners[event].push(callback);

        // Call the corresponding `super` method if needed
        if (event === 'open' && this.readyState === WebSocket.OPEN) {
            callback();
        }
    }

    // Override the dispatch of events so that the custom listeners are called
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    public trigger(event: string, ...args: any[]): void {
        // Call all listeners for this event
        if (this.listeners[event]) {
            this.listeners[event].forEach(listener => {
                listener(...args);
            });
        }
    }

    // You can mock other WebSocket behavior if necessary (e.g., send, close)
    public send(data: string | Blob | ArrayBuffer | ArrayBufferView): void {
        console.log('Mock sending data:', data);
        CustomMockWebSocket.sendMockFn(...arguments);
    }

    // You can also mock the close event and trigger the listeners for 'close'
    public close(): void {
        console.log('Mock WebSocket closed');
        this.trigger('close');
    }
}

// Export the extended WebSocket class
export { CustomMockWebSocket as default };

With this solution I can test anything, can verify that my websocket client really send data, example:

        expect(CustomMockWebSocket.sendMockFn).toHaveBeenCalledTimes(1);
        expect(CustomMockWebSocket.sendMockFn.mock.calls[0]).toEqual([
            '{"jsonrpc":"2.0","id":1,"method":"blabla","params":[{"mentions":["test"]},{"commitment":"processed"}]}',
        ]);

I can also use import WS from 'jest-websocket-mock'; to create a mock server like server = new WS(process.env.WSS_ENDPOINT as string);

and send messages to my client mock websocket that I custom mocked above

await server.connected;
server.send('{"data": "blabla"}');
发布评论

评论列表(0)

  1. 暂无评论