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

In Jest UT, Nest can't resolve dependencies of the RedisService (?). Please make sure that the argument Symbol(REDIS_CLIENT) at index [0] is available in the RootTestModule context. #91

Open
eharaj1 opened this issue Oct 5, 2021 · 8 comments

Comments

@eharaj1
Copy link

eharaj1 commented Oct 5, 2021

I have written the simple UT in Jest and also used nestjs-redis module for redis operation when i run the UT i am getting following error, i tried to mock as fn() but getting same issue.

Nest can't resolve dependencies of the RedisService (?). Please make sure that the argument Symbol(REDIS_CLIENT) at index [0] is available in the RootTestModule context.

   Potential solutions:
   - If Symbol(REDIS_CLIENT) is a provider, is it part of the current RootTestModule?
   - If Symbol(REDIS_CLIENT) is exported from a separate @Module, is that module imported within RootTestModule?
     @Module({
       imports: [ /* the Module containing Symbol(REDIS_CLIENT) */ ]
     })

Below is the code

import { Test, TestingModule } from '@nestjs/testing';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
import { getModelToken } from '@nestjs/mongoose';
import { RedisService } from '../../shared/lib/redis/redis.service';
describe('CatsController', () => {
    let controller: CatsController;
    let service: CatsService;
    
  beforeEach(async () => {
    const app: TestingModule = await Test.createTestingModule({
      controllers: [CatsController],
      providers: [CatsService, RedisService, { provide: getModelToken('Cats'), useValue: { Symbol: jest.fn()} }],
    }).compile();

    controller = app.get<CatsController>(CatsController);
    service = app.get<CatsService>(CatsService);
  });

  it('should be defined', () => {
    expect(controller).toBeDefined();
    expect(service).toBeDefined();
  });

  const catsData = [{
      cat_name: "cat",
      cat_type: "type",
      cat_color: "black"
  }]
  describe('Cats List', () => {


    it('should return all cats', async() => {
        jest.spyOn(service, 'getAll').mockResolvedValue({data: catsData, success: true})
        const catsList = await controller.findAll()
      expect(catsList).toBe({data: catsData, success: true});
    });

    it('should throw error record not found', async() => {
        jest.spyOn(service, 'getAll').mockRejectedValue({message: 'Records not found'})
        try{
            await controller.findAll();
          }catch(e){
            expect(e.message).toBe('Records not found');
          }
      });

  });
});
@eharaj1
Copy link
Author

eharaj1 commented Oct 6, 2021

Hello,

Please help me on this.

@rjpkuyper
Copy link

rjpkuyper commented Oct 6, 2021

As far as I see you are not importing the RedisModule in your test.

@eharaj1
Copy link
Author

eharaj1 commented Oct 7, 2021

Hi @rjpkuyper
I imported the RedisModule also but getting same error.

@rjpkuyper
Copy link

rjpkuyper commented Oct 7, 2021

Can you share a minimal repository to replicate?

@eharaj1
Copy link
Author

eharaj1 commented Oct 7, 2021

Hi @rjpkuyper
I have shared the repo with you.
Please check it out.

@rjpkuyper
Copy link

rjpkuyper commented Oct 7, 2021

See your repo branch fix/tests for updatet repo. For the commit see: eharaj1/nestjs-redis-mongo-opentelemetry-jaeger@15b7b9c .

  1. You are not actively overriding the RedisService and thus it cannot resolve. You have to explicitly override the RedisService to prevent connecting with a real Redis instance.
  2. On some places you did a toBe or toEqual check, but you want to match an object instead. Thus use matchObject instead.
  3. You don't need to do a beforeEach, use beforeAll instead.

So what I did, is to override the providers with a mock instead.

// cats.controller.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
import { getModelToken } from '@nestjs/mongoose';

import { RedisService } from '../../shared/lib/redis/redis.service';
import {REDIS_CLIENT} from "../../shared/lib/redis/redis.constants";

describe('CatsController', () => {
    let controller: CatsController;
    let service: CatsService;
    
  beforeAll(async () => {
    const app: TestingModule = await Test.createTestingModule({
      imports: [],
      controllers: [CatsController],
      providers: [
        CatsService, 
        { 
          provide: getModelToken('Cats'), 
          useValue: { Symbol: jest.fn()} 
        },
        {
          provide: RedisService,
          useValue: {
            get: jest.fn(),
            getClient: jest.fn().mockReturnValue(REDIS_CLIENT),
          }
        },
        {
          provide: REDIS_CLIENT,
          useValue: {
            get: jest.fn().mockReturnValue('foo'),
            keys: jest.fn().mockReturnValue(['foo', 'bar']),
          }
        }
      ],
    }).compile();

    controller = app.get<CatsController>(CatsController);
    service = app.get<CatsService>(CatsService);
  });

  it('should be defined', () => {
    expect(controller).toBeDefined();
    expect(service).toBeDefined();
  });

  const catsData = [{
      cat_name: "cat",
      cat_type: "type",
      cat_color: "black"
  }]
  describe('Cats List', () => {


    it('should return all cats', async() => {
      jest.spyOn(service, 'getAll').mockResolvedValue({data: catsData, success: true})
      const catsList = await controller.findAll();
        
      expect(catsList).toMatchObject({data: catsData, success: true});
    });

    it('should throw error record not found', async() => {
        jest.spyOn(service, 'getAll').mockRejectedValue({message: 'Records not found'})
        try{
            await controller.findAll();
          }catch(e){
            expect(e.message).toBe('Records not found');
          }
      });

  });
});
// cats.service.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { CatsService } from './cats.service';
import { getModelToken } from '@nestjs/mongoose';

const mappingModel = {
    findOne: jest.fn(),
    find: jest.fn(),
    create: jest.fn(),
    };
describe('CatsService', () => {
    let service: CatsService;
    let model: typeof mappingModel;

  beforeAll(async () => {
    const app: TestingModule = await Test.createTestingModule({
        providers: [CatsService, {provide: getModelToken('Cats'), useValue: mappingModel}],
    }).compile();

    service = app.get<CatsService>(CatsService);
    model = app.get(getModelToken('Cats'));
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
    expect(model).toBeDefined();
  });

  const catsData = {
      data: [{
        cat_name: "cat",
        cat_type: "type",
        cat_color: "black"
        }]  
    }

  describe('Cats List', () => {

    it('should return all cats', async() => {
        model.find.mockResolvedValue(catsData);
        const res = await service.getAll();

        expect(res).toMatchObject({ data: catsData })
        expect(model.find).toHaveBeenCalledTimes(1);
    });

    it('should through in cats list', async() => {
        model.find.mockRejectedValue({message:'hub not found!!'});
        try{
            await service.getAll();
          }catch(e){
            expect(e.message).toBe('Record not found.');
            expect(model.find).toHaveBeenCalledTimes(2);
          }
      });

  });
});

Hope this helps.

@eharaj1
Copy link
Author

eharaj1 commented Oct 8, 2021

Hey @rjpkuyper ,

Many thanks, you saved my days.

@rjpkuyper
Copy link

Your welcome!

Could you please close the issue.

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

2 participants