Nestjs Testing Module doesn't injected dependency when using Vitest as test runner

80 views Asked by At

I can't get the NestJS testing module to work with Vitest, it seems to not inject the services correctly. I got an undefined error when i run tests.

I created two services that I then injected into this service.

import { InjectedOneService } from './injected-one.service';
import { InjectedTwoService } from './intjected-two.service';

export class RandomService {
  constructor(
    private readonly injectedOneService: InjectedOneService,
    private readonly injectedTwoService: InjectedTwoService,
  ) { }
  getStr() {
    return `${this.injectedOneService.foo()} ${this.injectedTwoService.bar()}`;
  }
}
import { Injectable } from '@nestjs/common';

@Injectable()
export class InjectedOneService {
  foo() {
    return 'foo';
  }
}
import { Injectable } from '@nestjs/common';

@Injectable()
export class InjectedTwoService {
  constructor() { }
  bar() {
    return 'bar';
  }
}

Then i wrote this test, it's working fine without testing module

import { Test, TestingModule } from '@nestjs/testing';
import { RandomService } from './service';
import { InjectedOneService } from './injected-one.service';
import { InjectedTwoService } from './intjected-two.service';
import { describe, it, expect, vi } from 'vitest';

describe('Service', () => {
  it('should work without testing module', () => {
    const injectedOneMockService = new InjectedOneService();
    const injectedTwoMockService = new InjectedTwoService();
    const result = new RandomService(
      injectedOneMockService,
      injectedTwoMockService,
    );
    injectedOneMockService.foo = vi.fn().mockImplementation(() => 'mock foo');
    expect(result).toBeDefined();
    expect(result.getStr()).toBe('mock foo bar');
  });
  it('should work with testing module', async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [RandomService, InjectedOneService, InjectedTwoService],
    }).compile();

    const injectedOneMockService =
      module.get<InjectedOneService>(InjectedOneService);

    const injectedTwoMockService =
      module.get<InjectedTwoService>(InjectedTwoService);

    const result = module.get<RandomService>(RandomService);

    injectedOneMockService.foo = vi.fn().mockImplementation(() => 'mock foo');
    injectedTwoMockService.bar = vi.fn().mockImplementation(() => 'mock bar');

    expect(result).toBeDefined();
    expect(result.getStr()).toBe('mock foo mock bar');
  });
});

I got this error

TypeError: Cannot read properties of undefined (reading 'foo')
 ❯ RandomService.getStr src/vitest-test/service.ts:10:39
      8|   ) { }
      9|   getStr() {
     10|     return `${this.injectedOneService.foo()} ${this.injectedTwoService.bar()}`;
       |                                       ^
     11|   }
     12| }

I followed the documentation and installed the SWC plugin to be able to build the test files, and I have no idea where the problem could come from.

Edit :my vitest.config.ts file

    import swc from 'unplugin-swc';
    import { defineConfig } from 'vitest/config';
    
    export default defineConfig({
      test: {
        globals: true,
        root: './',
      },
      plugins: [
        swc.vite({
          module: { type: 'es6' },
        }),
      ],
    });
1

There are 1 answers

2
Jay McDoniel On

Your RandomService is missing the @Injectable() decorator, which is what forces Typescript (or swc in your case) to emit the decorator metadata that is necessary for Nest to read to know what to inject to which location.