thoov / mock-socket

Javascript mocking library for WebSockets and Socket.IO
MIT License
800 stars 119 forks source link

Using JWM/`mock-socket` in Jest with `partysocket` causes error: `TypeError: ports is not iterable` #390

Open vaughnkoch opened 9 months ago

vaughnkoch commented 9 months ago

Hi, I opened an issue in jest-websocket-mock; the maintainer said I should reopen the issue in mock-socket. See https://github.com/romgain/jest-websocket-mock/issues/169#issuecomment-1916434899.

Original issue text (slightly edited, and with added mock-socket version):


I'm trying to use jest-websocket-mock and mock-socket in conjunction with partysocket, which seems like the most updated browser WebSocket library right now: https://docs.partykit.io/reference/partysocket-api/.

When I run my tests and I use jest-websocket-mock / mock-socket to send a message, I get this error: this error: TypeError: ports is not iterable.

Here's what I do in my tests:

server.send({ type: 'system' })

Then, mock-socket creates the message from this function:

function createMessageEvent(config) {
  var type = config.type;
  var origin = config.origin;
  var data = config.data;
  var target = config.target;
  var messageEvent = new MessageEvent(type, {
    data: data,
    origin: origin
  });

  if (target) {
    messageEvent.target = target;
    messageEvent.srcElement = target;
    messageEvent.currentTarget = target;
  }

  return messageEvent;
}

Then partysocket clones the event with this code (it actually uses cloneEventNode because Jest is running in the node environment).

function cloneEventBrowser(e) {
  return new e.constructor(e.type, e);
}

function cloneEventNode(e) {
  if ("data" in e) {
    const evt2 = new MessageEvent(e.type, e);
    return evt2;
  }
  if ("code" in e || "reason" in e) {
    const evt2 = new CloseEvent(
      // @ts-expect-error we need to fix event/listener types
      e.code || 1999,
      // @ts-expect-error we need to fix event/listener types
      e.reason || "unknown reason",
      e
    );
    return evt2;
  }
  if ("error" in e) {
    const evt2 = new ErrorEvent(e.error, e);
    return evt2;
  }
  const evt = new Event(e.type, e);
  return evt;
}

The above code fails on this line:

const evt2 = new MessageEvent(e.type, e);

I looked at the e parameter and e.ports, is null which explains the error. This may be because of a different environment, but do you have any suggestions on how to fix this?

Note: I also tried to force the environment to Node (instead of the browser), but got this cryptic error:

TypeError: The "event" argument must be an instance of Event. Received an instance of Event

  at WebSocket._handleOpen (node_modules/partysocket/dist/index.js:444:10)
  at node_modules/mock-socket/dist/mock-socket.js:859:16
      at Array.forEach (<anonymous>)
  at WebSocket.dispatchEvent (node_modules/mock-socket/dist/mock-socket.js:855:13)
  at WebSocket.delayCallback (node_modules/mock-socket/dist/mock-socket.js:1522:16)
  at Timeout._onTimeout (node_modules/mock-socket/dist/mock-socket.js:757:58)

Versions:

 "partysocket": "0.0.25",
 "jest-websocket-mock": "2.4.0",
  mock-socket@9.2.1
Atrue commented 9 months ago

Hi, @vaughnkoch. According to the details, you are using 3 libraries and one of them has a conflict with the api. So right now it’s hard to say what’s the real reason of it.

Can you please create a minimal repo or share a snippet of how to reproduce it?