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

Set then Get fails #197

Open
fishcharlie opened this issue Sep 18, 2021 · 6 comments
Open

Set then Get fails #197

fishcharlie opened this issue Sep 18, 2021 · 6 comments

Comments

@fishcharlie
Copy link

The following code should print bar to the console. However, instead it prints undefined.

Running redis-mock version 0.56.3.

var redis = require("redis-mock"),
    client = redis.createClient();

(async () => {
	try {
		await client.set("foo", "bar");
		console.log(await client.get("foo"));
	} catch (e) {
		console.log(e);
	}
})();
@jason-ransom-slalom
Copy link

Curious about this as well. Experiencing the same behavior.

@cohendvir
Copy link

any updates on this one? this actually prevents my from using this package

@rbrcurtis
Copy link

It's because redis-mock only supports the callback syntax for redis not async/await, which was removed in the latest major version of the redis package. This works:

  let redis = require('redis-mock').createClient()
  await new Promise<void>((resolve) => {
    redis.set('foo', 'bar', () => {
      log('set complete')
      redis.get('foo', (err, val) => {
        log('get complete', val)
        resolve()
      })
    })
  })

and as an aside, the latest version of @types/redis-mock is incorrect.

@rbrcurtis
Copy link

rbrcurtis commented Oct 14, 2022

Here's a kind of smelly workaround:

  let redis = require('redis-mock').createClient()
  redis.set = promisify(redis.set.bind(redis))
  redis.get = promisify(redis.get.bind(redis))
  await redis.set('foo', 'bar')
  log('set complete')
  let val = await redis.get('foo')
  log('get complete', val)

@eatoncw
Copy link

eatoncw commented Dec 15, 2023

Building from @rbrcurtis 's workaround:

I had to create a custom promisify function for the set method to be able to pass additional args, for example client.set("key", "value", {EX: ttl}).

Because this library has a set method where the last argument is not actually the callback, but args = {}, this was required to be able to pass additional args and it not throw.

I'm sure there are better ways to do this (l couldn't get util/promisify custom to work), and this now means I can't mock ttl, but this at least got me started.

I put this all in jest setup file:

import util from 'node:util';
jest.mock('redis', () => jest.requireActual('redis-mock'));

beforeAll(() => {
  let redis = require('./server/lib/redis/client').redisClient;
  redis.set = customPromisify(redis.set.bind(redis));
  redis.get = util.promisify(redis.get.bind(redis));
});

function customPromisify(f) {
  return function (...args) {
    args.pop(); // just removing the last argument basically
    return new Promise((resolve, reject) => {
      function cb(err, result) {
        if (err) {
          reject(err);
        } else {
          resolve(result);
        }
      }

      args.push(cb);

      f.call(this, ...args);
    });
  };
}

@dvqc
Copy link

dvqc commented May 14, 2024

Building from @rbrcurtis 's workaround:

I had to create a custom promisify function for the set method to be able to pass additional args, for example client.set("key", "value", {EX: ttl}).

Because this library has a set method where the last argument is not actually the callback, but args = {}, this was required to be able to pass additional args and it not throw.

I'm sure there are better ways to do this (l couldn't get util/promisify custom to work), and this now means I can't mock ttl, but this at least got me started.

I put this all in jest setup file:

import util from 'node:util';
jest.mock('redis', () => jest.requireActual('redis-mock'));

beforeAll(() => {
  let redis = require('./server/lib/redis/client').redisClient;
  redis.set = customPromisify(redis.set.bind(redis));
  redis.get = util.promisify(redis.get.bind(redis));
});

function customPromisify(f) {
  return function (...args) {
    args.pop(); // just removing the last argument basically
    return new Promise((resolve, reject) => {
      function cb(err, result) {
        if (err) {
          reject(err);
        } else {
          resolve(result);
        }
      }

      args.push(cb);

      f.call(this, ...args);
    });
  };
}

@eatoncw The customPromisify function should have a check for args length in case redis.set is called without the additional args. Something like this:

if (args.length > 2)
    args.pop();

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

No branches or pull requests

6 participants