jupiter / simple-mock

Super simple stubs and spies with 1-step sandbox restore
MIT License
87 stars 12 forks source link

Mock return value from another mock #30

Closed alejandrodelarosa closed 5 years ago

alejandrodelarosa commented 5 years ago

Taking the following example.

if (allSessions) {
  const sIds = await redis.lrange(`allUserSessions:${userId}`, 0, -1);
  const pipeline = redis.pipeline();

  sIds.forEach((sId) => pipeline.del(`userSession:${sId}`));
  pipeline.del(`allUserSessions:${userId}`);
  pipeline.exec((err) => {
    if (err) {
      console.error(`While removeing ALL user Sessions: ${err}`);
    }
  });

  return true;
}

i'm trying to writte a test like this.

it('******', async () => {
  const sIds = ['sid1', 'sid2', 'sid3'];

  const redisLrangeFn = simple.mock(redis, 'lrange').resolveWith(new Promise(resolve => resolve(sIds)));
  const redisPipelineFn = simple.mock(redis, 'pipeline').callOriginal();

  const actual = await logout({}, { allSessions: true }, contextMock());

  console.log(redisPipelineDelFn);
  expect(actual).to.be.true;
  expect(destroySessionFn.called).to.be.true;
  expect(destroySessionFn.callCount).to.equal(1);
  expect(redisPipelineFn.called).to.be.true;
  expect(redisPipelineFn.callCount).to.equal(1);
  expect(redisLrangeFn.called).to.be.true;
  expect(redisLrangeFn.callCount).to.equal(1);
  expect(redisLrangeFn.calls[0].returned).to.eventually.deep.equal(sIds);
  expect(redisPipelineDelFn.called).to.be.true;
  /* counting forEach calls + pipeline.del(`allUserSessions:${userId}`); */
  // expect(redisPipelineDelFn.callCount).to.equal(sIds.length + 1);
  // expect(redisPipelineExecFn.called).to.be.true;
  // expect(redisPipelineExecFn.callCount).to.equal(1);
});

is there a way to also mock the returned value of

const redisPipelineFn = simple.mock(redis, 'pipeline').callOriginal();

so i can do something like

const redisPipelineDelFn = simple.mock(redisPipelineFn, 'del').returnWith(true);
const redisPipelineExecFn = simple.mock(redisPipelineFn, 'exec').returnWith(true);

Basically, mock redis.pipeline().del and redis.pipeline().exec

Sorry if the title is incorrect.

jupiter commented 5 years ago

The simplest option is probably to return a mock 'pipeline' object, e.g. taking your example:

const mockPipeline = {
  del: simple.mock().returnWith(true),
  exec: simple.mock() // You could also `.returnWith(true)`, but I don't see the point
};
simple.mock(redis, 'pipeline').returnWith(mockPipeline);
// ...
expect(redis.pipeline.callCount).to.equal(1)
expect(mockPipeline.del.callCount).to.equal(sIds.length + 1)
expect(mockPipeline.exec.callCount).to.equal(1)

Does that make sense?

Another unrelated tip: You do not need to create a promise to resolve with, just resolve the value:

simple.mock(redis, 'lrange').resolveWith(sIds);