2

I am developing a node.js application using nestjs I have a class called LoggerService as below

export class LoggerService {

    private logger: Rollbar;

    constructor() {
        this.logger = this.setupLogger();
    }

    critical(...args: Array<string | Error | object | Date | any[]>) {
        this.logger.error(...args);
    }

    private setupLogger(): Rollbar {
        if (this.logger == null) {

            this.logger = new Rollbar({
                accessToken: 'token',
                environment: 'dev',
                captureUncaught: true,
                captureUnhandledRejections: true,
            });

        }

        return this.logger;
    }

Now I am writing unit test for this class using jest as below.

describe('LoggerService.log', () => {
  let service: LoggerService;

  beforeEach(async () => {

    const module: TestingModule = await Test.createTestingModule({
      providers: [LoggerService],
    }).compile();

    service = module.get<LoggerService>(LoggerService);
  });

  it('critical', () => {
    service.critical('error','message');
    expect(???).toHaveBeenCalledWith('error', 'message')
  })

);

My question is how to check(expect) if logger.error is called, or how to mock Rollbar in this class.

Kim Kern
  • 54,283
  • 17
  • 197
  • 195
Reza
  • 18,865
  • 13
  • 88
  • 163

1 Answers1

1

1) Provide your external dependency/library as an injectable token in your module

@Module({
  providers: [
    {
      provide: 'Rollbar',
      useFactory: async (configService: ConfigService) => new Rollbar({
                accessToken: configService.accessToken,
                environment: configService.environment,
                captureUncaught: true,
                captureUnhandledRejections: true,
            }),
      inject: [ConfigService],
    },
  ]

2) Inject it in your LoggerService instead of creating it

export class LoggerService {
    constructor(@Inject('Rollbar') private logger: Rollbar) {
    }

3) Now you can mock your dependency in your test

const module: TestingModule = await Test.createTestingModule({
  providers: [
    LoggerService,
    { provide: 'Rollbar', useFactory: rollbarMockFactory },
  ],
}).compile();
Kim Kern
  • 54,283
  • 17
  • 197
  • 195
  • Awesome, just one thing where is `rollbarMockFactory` defined? – Reza Aug 06 '19 at 18:18
  • Glad you find it helpful. :-) That's just a placeholder. If you want to learn more about mocking, have a look at this thread: https://stackoverflow.com/a/55366343/4694994 – Kim Kern Aug 06 '19 at 18:20
  • I did that, and in my test my code is like `const module: TestingModule = await Test.createTestingModule({ providers: [ LoggerService, { provide: 'Rollbar', useFactory: jest.fn(() => ({ error: jest.fn(() => null), })) } ], })` but I get this error ` Nest can't resolve dependencies of the LoggerService (?). Please make sure that the argument at index [0] is available in the _RootTestModule context` and this is my service `constructor(@Inject('Rollbar') private logger: Rollbar) { }` – Reza Aug 06 '19 at 18:34
  • Does the server start up? Btw: You should not use a plain string as a token in production. Define a constant for your injection token. Definitely make sure that your tokens are the same everywhere. – Kim Kern Aug 06 '19 at 18:38
  • also I did this, still same ` .overrideProvider('Rollbar') .useFactory({ factory: () => ({ error: jest.fn(() => null), }) }) ` – Reza Aug 06 '19 at 18:43
  • and also this one ` providers: [ LoggerService, { provide: 'Rollbar', useValue: { error: jest.fn(() => null), } } ], ` – Reza Aug 06 '19 at 18:55
  • Mh, I don't know why it doesn't work for you, it does for in my code. :-| Maybe has something to do with https://github.com/nestjs/nest/issues/412#issuecomment-366076180 ? – Kim Kern Aug 06 '19 at 19:01
  • There are also a couple of bugs linked to injection tokens. Maybe try updating your dependencies: https://github.com/nestjs/nest/issues/2379 – Kim Kern Aug 06 '19 at 19:03
  • I am on '6.5.3' which is the latest ;) – Reza Aug 06 '19 at 19:15
  • I submitted a bug in their repo, https://github.com/nestjs/nest/issues/2713 – Reza Aug 06 '19 at 19:24
  • 1
    btw I mark your response as answer, since it's right direction – Reza Aug 06 '19 at 19:28
  • As a workaround, you can just create the service manually in your test with `new LoggerService(rollbarMock)`. You don't need the TestingModule utitlities in a unit test, see https://github.com/nestjs/nest/issues/1786#issuecomment-475585609 – Kim Kern Aug 06 '19 at 19:32
  • It was my mistake , I have had 2 `describe` and I changed 1 and error was from the second one ;DDDD – Reza Aug 06 '19 at 19:47
  • Also would you please take a look at this question as well https://stackoverflow.com/questions/57383233/how-to-create-custom-provider-for-third-party-library-in-nestjs-with-access-to-r – Reza Aug 06 '19 at 20:03