mswjs / msw

Industry standard API mocking for JavaScript.
https://mswjs.io
MIT License
16.03k stars 525 forks source link

Support mocking WebSocket APIs #156

Closed Doesntmeananything closed 1 month ago

Doesntmeananything commented 4 years ago

Is it possible to use msw to mock server-sent events (SSE) and WebSocket (WS) connections?

My use case is to have a somewhat full client-side mocking story (including REST, SSE, and WS functionality), and since msw is such a joy to use when mocking out REST APIs, I was wondering if it makes sense to use it to mock more specialised server interactions.

Have you thought about this? I admit that I haven't looked much into whether it's possible just to use custom request handlers to add this functionality, emulating SSE and WS behaviour in some way. I wanted to know if you already had something in mind regarding this question. Thanks!

kettanaito commented 1 year ago

September 2023 Status Update

https://github.com/mswjs/interceptors/pull/236#issuecomment-1691251251

@Stackustack, supporting SSE is unfortunately not enough to ship WebSocket support. See the status update in the linked comment above.

kettanaito commented 10 months ago

Update

I've had some success implementing a WebSocket class-based interceptor (https://github.com/mswjs/interceptors/pull/501). This means that the WebSocket support is coming to MSW rather soon! The browser test suite is currently passing. The Node.js test suite using Undici's WebSocket as a global is also passing!

Now, before anyone gets overly excited about this, let me clarify a few things.

  1. MSW will only support intercepting a WebSocket communication established by using the global WebSocket class (i.e. the WHATWG WebSocket standard present globally). This means that third-party libraries that implement WebSockets by other means (e.g. using custom transports) will not be supported. I see no future in supporting contrived transports from third-parties—that is an unreliable strategy. I'd much rather see (and even help) those third-parties migrate to use the standard, as it's also landing in Node.js later this year.
  2. The API to intercept and work with WebSockets will respect the WHATWG WebSocket Standard. This means you will receive outgoing MessageEvent and send back data that will be translated to an incoming MessageEvent.

What's left?

Feedback. You can help land this API sooner by helping with the following:

Meanwhile, I will improve the test coverage of the interceptor to make sure it's fully compatible with the standard when you're using it.

kettanaito commented 10 months ago

Turns out that the initial WebSocket implementation will support SocketIO also!

If you want to be able to mock SocketIO with MSW, please read and upvote this: https://github.com/socketio/socket.io-parser/issues/129

Thank you.

kettanaito commented 10 months ago

WebSocket Support Beta

Please participate in the discussion about the upcoming WebSocket API to help us shape it and ship it faster:

Thank you!

kettanaito commented 9 months ago

I'm renaming this issue so it focuses on the WebSocket API mocking exclusively.

Server-Sent Events (SSE) are quite different, and to my best knowledge, they can be intercepted by the Service Worker. Their implementation will be different. If someone needs it, I encourage you to open a new feature proposal and describe it in more detail (e.g. how you are using SSE in your application, how you imagine mocking to look like, etc).

kettanaito commented 8 months ago

Update: Give the RC a try!

You can install the RC with the WebSocket support today: npm i msw@next.

Please participate and share your feedback! The more feedback we get, the faster and better the end API will be released. Thank you!

95th commented 8 months ago

@kettanaito I am getting when using websocket mocks:

ReferenceError: BroadcastChannel is not defined
    at file:///<project>/node_modules/.pnpm/msw@2.3.0-ws.rc-1_typescript@4.8.4/node_modules/msw/src/core/ws/ws.ts:14:28
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)

Code I am trying:

    const api = ws.link("wss://foo.bar.com/baz");
    const apiHandler = api.on("connection", ({ client }) => {
        client.addEventListener("message", event => {
            // Echo the message back to the client
            client.send(event.data);
        });
    });

Platform: Node

kettanaito commented 8 months ago

@95th, hi! What version of Node.js are you running? It looks like it's older than v18.

MSW itself doesn't support Node.js <18. Please update and have the global BroadcastChannel API available!

johnhunter commented 2 months ago

I have a regression with 2.3.0-ws.rc-9 moving from 2.3.0-ws.rc-8. The socket returned by ws.link has no on method.

Resolved: looks like I can listen for events directly on the WebSocketLink, e.g.

const socket = ws.link('wss://chat.example.com');
socket.addEventListener("connection", ...)
kettanaito commented 2 months ago

@johnhunter, hi. That is not a regression but a change in the API. I've removed .on in favor of consistent .addEventListener. My bad, I forgot to include the change log (fixed here).

kettanaito commented 1 month ago

Released: v2.6.0 🎉

This has been released in v2.6.0!

Make sure to always update to the latest version (npm i msw@latest) to get the newest features and bug fixes.


Predictable release automation by @ossjs/release.

AdrienFromToulouse commented 1 month ago

👋

Is it expected to have to mock BroadcastChannel even for "classic" HTTP requests using msw/node? With 2.6.0 I get this error with my Jest mocks: ReferenceError: BroadcastChannel is not defined

http.get(myMockedEndpoint, () => {
    return HttpResponse.json(foo);
}),

using the node setupServer like so with the brand new type WebSocketHandler

import { setupServer } from 'msw/node';

export const server = setupServer(...handlers);

Since the setupServer is now having union type like so: declare const setupServer: (...handlers: Array<RequestHandler | WebSocketHandler>) => SetupServerApi;

Cheers,

kettanaito commented 1 month ago

Hi, @AdrienFromToulouse. Thanks for reporting his. Looks like the same issue as https://github.com/mswjs/data/issues/306#issuecomment-2446904312. Please use the supported version range of Node.js and stay away from browser-like environments that meddle with your environment.

Is it expected to have to mock BroadcastChannel

No. BroadcastChannel is a global Node.js API. If it's not there, your test environment is taking it away from you. Don't use such environments.

AdrienFromToulouse commented 1 month ago

Hi, @AdrienFromToulouse. Thanks for reporting his. Looks like the same issue as mswjs/data#306 (comment). Please use the supported version range of Node.js and stay away from browser-like environments that meddle with your environment.

Is it expected to have to mock BroadcastChannel

No. BroadcastChannel is a global Node.js API. If it's not there, your test environment is taking it away from you. Don't use such environments.

Thank you for you detailed answer and thank you for maintaining msw. Cheers

kettanaito commented 1 month ago

I will do my best to make in-browser automation accessible and clear in the months to come. This experience has to go, it's absurd. Sorry you have to go through this. It will get better.

AdrienFromToulouse commented 1 month ago

I am planning to migrate to vitest. Jest was great for a while but the amount of shenanigans with typescript and nextJs etc to run tests is just too much and unproductive at some point. Thank you again.