stipsan / ioredis-mock

Emulates ioredis by performing all operations in-memory.
MIT License
336 stars 124 forks source link

Unsupported methods (e.g. client()) are marked as `writable: false` so preventing monkey-patching #1258

Closed robinsummerhill closed 1 year ago

robinsummerhill commented 1 year ago

I am trying to write Jest unit tests for a library that attempts to call ioredis.client(). I understand that it is not supported by ioredis-mock and that the correct thing to do would be to fork the project, implement support, create a pull-request and wait.

The library usage of ioredis.client() has no bearing on the unit tests, so in the meantime, I would like to monkey patch client() to make it a do-nothing.

However, I cannot do this because unsupported methods are marked as writable: false in _initCommands. I can't monkey patch the client() method directly or even create a proxy that bypasses it using a get hander.

I ended up monkey-patching _initCommands like this to implement ioredis.client as a Jest mock fn:

  const originalInitCommands = MockRedis.prototype._initCommands;

  MockRedis.prototype._initCommands = function() {
    this.client = jest.fn();
    originalInitCommands.call(this);
  }

  const mock = new MockRedis(options);

Would it be possible to remove the writable: false property annotation from unsupported methods to facilitate use with testing frameworks?

stipsan commented 1 year ago

Feel free to send in a PR :)

I'm sure the original intent might've been to prevent mistakes. But it doesn't make sense to me why unsupported commands are writeable: false while all the supported commands are writable: true 🤔

marikaner commented 1 year ago

I got the same issue, any ideas for workarounds for now?

marikaner commented 1 year ago

Actually, the fix seems very straight forward, easier than workarounds in my tests ;)

robinsummerhill commented 1 year ago

This is what I am doing to mock ioredis in my tests. Unsupported methods are marked as writable: false in _initCommands if they are found to be missing. This mock monkey patches _initCommands to add the required methods first (client() in my case)and then calls the original version of the method.

const RedisMock = require('ioredis-mock');

const Redis = jest.fn().mockImplementation((options) => {

  const originalInitCommands = RedisMock.prototype._initCommands;

  RedisMock.prototype._initCommands = function() {
    this.client = jest.fn();
    originalInitCommands.call(this);
  }

  const mock = new RedisMock(options);

  return mock;
});

module.exports = {
  Redis
}
github-actions[bot] commented 1 year ago

:tada: This issue has been resolved in version 8.8.2 :tada:

The release is available on:

Your semantic-release bot :package::rocket: