daronwolff
daronwolff

Reputation: 2064

How to test a RedisClient returned by a promise using Jest and Node.JS

// client.js
const getCacheClient = async (configuration) => {
  return new Promise((resolve, reject) => {
    const redisClient = redis.createClient(configuration.port, configuration.host);
    // note that promise is fullfiled or rejected based on redis client events
    redisClient.on('ready', () => resolve(redisClient));
    redisClient.on('error', (redisError) => {
      console.log('Error connecting Redis', redisError.message);
      redisClient.quitAsync();
      return reject(redisError);
    });
  });
};

What is the proper way of testing a Redis client that is returned by a promise but the resolve or reject is based on an event handler?

Since the resolve or reject are based on the event of "success/error" I´m not sure how to recreate the events. I´m getting an 'Async callback was not invoked within the 10000 ms timeout specified by jest.setTimeout.Timeout - Async callback was not invoked within the 10000 ms timeout specified by jest.setTimeout.Error:'

// client.test.js

import client, { __RewireAPI__ as API } from '../client';

describe('get-cache-client', () => {
  const mockBlueprint = { promisifyAll: jest.fn((x) => x) };
  const mockRedisClient = {
    getAsync: jest.fn(),
    setexAsync: jest.fn(),
    on: jest.fn(),
  };
  const mockRedis = {
    createClient: {
      on: jest.fn(),
    },
  };

  beforeEach(() => {
    API.__Rewire__('redis', mockRedis);
    API.__Rewire__('blueprint', mockBlueprint);
  });

  afterEach(() => {
    __rewire_reset_all__();
    mockRedis.createClient.mockReset();
  });

  describe('getCacheClient', () => {
    it('should create a client with the expected parameters', async (done) => {
      const config = {
        host: 'testrediscachehost',
        port: 1234,
        key: 'testrediscachekey',
      };
      mockRedis.createClient.on.mockReturnValue(mockRedisClient);
      const client = await expect(getCacheClient(config));
      // it gets stuck here, promise is never fulfilled or rejected
      // .... tests...
    });
  });
});

Upvotes: 0

Views: 2577

Answers (1)

Lin Du
Lin Du

Reputation: 102277

I didn't see any reason to use __Rewire__ things.

Use jest.spyOn() and jest.restoreAllMocks() are enough.

E.g.

client.js:

import redis from 'redis';

export const getCacheClient = async (configuration) => {
  return new Promise((resolve, reject) => {
    const redisClient = redis.createClient(configuration.port, configuration.host);
    redisClient.on('ready', () => resolve(redisClient));
    redisClient.on('error', (redisError) => {
      console.log('Error connecting Redis', redisError.message);
      redisClient.quit();
      return reject(redisError);
    });
  });
};

client.test.js:

import { getCacheClient } from './client';
import redis from 'redis';

describe('68492493', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  test('should create redis client and be ready', async () => {
    const config = {
      host: 'testrediscachehost',
      port: 1234,
      key: 'testrediscachekey',
    };
    const mRedisClient = {
      on: jest.fn().mockImplementation(function (event, handler) {
        if (event === 'ready') {
          handler();
        }
        return this;
      }),
      quit: jest.fn(),
    };
    const createClientSpy = jest.spyOn(redis, 'createClient').mockReturnValueOnce(mRedisClient);
    await getCacheClient(config);
    expect(createClientSpy).toBeCalledWith(1234, 'testrediscachehost');
    expect(mRedisClient.on).toBeCalledWith('ready', expect.any(Function));
  });

  test('should handle error', async () => {
    // Try test by yourself
  });
});

test result:

 PASS  examples/68492493/client.test.ts (8.739 s)
  68492493
    ✓ should create redis client and be ready (4 ms)

-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------|---------|----------|---------|---------|-------------------
All files  |      75 |      100 |      80 |   66.67 |                   
 client.ts |      75 |      100 |      80 |   66.67 | 8-10              
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        9.548 s, estimated 10 s
Ran all test suites related to changed files.

Upvotes: 1

Related Questions