Skip to content

It doesn't trigger any events on creating a new connection to capture at on methods #1351

Description

@SeyyedKhandon

I'm trying to mock ioredis so to be able to test it, but unfortunately, am not able to do it properly, I triedioredis-mock but it doesnt trigger any event on ready, so it does not work for me or I dont know how to do it properly, please someone shed some light on it

const createCacheInstance = async () => {
  const address = process.env.REDIS_CLUSTER_ADDRESS
  const password = process.env.REDIS_AUTH_TOKEN

  logger.info(`Redis cluster env address:${address}`)

  try {
    if (!address || !password)
      throw new Error('Environment variables {REDIS_CLUSTER_ADDRESS or REDIS_AUTH_TOKEN} are not available')

    const host = address.split(':')[0]
    const port = Number(address.split(':')[1])
    logger.info(`Redis cluster host:${host} port:${port}`)

    const tlsMode = process.env.NODE_ENV === 'production' ? { tls: {} } : {} // https://github.com/redis/ioredis?tab=readme-ov-file#special-note-aws-elasticache-clusters-with-tls

    const redisCluster = new Redis.Cluster([{ host, port }], {
      slotsRefreshTimeout: 2000, // to prevent [Failed to refresh slots cache error](https://github.com/redis/ioredis/issues/711)
      scaleReads: 'all', // Send write queries to masters and read queries to masters or slaves randomly.
      dnsLookup: (address, callback) => callback(null, address), // https://github.com/redis/ioredis?tab=readme-ov-file#special-note-aws-elasticache-clusters-with-tls
      redisOptions: { password, ...tlsMode },
    })

    return await new Promise<{ redisCluster?: Cluster; error?: Error }>((resolve, reject) => {
      redisCluster
        .on('connecting', () => {
          cacheStatus = redisCluster.status
          logger.info('Connecting to Redis DB')
        })
        .on('connect', () => {
          cacheStatus = redisCluster.status
          logger.info('Connected to Redis DB')
        })
        .on('ready', () => {
          cacheStatus = redisCluster.status
          logger.info('Redis cache instance is ready to use')
          resolve({ redisCluster })
        })
        .on('end', () => {
          cacheStatus = redisCluster.status
          logger.warn('Redis cache connection has been closed')
        })
        .on('error', async (error) => {
          cacheStatus = redisCluster.status
          cacheError = error
          logger.error(error)
          try {
            await redisCluster.quit()
          } catch (e) {
            logger.error({ message: 'Error while closing the Redis cache connection', e })
          }
          reject({ error })
        })
    })
  } catch (e) {
    const error = e as Error
    logger.error(error)
    cacheStatus = 'error'
    cacheError = error
    return { error }
  }
}

What I tried which results in "Connection is closed." "ClusterAllFailedError: Failed to refresh slots cache. which seems I need to mock the connection itself too, but am not sure how?

import { afterAll, describe, expect, it, vi } from 'vitest'
import cacheManager, { useCache } from './index'
import { useHashTagKeyMaker } from './helper'

const mocks = vi.hoisted(() => {
  return {
    redisCluster: vi.fn().mockImplementation(() => ({
      set: vi.fn(),
      get: vi.fn(),
      exists: vi.fn(),
      del: vi.fn(),
      sadd: vi.fn(),
      smembers: vi.fn(),
      srem: vi.fn(),
      scard: vi.fn(),
      smismember: vi.fn(),
      flushdb: vi.fn(),
      nodes: vi.fn().mockReturnValue([{ flushdb: vi.fn() }]),
      on: vi.fn().mockImplementation((event, callback) => {
        if (event === 'ready') {
          callback()
        }
        return this
      }),
      quit: vi.fn(),
      status: 'ready',
    })),
  }
})

vi.mock('ioredis', async () => {
  const actual = await vi.importActual('ioredis')
  return {
    ...actual,
    Cluster: mocks.redisCluster,
  }
})

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions