{"id":24003419,"url":"https://github.com/romgain/jest-websocket-mock","last_synced_at":"2025-05-16T13:05:52.629Z","repository":{"id":33651336,"uuid":"159844383","full_name":"romgain/jest-websocket-mock","owner":"romgain","description":"Mock websockets and assert complex websocket interactions with Jest","archived":false,"fork":false,"pushed_at":"2024-02-11T21:38:09.000Z","size":269,"stargazers_count":175,"open_issues_count":12,"forks_count":30,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-05T22:03:15.096Z","etag":null,"topics":["assertions","jest","mock","mock-websockets","unit-testing","websocket"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/romgain.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-30T15:43:49.000Z","updated_at":"2024-08-29T11:13:21.000Z","dependencies_parsed_at":"2024-06-18T12:36:40.234Z","dependency_job_id":"8b00cc79-3378-40de-ac4e-df05a43d0499","html_url":"https://github.com/romgain/jest-websocket-mock","commit_stats":{"total_commits":144,"total_committers":16,"mean_commits":9.0,"dds":0.375,"last_synced_commit":"820d884a511af8386eecf40b4468d53dfc9e250c"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romgain%2Fjest-websocket-mock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romgain%2Fjest-websocket-mock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romgain%2Fjest-websocket-mock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/romgain%2Fjest-websocket-mock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/romgain","download_url":"https://codeload.github.com/romgain/jest-websocket-mock/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253609632,"owners_count":21935560,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assertions","jest","mock","mock-websockets","unit-testing","websocket"],"created_at":"2025-01-08T01:38:25.600Z","updated_at":"2025-05-16T13:05:52.612Z","avatar_url":"https://github.com/romgain.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Jest websocket mock\n\n[![npm version](https://badge.fury.io/js/jest-websocket-mock.svg)](https://badge.fury.io/js/jest-websocket-mock)\n[![Build Status](https://github.com/romgain/jest-websocket-mock/actions/workflows/ci.yml/badge.svg)](https://github.com/romgain/jest-websocket-mock/actions)\n[![Coverage report](https://codecov.io/gh/romgain/jest-websocket-mock/branch/master/graph/badge.svg)](https://codecov.io/gh/romgain/jest-websocket-mock)\n[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n\nA set of utilities and Jest matchers to help testing complex websocket interactions.\n\n**Examples:**\nSeveral examples are provided in the [examples folder](https://github.com/romgain/jest-websocket-mock/blob/master/examples/).\nIn particular:\n\n- [testing a redux saga that manages a websocket connection](https://github.com/romgain/jest-websocket-mock/blob/master/examples/redux-saga/src/__tests__/saga.test.js)\n- [testing a component using the saga above](https://github.com/romgain/jest-websocket-mock/blob/master/examples/redux-saga/src/__tests__/App.test.js)\n- [testing a component that manages a websocket connection using react hooks](https://github.com/romgain/jest-websocket-mock/blob/master/examples/hooks/src/App.test.tsx)\n\n## Install\n\n```bash\nnpm install --save-dev jest-websocket-mock\n```\n\n## Mock a websocket server\n\n### The `WS` constructor\n\n`jest-websocket-mock` exposes a `WS` class that can instantiate mock websocket\nservers that keep track of the messages they receive, and in turn\ncan send messages to connected clients.\n\n```js\nimport WS from \"jest-websocket-mock\";\n\n// create a WS instance, listening on port 1234 on localhost\nconst server = new WS(\"ws://localhost:1234\");\n\n// real clients can connect\nconst client = new WebSocket(\"ws://localhost:1234\");\nawait server.connected; // wait for the server to have established the connection\n\n// the mock websocket server will record all the messages it receives\nclient.send(\"hello\");\n\n// the mock websocket server can also send messages to all connected clients\nserver.send(\"hello everyone\");\n\n// ...simulate an error and close the connection\nserver.error();\n\n// ...or gracefully close the connection\nserver.close();\n\n// The WS class also has a static \"clean\" method to gracefully close all open connections,\n// particularly useful to reset the environment between test runs.\nWS.clean();\n```\n\nThe `WS` constructor also accepts an optional options object as second argument:\n\n- `jsonProtocol: true` can be used to automatically serialize and deserialize JSON messages:\n\n```js\nconst server = new WS(\"ws://localhost:1234\", { jsonProtocol: true });\nserver.send({ type: \"GREETING\", payload: \"hello\" });\n```\n\n- The `mock-server` options `verifyClient` and `selectProtocol` are directly passed-through to the mock-server's constructor.\n\n### Attributes of a `WS` instance\n\nA `WS` instance has the following attributes:\n\n- `connected`: a Promise that resolves every time the `WS` instance receives a\n  new connection. The resolved value is the `WebSocket` instance that initiated\n  the connection.\n- `closed`: a Promise that resolves every time a connection to a `WS` instance\n  is closed.\n- `nextMessage`: a Promise that resolves every time a `WS` instance receives a\n  new message. The resolved value is the received message (deserialized as a\n  JavaScript Object if the `WS` was instantiated with the `{ jsonProtocol: true }`\n  option).\n\n### Methods on a `WS` instance\n\n- `send`: send a message to all connected clients. (The message will be\n  serialized from a JavaScript Object to a JSON string if the `WS` was\n  instantiated with the `{ jsonProtocol: true }` option).\n- `close`: gracefully closes all opened connections.\n- `error`: sends an error message to all connected clients and closes all\n  opened connections.\n- `on`: attach event listeners to handle new `connection`, `message` and `close` events. The callback receives the `socket` as its only argument.\n\n## Run assertions on received messages\n\n`jest-websocket-mock` registers custom jest matchers to make assertions\non received messages easier:\n\n- `.toReceiveMessage`: async matcher that waits for the next message received\n  by the the mock websocket server, and asserts its content. It will time out\n  with a helpful message after 1000ms.\n- `.toHaveReceivedMessages`: synchronous matcher that checks that all the\n  expected messages have been received by the mock websocket server.\n\n### Run assertions on messages as they are received by the mock server\n\n```js\ntest(\"the server keeps track of received messages, and yields them as they come in\", async () =\u003e {\n  const server = new WS(\"ws://localhost:1234\");\n  const client = new WebSocket(\"ws://localhost:1234\");\n\n  await server.connected;\n  client.send(\"hello\");\n  await expect(server).toReceiveMessage(\"hello\");\n  expect(server).toHaveReceivedMessages([\"hello\"]);\n});\n```\n\n### Send messages to the connected clients\n\n```js\ntest(\"the mock server sends messages to connected clients\", async () =\u003e {\n  const server = new WS(\"ws://localhost:1234\");\n  const client1 = new WebSocket(\"ws://localhost:1234\");\n  await server.connected;\n  const client2 = new WebSocket(\"ws://localhost:1234\");\n  await server.connected;\n\n  const messages = { client1: [], client2: [] };\n  client1.onmessage = (e) =\u003e {\n    messages.client1.push(e.data);\n  };\n  client2.onmessage = (e) =\u003e {\n    messages.client2.push(e.data);\n  };\n\n  server.send(\"hello everyone\");\n  expect(messages).toEqual({\n    client1: [\"hello everyone\"],\n    client2: [\"hello everyone\"],\n  });\n});\n```\n\n### JSON protocols support\n\n`jest-websocket-mock` can also automatically serialize and deserialize\nJSON messages:\n\n```js\ntest(\"the mock server seamlessly handles JSON protocols\", async () =\u003e {\n  const server = new WS(\"ws://localhost:1234\", { jsonProtocol: true });\n  const client = new WebSocket(\"ws://localhost:1234\");\n\n  await server.connected;\n  client.send(`{ \"type\": \"GREETING\", \"payload\": \"hello\" }`);\n  await expect(server).toReceiveMessage({ type: \"GREETING\", payload: \"hello\" });\n  expect(server).toHaveReceivedMessages([\n    { type: \"GREETING\", payload: \"hello\" },\n  ]);\n\n  let message = null;\n  client.onmessage = (e) =\u003e {\n    message = e.data;\n  };\n\n  server.send({ type: \"CHITCHAT\", payload: \"Nice weather today\" });\n  expect(message).toEqual(`{\"type\":\"CHITCHAT\",\"payload\":\"Nice weather today\"}`);\n});\n```\n\n### verifyClient server option\n\nA `verifyClient` function can be given in the options for the `jest-websocket-mock` constructor.\nThis can be used to test behaviour for a client that connects to a WebSocket server it's blacklisted from for example.\n\n**Note** : _Currently `mock-socket`'s implementation does not send any parameters to this function (unlike the real `ws` implementation)._\n\n```js\ntest(\"rejects connections that fail the verifyClient option\", async () =\u003e {\n  new WS(\"ws://localhost:1234\", { verifyClient: () =\u003e false });\n  const errorCallback = jest.fn();\n\n  await expect(\n    new Promise((resolve, reject) =\u003e {\n      errorCallback.mockImplementation(reject);\n      const client = new WebSocket(\"ws://localhost:1234\");\n      client.onerror = errorCallback;\n      client.onopen = resolve;\n    }),\n    // WebSocket onerror event gets called with an event of type error and not an error\n  ).rejects.toEqual(expect.objectContaining({ type: \"error\" }));\n});\n```\n\n### selectProtocol server option\n\nA `selectProtocol` function can be given in the options for the `jest-websocket-mock` constructor.\nThis can be used to test behaviour for a client that connects to a WebSocket server using the wrong protocol.\n\n```js\ntest(\"rejects connections that fail the selectProtocol option\", async () =\u003e {\n  const selectProtocol = () =\u003e null;\n  new WS(\"ws://localhost:1234\", { selectProtocol });\n  const errorCallback = jest.fn();\n\n  await expect(\n    new Promise((resolve, reject) =\u003e {\n      errorCallback.mockImplementationOnce(reject);\n      const client = new WebSocket(\"ws://localhost:1234\", \"foo\");\n      client.onerror = errorCallback;\n      client.onopen = resolve;\n    }),\n  ).rejects.toEqual(\n    // WebSocket onerror event gets called with an event of type error and not an error\n    expect.objectContaining({\n      type: \"error\",\n      currentTarget: expect.objectContaining({ protocol: \"foo\" }),\n    }),\n  );\n});\n```\n\n### Sending errors\n\n```js\ntest(\"the mock server sends errors to connected clients\", async () =\u003e {\n  const server = new WS(\"ws://localhost:1234\");\n  const client = new WebSocket(\"ws://localhost:1234\");\n  await server.connected;\n\n  let disconnected = false;\n  let error = null;\n  client.onclose = () =\u003e {\n    disconnected = true;\n  };\n  client.onerror = (e) =\u003e {\n    error = e;\n  };\n\n  server.send(\"hello everyone\");\n  server.error();\n  expect(disconnected).toBe(true);\n  expect(error.origin).toBe(\"ws://localhost:1234/\");\n  expect(error.type).toBe(\"error\");\n});\n```\n\n### Add custom event listeners\n\n#### For instance, to refuse connections:\n\n```js\nit(\"the server can refuse connections\", async () =\u003e {\n  const server = new WS(\"ws://localhost:1234\");\n  server.on(\"connection\", (socket) =\u003e {\n    socket.close({ wasClean: false, code: 1003, reason: \"NOPE\" });\n  });\n\n  const client = new WebSocket(\"ws://localhost:1234\");\n  client.onclose = (event: CloseEvent) =\u003e {\n    expect(event.code).toBe(1003);\n    expect(event.wasClean).toBe(false);\n    expect(event.reason).toBe(\"NOPE\");\n  };\n\n  expect(client.readyState).toBe(WebSocket.CONNECTING);\n\n  await server.connected;\n  expect(client.readyState).toBe(WebSocket.CLOSING);\n\n  await server.closed;\n  expect(client.readyState).toBe(WebSocket.CLOSED);\n});\n```\n\n### Environment set up and tear down between tests\n\nYou can set up a mock server and a client, and reset them between tests:\n\n```js\nbeforeEach(async () =\u003e {\n  server = new WS(\"ws://localhost:1234\");\n  client = new WebSocket(\"ws://localhost:1234\");\n  await server.connected;\n});\n\nafterEach(() =\u003e {\n  WS.clean();\n});\n```\n\n## Known issues\n\n`mock-socket` has a strong usage of delays (`setTimeout` to be more specific). This means using `jest.useFakeTimers();` will cause issues such as the client appearing to never connect to the server.\n\nWhile running the websocket server from tests within the jest-dom environment (as opposed to node)\nyou may see errors of the nature:\n\n```bash\n ReferenceError: setImmediate is not defined\n```\n\nYou can work around this by installing the setImmediate shim from\n[https://github.com/YuzuJS/setImmediate](https://github.com/YuzuJS/setImmediate) and\nadding `require('setimmediate');` to your `setupTests.js`.\n\n## Testing React applications\n\nWhen testing React applications, `jest-websocket-mock` will look for\n`@testing-library/react`'s implementation of [`act`](https://reactjs.org/docs/test-utils.html#act).\nIf it is available, it will wrap all the necessary calls in `act`, so you don't have to.\n\nIf `@testing-library/react` is not available, we will assume that you're not testing a React application,\nand you might need to call `act` manually.\n\n## Using `jest-websocket-mock` to interact with a non-global WebSocket object\n\n`jest-websocket-mock` uses [Mock Socket](https://github.com/thoov/mock-socket)\nunder the hood to mock out WebSocket clients.\nOut of the box, Mock Socket will only mock out the global `WebSocket` object.\nIf you are using a third-party WebSocket client library (eg. a Node.js\nimplementation, like [`ws`](https://github.com/websockets/ws)), you'll need\nto set up a [manual mock](https://jestjs.io/docs/en/manual-mocks#mocking-node-modules):\n\n- Create a `__mocks__` folder in your project root\n- Add a new file in the `__mocks__` folder named after the library you want to\n  mock out. For instance, for the `ws` library: `__mocks__/ws.js`.\n- Export Mock Socket's implementation in-lieu of the normal export from the\n  library you want to mock out. For instance, for the `ws` library:\n\n```js\n// __mocks__/ws.js\n\nexport { WebSocket as default } from \"mock-socket\";\n```\n\n**NOTE** The `ws` library is not 100% compatible with the browser API, and\nthe `mock-socket` library that `jest-websocket-mock` uses under the hood only\nimplements the browser API.\nAs a result, `jest-websocket-mock` will only work with the `ws` library if you\nrestrict yourself to the browser APIs!\n\n## Examples\n\nFor a real life example, see the\n[examples directory](https://github.com/romgain/jest-websocket-mock/tree/master/examples),\nand in particular the saga tests.\n\n## Contributing\n\nSee the [contributing guide](https://github.com/romgain/jest-websocket-mock/tree/master/CONTRIBUTING.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fromgain%2Fjest-websocket-mock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fromgain%2Fjest-websocket-mock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fromgain%2Fjest-websocket-mock/lists"}