Git Product home page Git Product logo

socket.io-mock's Introduction

socket.io-mock

npm version npm license XO code style

Build Status Code Climate Test Coverage Issue Count npm npm

A mock to test the socket.io library implementation.

πŸš€ Now written in ES6! Bundled with rollup.

NEW! Added support for disconnect() and close()

Installation

npm install socket.io-mock

Usage

Simply create new socket mock with:

import MockedSocket from 'socket.io-mock';
let socket = new MockedSocket();

And use the socket as if it was a normal Socket.io socket.

For example:

import SocketMock from 'socket.io-mock';
import { expect } from 'chai';

describe('Fast and isolated socket tests', function(){
    it('Sockets should be able to talk to each other without a server', function(done) {
        let socket = new SocketMock();

        socket.on('message', function (message) {
            expect(message).to.equal('Hello World!');
        });
        socket.socketClient.emit('message', 'Hello World!');
    });
});

socket.io-mock's People

Contributors

briaoeuidhtns avatar dkmorlok avatar supremetechnopriest avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

socket.io-mock's Issues

Release isn't tagged

A small thing, but the latest commits were released as [email protected], but the latest tag is 1.2.3. When next version is release, it won't be as clear which is which.

Callback is not working when emit an event on the Server-side

it("Test Mock Socket", (done) => {
        const socketMock = new SocketMock();
        socketMock.socketClient.on("event", (message) => {
            expect(message).toBe("Hello");
        });

        socketMock.emit("event", "Hello", () => {
            done();
        });
    });

The thing is the code will not invoke the callback function as i would expect it to behave because the next code is actually working.

it("Test Mock Socket", (done) => {
        const socketMock = new SocketMock();
        socketMock.on("event", (message) => {
            expect(message).toBe("Hello");
        });

        socketMock.socketClient.emit("event", "Hello", () => {
            done();
        });
    });

Am I missing something?

[question] how to get io object

Is it possible to get io object out of SocketMock?

I need to test

  // sending to all clients in 'game' room, including sender
  io.in('game').emit('big-announcement', 'the game will start soon');

And I am not sure how to approach this.

error when no message

Error when sending an event without message
ex : socket.socketClient.emit('message');
SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse ()

can be easily correct with a minor modification

createPayload = function (e) {
    return (e)?JSON.parse(JSON.stringify(e)):undefined
},

Only a maximum of 2 arguments are emited

Problem

When I emit using the mock, only up to two of the arguments provided are emitted. This is because the current setup assumed that the first parameter (payload contains the entire payload). However, socket io permits for the payload to be sent via multiple arguments (socket.emit(eventName[, …args][, ack]))

For example

socket.on('lobbyTimeout', (...args) => {
    console.log(...args);
});
socket.socketClient.emit(
    'lobbyTimeout',
    10,
    'Brand New Title',
    123
);

This outputs

10 Brand New Title

when the following is expected

 10 Brand New Title 123

Fix

I Fixed this issue by changing the emit in socket-client.js to this

  emit(eventKey, payload, ack, ...args) {
      if (typeof payload === 'function') {
          payload = null
          ack = payload
      }
      this._socketMock.emitEvent(eventKey, payload, ack, ...args)
  }

and the emitEvent in index.js to

 emitEvent(eventKey, payload, ack, ...args) {
     if (typeof ack !== 'function' && args.length > 0) {
         this._emitFn(eventKey, payload, ack, ...args)
         return
     }
     this._emitFn(eventKey, createPayload(payload), ack)
 }

This might not be the most efficient solution but it fixes my issue for now. For anyone else who might have this same problem, I'm using patch-package to patch these changes after install deps

Release 1.3.1 breaking tests

Hi, we were on 1.2.4 but as soon as we upgrade to latest visible on NPM (1.3.1) we're seeing our unit tests failing.

