Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support mocking WebSocket APIs #2011

Open
wants to merge 102 commits into
base: main
Choose a base branch
from
Open

feat: support mocking WebSocket APIs #2011

wants to merge 102 commits into from

Conversation

kettanaito
Copy link
Member

@kettanaito kettanaito commented Feb 3, 2024

Roadmap

  • Support runtime overrides for event handlers.
  • Extend Handler in RequestHandler. This way HttpHandler and GraphQLHandler will be assignable to type Handler, and Array<Handler> can annotate both HTTP and WebSocket handlers.
    • Bad idea. Even abstracted, RequestHandler relies on caching to clone requests, parsed result, etc. Not enough common ground to reuse between it and WebSocketHandler. WS handler is better off as a standalone class (doesn't support once anyway).
  • Call handleWebSocketEvent() in SetupWorkerApi and SetupServerApi.
  • handleRequest: Check that the handler is instanceof RequestHandler to skip WebSocket handlers.
  • Update to @mswjs/interceptors that ships WebSocketInterceptor.
  • Improve types. The data argument of message listeners must be annotated across the board (includes annotating the MessageEvent in the Interceptors).
    • Not a good idea. The data you receive is still string | Blob | ArrayBuffer. You cannot just cast it to something else. Instead, introduce a custom parser that does that casting, as well as the runtime typeof checks. That's the way.
    • Document this approach.
  • Add links to jsdoc blocks of the new API.
  • Bug: look into why pnpm test:modules:node hangs forever on setupServer() without the explicit process.exit() in the generated runtime.* scripts.
  • Add Node.js tests.
  • Add browser tests.
  • Add .use() override tests (i.e. event.stopImmediatePropagation()).
  • Defer the interceptor application to the .start()/.listen() calls.
  • Add server.close() API (a task for Interceptors, here just add tests).
  • Invoke onUnhandledRequest() (or similar) for unhandled WebSocket connections. Technically, there are no requests, so the existing method reads weird. WebSocket Support Beta #2010 (comment)
  • feat(ws): add logging to WebSocket connections #2112
  • WebSocket: Decide how to handle actual server errors interceptors#539
  • Forward client events to the server by default (WebSocket Support Beta #2010 (comment)).
  • Fix .broadcast() not broadcasting from N(1) -> N+ but working from N+ -> N+. (discovered in add WebSocket + ws example examples#111) (fix(WebSocketClientManager): use localStorage for clients persistence #2127).
  • Annotate this: WebSocket in the client/server event listeners.
  • Refreshing the page keeps adding the same client under a new ID to the localStorage (fix: fix: purge persisted clients on page reload #2133)
Screenshot 2024-04-12 at 13 09 35

@kettanaito
Copy link
Member Author

📦 v2.3.0-ws.rc-7

  • Add info argument to the connection event (@mswjs/interceptors@0.30.0).

@kettanaito
Copy link
Member Author

Node tests on HttpResponse.arrayBuffer() are failing due to #2228.

@kettanaito
Copy link
Member Author

Supporting onUnhandledRequest

I've decided for the unhandled WebSocket connections to also trigger the onUnhandledRequest calls. WebSocket connection is often preceded with an Upgrade handshake request, so it's technically an HTTP request first. You will see the URL, including the WebSocket protocol, giving you enough indication of what you are not handling.

There's a difficulty in handling the error unhandled request strategy though. That strategy throws in MSW, and since MSW runs within queueMicrotask(() => emitter.emit(here)), for some reason, those exceptions are not caught by Interceptors (it's not the queueMicrotask/process.nextTick issue, I checked, and Interceptors already have internal error handling in the queued task).

I think I'd have to expose some .errorWith() control utility to allow any layer to error the WebSocket connection (non-graraceful closure). That way, onUnhandledRequest() throws can be caught and translated to that closure:

// msw
await onUnhandledRequest().catch((error) => {
  connection.client.errorWith(error)
})

Will have to think on this API.

@kettanaito
Copy link
Member Author

📦 v2.3.0-ws.rc-8

  • Fixes the WebSocketClientManager not keeping track of cross-tabs clients (a refactor to use IndexedDB in the browser).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support mocking WebSocket APIs
3 participants