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' },
}),
],
});
Your
RandomServiceis 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.