Where we previously had the mock returning Objects the latest update seems to be returning Arrays for us...

            -   "subscribeToSomething": Object {
            +   "subscribeToSomething": Array [

Disconnect?

I like the simple API of this package.

But how can I disconnect a client socket? I've tried

    socket.disconnect();
    socket.socketClient.disconnect();
    socket.close();
    socket.socketClient.close();

Documentation does not specify how to set up room broadcasts

I found that the documentation lacked specificity on how to set up room based broadcasts with the MockedServerSocket implementation. Digging through the code of socket.io-mock plus trial and error allowed me to come up with this code below to officially send information back and forth for testing my ReactApp. The undocumented trick is the need to set up an onEmit() function for that specific event type which will serialize the data and check for room subscription outside of configuring the actual event emit handler.

Disclaimer: If this is exactly how to setup regular socket.io for the server in JS/TS, then I'm unfamiliar since our project has a python based backend implementation of server side socket.io and also I'm not the backend developer.

My solution

This tests a ReactApp that implements socket.io-client

// FILE: ./src/__tests__/App.test.tsx
import React from "react"
import App from "../App"
import { render, cleanup, act, RenderResult, waitFor, prettyDOM } from "@testing-library/react"
import { io } from "socket.io-client"
import MockedServerSocket from "socket.io-mock"
// See Issue #14 for details on type implementation
import { SocketMock, SocketClient } from "../typescript-declarations/socketio-mock"

jest.mock("socket.io-client")
const mockIO = (io as unknown) as jest.MockedFunction<() => SocketClient>

// Generic function to configure MockServerSocket before an event is emitted from the server
// Also handles room subscription verification
function prepareServerSocket2EmitEvent(this: SocketMock, eventType: string): SocketMock {
  this.onEmit(eventType, (payload?: unknown, roomKey?: string) => {
    if (this.joinedRooms.includes(roomKey || "")) {
      this.emit(eventType, JSON.stringify(payload))
    }
  })
  return this
}

describe("<App />", () => {
  let fakeServerSocket: SocketMock
  let fakeSocketClient: SocketClient

  beforeEach(() => {
    fakeServerSocket = new MockedServerSocket()
    fakeSocketClient = fakeServerSocket.socketClient

    // Since fakeServerSocket does not automatically emit a connect message as socketio io() does, simulate it here.
    fakeServerSocket.on("connect", (obj: unknown) => {
      fakeServerSocket.emit("connect", { status: "success" })
    })

    // My server API event method of joining rooms
    fakeServerSocket.on("subscribe", (url: unknown) => {
      if (typeof url === "string") {
        fakeServerSocket.join(url)
      }
    })

    // Since fakeSocketClient does not automatically send connect event as a call
    // to socket.io-client's io() does automatically, emulate it here
    mockIO.mockImplementation(() => {
      fakeSocketClient.emit("connect")
      return fakeSocketClient
    })
  })

  afterEach(async () => {
    await cleanup()
    jest.clearAllMocks()
  })

  describe("socket.io", () => {
    it("should dispatch a event when user is subscribed", async () => {
      const eventType = "new"
      let renderResult: RenderResult<typeof import("@testing-library/dom/types/queries")> | null = null

      await act(async () => {
        // App will autoconnect, subscribe to /myroom, & define handler for eventType which updates component
        renderResult = render(<App />)
      })
      prepareServerSocket2EmitEvent.call(fakeServerSocket, eventType)
      await act(async () => {
        fakeServerSocket.broadcast.to("/myroom").emit(eventType, { class: "custom" })
      })
      await waitFor(() => {
        // Wait for App to react to received event data object
        expect(prettyDOM(renderResult?.container)).toMatchSnapshot()
      })
    })
  })
})

TypeError: socket_io_mock_1.default is not a constructor

I tried to create a test but i got error with using socket.io-mock library. I'm using Typescript btw.

room.gateway.spec.ts

import { Test, TestingModule } from '@nestjs/testing'
import { RoomGateway } from './room.gateway'
import { Socket } from 'socket.io'
import SocketMock from 'socket.io-mock'

let socket: Socket

describe('RoomGateway', () => {
  let roomGateway: RoomGateway

  beforeEach(async () => {
    const RoomModule: TestingModule = await Test.createTestingModule({
      providers: [RoomGateway],
    }).compile()

    socket = SocketMock()
    roomGateway = RoomModule.get<RoomGateway>(RoomGateway)
  })

  it('Should be defined', () => {
    expect(roomGateway).toBeDefined()
  })

  it('Should return message that we provide', async () => {
    expect(roomGateway.handleMessage(socket, 'Hello World')).toEqual({
      event: 'message',
      data: 'Hello World',
    })
  })
})

socket.close is not a function

Within my project i have pretty simple global mock for socket.io made by you (btw really thanks)

jest-setup.js

// outsource dependencies
import MockedSocket from 'socket.io-mock';
import socketIOClient from 'socket.io-client';

// NOTE mock socket.io globally
jest.mock('socket.io-client');
socketIOClient.mockReturnValue(new MockedSocket());

Within this project i faced up with really complex solutions which required deep integration with socket.io and has wrapper service for it. In order to fit all requirements was used socket.close

But it implementation absent within socket.io-mock 😒 also as socket.disconnect. I think it's possible to at least emulate some behavior of socket instance for client. And I am begging you to provide such functionality πŸ˜‡ Ofcourse it's possible to emulate within tests and, i do not think it will be helpful, but the solution which useful for me is:

bloody hack

// outsource dependencies
import MockedSocket from 'socket.io-mock';
import socketIOClient from 'socket.io-client';

// NOTE mock socket.io globally
jest.mock('socket.io-client');
MockedSocket.prototype.disconnect = jest.fn();
socketIOClient.mockReturnValue(new MockedSocket());

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.