Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nestjs mocking service constructor with Jest

I have created following service to use twilio send login code sms to users:

sms.service.ts

import { Injectable, Logger } from '@nestjs/common';
import * as twilio from 'twilio';

Injectable()
export class SmsService {
    private twilio: twilio.Twilio;
    constructor() {
        this.twilio = this.getTwilio();
    }

    async sendLoginCode(phoneNumber: string, code: string): Promise<any> {
        const smsClient = this.twilio;
        const params = {
            body: 'Login code: ' + code,
            from: process.env.TWILIO_SENDER_NUMBER,
            to: phoneNumber
        };
        smsClient.messages.create(params).then(message => {
            return message;
        });
    }
    getTwilio() {
        return twilio(process.env.TWILIO_SID, process.env.TWILIO_SECRET);
    }
}

sms.service.spec.js that contains my test

import { Test, TestingModule } from '@nestjs/testing';
import { SmsService } from './sms.service';
import { Logger } from '@nestjs/common';

describe('SmsService', () => {
  let service: SmsService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
        providers: [SmsService]
    }).compile();
    service = module.get<SmsService>(SmsService);
});

describe('sendLoginCode', () => {
    it('sends login code', async () => {
      const mockMessage = {
        test: "test"
      }
      jest.mock('twilio')
      const twilio = require('twilio');
      twilio.messages = {
          create: jest.fn().mockImplementation(() => Promise.resolve(mockMessage))
      }
      expect(await service.sendLoginCode("4389253", "123456")).toBe(mockMessage);
    });
  });
});

How can I use jest create mock of the SmsService constructor so that it's twilio variable gets set to mocked version of it I create in service.spec.js?

like image 280
user3482304 Avatar asked Jan 20 '20 11:01

user3482304


People also ask

How do I mock a module in nest JS?

useMocker(createMock) . compile() const usersService = await module. get(UsersService); With this new implementation, every missing dependency of our module will be mocked using the createMock function, and we're safe to unit test our methods without coupling and importing many other modules.

How do you mock a class in jest?

Jest can be used to mock ES6 classes that are imported into files you want to test. ES6 classes are constructor functions with some syntactic sugar. Therefore, any mock for an ES6 class must be a function or an actual ES6 class (which is, again, another function). So you can mock them using mock functions.

How do I run test cases in nest?

To start writing unit test cases, you should install Jest which has default integration with NestJS. We need to create a “spec” file to define the unit tests. That file would normally be named cats. controller.


1 Answers

You should inject your dependency instead of using it directly, then you can mock it in your test:

Create a custom provider

@Module({
  providers: [
    {
      provide: 'Twillio',
      useFactory: async (configService: ConfigService) =>
                    twilio(configService.TWILIO_SID, configService.TWILIO_SECRET),
      inject: [ConfigService],
    },
  ]

Inject it in your service

constructor(@Inject('Twillio') twillio: twilio.Twilio) {}

Mock it in your test

const module: TestingModule = await Test.createTestingModule({
  providers: [
    SmsService,
    { provide: 'Twillio', useFactory: twillioMockFactory },
  ],
}).compile();

See this thread on how to create mocks.

like image 101
Kim Kern Avatar answered Sep 22 '22 23:09

Kim Kern