e2e test failing - getRepository is null - jestjs

When I run the e2e test(as integration tests) I get a getRepository null error. I import the entire app module in my test spec file(below),the error occurs, which says something like this:
[Nest] 47867 - 08/22/2022, 8:07:35 PM ERROR [ExceptionsHandler] Cannot read property 'getRepository' of null
TypeError: Cannot read property 'getRepository' of null
TypeError: Cannot read property 'getRepository' of null
at new usersService (/mypath/src/users/users.service.ts:35:42)
at Injector.instantiateClass (/mypath/node_modules/#nestjs/core/injector/injector.js:330:19)
at callback (/mypath/node_modules/#nestjs/core/injector/injector.js:48:41)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at Injector.loadInstance (/mypath/node_modules/#nestjs/core/injector/injector.js:52:9)
at Injector.loadProvider (/mypath/node_modules/#nestjs/core/injector/injector.js:74:9)
at Injector.resolveComponentHost (/mypath/node_modules/#nestjs/core/injector/injector.js:192:13)
at async Promise.all (index 0)
at Injector.loadCtorMetadata (/mypath/node_modules/#nestjs/core/injector/injector.js:358:23)
at Injector.resolveConstructorParams (/mypath/node_modules/#nestjs/core/injector/injector.js:89:26)
FAIL test/user.service.int-spec.ts (10.525 s)
GET /users
✓ (GET) / (102 ms)
✕ (GET) /users (62 ms)
● GET /users › (GET) /users
expected 200 "OK", got 500 "Internal Server Error"
26 |
27 | it('(GET) /users', () => {
> 28 | return request(app.getHttpServer()).get('/users').expect(200);
| ^
29 | });
30 | });
31 |
at Object.<anonymous> (test/user.service.int-spec.ts:28:59)
----
at Test._assertStatus (node_modules/supertest/lib/test.js:252:14)
at node_modules/supertest/lib/test.js:306:17
at Test._assertFunction (node_modules/supertest/lib/test.js:285:13)
at Test.assert (node_modules/supertest/lib/test.js:164:23)
at Server.localAssert (node_modules/supertest/lib/test.js:120:14)
The folder structure is this:
parent_folder
| package.json
| package-lock.json
| ---src
| \-User
| \-user.module.ts
| \-user.service.ts
| \-user.controller.ts
|...
| ---tests
| \-jest-int.json
| \-user.int-spec.ts
The jest config file contains this:
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": "../", // <<<--- I use absolute path path, so rootDir is "../"
"roots": ["<rootDir>"],
"modulePaths": ["<rootDir>"],
"moduleDirectories": ["node_modules"],
"testEnvironment": "node",
"testRegex": ".int-spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
}
}
The module contains this only:
import { Module } from '#nestjs/common';
import { UsersController } from './Users.controller';
import { UsersService } from './Users.service';
#Module({
providers: [UsersService],
controllers: [UsersController],
})
export class UserModule {}
The service contains:
#Injectable()
export class UsersService {
private userRepository: Repository<User>;
private fileRepository: Repository<file>;
private filedworthRepository: Repository<filedworth>;
private filedValueRepository: Repository<filedValue>;
private fileStrategyRepository: Repository<fileStrategy>;
private valueRepository: Repository<Value>;
private defaultData = {
created_date: new Date(),
updated_date: new Date(),
created_by: 'user',
updated_by: 'user',
};
constructor(#Inject(CONNECTION) private connection: DataSource) {
this.userRepository = connection.getRepository(user);
this.fileRepository = connection.getRepository(file);
this.filedworthRepository =
connection.getRepository(filedworth);
this.filedValueRepository =
connection.getRepository(filedValue);
this.fileStrategyRepository =
connection.getRepository(fileStrategy);
this.ValueRepository = connection.getRepository(Value);
}
...//other methods
}
The controller is:
#Controller('users')
export class usersController {
constructor(private usersService: usersService) {}
#Get()
getusers(
#Query()
query: GetUsersFilterDto,
) {
return this.usersService.getusers(query);
}
...//others
}
and the test file itself contains the following:
import { Test, TestingModule } from '#nestjs/testing';
import { INestApplication } from '#nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';
describe('GET /users ', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
afterAll(async () => {
await app.close();
});
it('(GET) /', () => {
return request(app.getHttpServer()).get('/').expect(200);
});
it('(GET) /users', () => {
return request(app.getHttpServer()).get('/users').expect(200);
});
});
I run the test using:
npm run test:int // "test:int": "jest -i --no-cache --detectOpenHandles --config ./test/jest-int.json"
Is there something I'm missing? Hopefully these are enough details to convey my issue.

You need to add CONNECTION as a provider to your test app: TestingModule =
await Test.createTestingModule({
imports: [AppModule],
providers: [
{ provide: CONNECTION, getRepository: jest.fn() },
],
}).compile();

What Georgi has mentioned was true, I hadn't provided the values of the dependency CONNECTION that was being injected. But, the syntax mentioned there didn't work, this did:
beforeAll(async () => {
const connection = await DataSource(myDB_Config);//hosturl, port etc.
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
})
.overrideProvider(CONNECTION)
.useValue(connection)
.compile();
app = moduleFixture.createNestApplication();
await app.init();
});

Related

NestJS Jest error: TypeError: Cannot read properties of undefined (reading '[any variable from required config]')

While trying to cover out project in unit tests using nest's jest I've bumped into a problem of a testing module not being able to pull variables from config.
Basically, I have an EmailService, I want to test it, I use it as a Provider in my testing module. Naturally, as EmailService takes ConfigService in its constructor to pull some variables from config (that initially come from env) I put ConfigService into the providers array as well... well, then upon initialization testing module drops
NestJS Jest error: TypeError: Cannot read properties of undefined (reading 'region')
note: region variable is taken from env in a registered config module
code example of my test that throws
describe('EmailService', () => {
let emailService: EmailService;
let configService: ConfigService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [EmailService, ConfigService],
}).compile();
emailService = module.get<EmailService>(EmailService);
configService = module.get<ConfigService>(ConfigService);
});
it('should be defined', () => {
expect(emailService).toBeDefined();
});
});
I have came to the conclusion that it throws an error specifically because EmailService takes ConfigService in it's constructor in this way:
export class EmailService {
private readonly config: IAwsConfig;
private readonly region: IRegion;
constructor(private readonly configService: ConfigService) {
this.config = this.configService.get('aws');
this.region = this.config.region;
}
aditional info: both EmailService and ConfigService work just fine during a normal runtime, it only fails during jest testing
seems like this.configService.get method returns 'undefined' during a test run and i'm, not sure why or how to fix it. Any ideas?
In case you don't want to import the entire ConfigService but just the config values themselves, then you use them in the test as follows :)
// my-config.ts
import { registerAs } from '#nestjs/config';
export default registerAs('myConfig', () => ({ propA: 'aa', propB: 123 }));
import { Inject } from '#nestjs/common';
import { ConfigType } from '#nestjs/config';
import myConfig from './my-config.ts';
export class EmailService {
private propA: string;
private propB: number;
constructor(
#Inject(myConfig.KEY) config: ConfigType<typeof myConfig>
) {
this.propA = config.propA;
this.propB = config.propB;
}
}
import { ConfigModule, registerAs } from '#nestjs/config';
import { Test, TestingModule } from '#nestjs/testing';
describe('Test', () => {
const configValues = { propA: 'aa', proprB: 123 };
const config = registerAs('testConfig', () => configValues);
beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
imports: [ConfigModule.forFeature(config)],
providers: [EmailService],
}).compile();
});
});
Was not able to find an answer for 2 hours straight, but then, 10 minutes after asking a question, there you go, an answer.
Seems like ConfigService doesn't provide configs during jest testing so you have to provide it in the testing module with replaced get method, something like such:
providers: [
EmailService,
{
provide: ConfigService,
useValue: {
get: jest.fn((key: string) => {
return hardcodedConfigFromWithinTheTestFile;
}),
},
},
],

End-to-end testing NestJS with Fastify: "#nestjs/platform-express" package is missing" error

I have fresh NestJS application using Fastify. When trying to npm run test:e2e I got the following error:
[Nest] 14894 - 11/19/2021, 10:29:10 PM [ExceptionHandler] The "#nestjs/platform-express" package is missing. Please, make sure to install this library ($ npm install #nestjs/platform-express) to take advantage of NestFactory.
● process.exit called with "1"
12 | }).compile();
13 |
> 14 | app = moduleFixture.createNestApplication();
| ^
15 | await app.init();
16 | });
17 |
at Object.loadPackage (../node_modules/#nestjs/common/utils/load-package.util.js:13:17)
at TestingModule.createHttpAdapter (../node_modules/#nestjs/testing/testing-module.js:25:56)
at TestingModule.createNestApplication (../node_modules/#nestjs/testing/testing-module.js:13:43)
at Object.<anonymous> (app.e2e-spec.ts:14:25)
RUNS test/app.e2e-spec.ts
Process finished with exit code 1
Seems odd, because why would platform-express be needed for fastify-based app?
Appears that after switching to Fastify we also need to update test/app.e2e-spec.ts accordingly:
import { Test, TestingModule } from '#nestjs/testing';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
import { FastifyAdapter, NestFastifyApplication } from '#nestjs/platform-fastify';
describe('AppController (e2e)', () => {
let app: NestFastifyApplication;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication<NestFastifyApplication>(new FastifyAdapter());
await app.init();
await app.getHttpAdapter().getInstance().ready();
});
afterEach(async () => {
await app.close();
});
it('/ (GET)', () => {
return request(app.getHttpServer()).get('/').expect(200).expect('Hello World!');
});
});

Mocking custom Hook with jest and enzyme results in 'xxx is not a function or its return value is not iterable' Error

I am very new to jest and enzyme. In my Project I will use a SPA React based Application. Containing a Context Provider for the data, also several hooks. I Using now Jest (with ts-jest and enzyme)
My jest.config looks like this
module.exports = {
"roots": [
"<rootDir>/src"
],
"transform": {
"^.+\\.tsx?$": "ts-jest"
},
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
],
"snapshotSerializers": ["enzyme-to-json/serializer"]
So my first stept so test UI components works.
Next step was to test componentes with mocked data. But there I got the error described at the bottom.
I have a functional component like this:
export default function CurrentWeather(props: ICurrentWeatherProps) {
const [data, Reload] = useCurrentWeather(props.locationID);
return (<div>......</div>)
}
You will notice the useCurrentWeather hook, here is the code for this:
import { useEffect, useState } from 'react';
import { useLocationState } from '../context/locationContext';
import { ILocationData } from './useLocations';
import _ from 'lodash';
...
export default function useCurrentWeater(locationId: number) {
const locationState = useLocationState();
const Reload = () => { GetData() }
const [Data, SetData] = useState<IWeatherDataInfo>({Id:0,ConditionIcon:'',Date:new Date(),MaxTemp:0, MinTemp:0});
async function GetData() { .... }
useEffect(Reload, [locationState.data, locationId]);
return [Data, Reload] as const;
}
Now I wand to mock these Hook. I tried following
import React from 'react';
import { configure, shallow, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import CurrentWeather from '../components/Weather/CurrentWeather';
import { IWeatherDataInfo } from '../Hooks/useWeaters';
configure({ adapter: new Adapter() });
const mockWeatherReload = jest.fn();
const mockdata: IWeatherDataInfo = { Date: new Date(), ConditionIcon: "", MinTemp: 0, MaxTemp: 10 };
jest.mock('../Hooks/useCurrentWeather', () => ({
useCurrentWeather: jest.fn(()=>{ [mockdata, mockWeatherReload]})
}));
describe("WeatherWidget", () => {
it("RenderOnlyAddButton", () => {
const container = shallow(<CurrentWeather locationID={1} hidden={false} />);
});
});
Now, when I execute this test, I will get this error result:
src/tests/WeatherWidget.test.tsx
● WeatherWidget › RenderOnlyAddButton
TypeError: (0 , _useCurrentWeather.default) is not a function or its return value is not iterable
9 |
10 | export default function CurrentWeather(props: ICurrentWeatherProps) {
> 11 | const [data, Reload] = useCurrentWeather(props.locationID);
| ^
12 | return (
What I'm doing wrong here? Is there what I'm missing?
Try like this:(below should be your functional component's test file)
const mockUseCurrentWeather = jest.fn();
jest.mock("put here the absolute path", () => ({
__esModule: true,
useCurrentWeather: (...args: any) => mockUseCurrentWeather(...args),
}));
describe("WeatherWidget", () => {
beforeEach(() => {
mockUseCurrentWeather.mockClear();
mockUseCurrentWeather.mockReturnValue([undefined, undefined]);
});
it("RenderOnlyAddButton", () => {
mockUseCurrentWeather.mockClear();
mockUseCurrentWeather.mockReturnValue([undefined, undefined]);
const container = shallow(<CurrentWeather locationID={1} hidden={false} />);
});
});

Nest can't resolve dependencies in the RootTestModule context when I use Bazel Test

I need to run my tests in the bezel. how can I solve this mysterious problem?
I have a nestjs project contains multiple apps and libs. When I run the test yarn jest --config ./jest.config.json libs/lib1, it works perfectly. However when I run with bezel bazel test //libs/lib1/... it gives me an error "Nest can't resolve dependencies ... Please make sure that the argument dependency at index ... is available in the RootTestModule context.".
REPO
https://github.com/smhmayboudi/bazel_jest_nestjs
I find out that the order of mapping at jest.config.json is important.
this one works well ( shows test + coverage ), but dependency problem
"moduleNameMapper": {
"#melo/lib1": "<rootDir>/libs/lib1/src",
"#melo/lib1/(.*)": "<rootDir>/libs/lib1/src/$1",
},
this one works ( show just pass message with out actual test result and coverage !? )
"moduleNameMapper": {
"#melo/lib1/(.*)": "<rootDir>/libs/lib1/src/$1",
"#melo/lib1": "<rootDir>/libs/lib1/src",
},
Jest Config
{
"coverageReporters": ["lcov", "text-summary"],
"moduleNameMapper": {
"#melo/libs1": "<rootDir>/libs/libs1/src",
"#melo/libs1/(.*)": "<rootDir>/libs/libs1/src/$1",
},
"modulePathIgnorePatterns": ["/bazel-out/", "/node_modules/"],
"preset": "ts-jest",
"testEnvironment": "node"
}
Bazel Config
ts_library(
name = "lib1_test_ts_library",
srcs = glob(["*spec.ts"]),
runtime = "nodejs",
deps = [
":lib1_ts_library",
"#npm//#nestjs/common",
"#npm//#nestjs/testing",
"#npm//#types/jest",
"#npm//rxjs",
"#npm//ts-jest",
],
)
jest_test(
name = "lib1_jest_test",
srcs = glob(["*spec.ts"]),
jest_config = "//:jest.config.json",
deps = [
":lib1_test_ts_library",
],
coverage = True,
)
Error Log
INFO: Invocation ID: 84f45d55-c6e4-4c2a-b05d-367d0f84baf7
INFO: Analyzed target //libs/lib1/src:lib1_jest_test (633 packages loaded, 19569 targets configured).
INFO: Found 1 test target...
WARNING: failed to create one or more convenience symlinks for prefix 'dist/':
cannot create symbolic link bazel-out -> /Users/WHOAMI/Developer/MY_PROJECT/bazel-out/execroot/melo/bazel-out: /Users/WHOAMI/Developer/MY_PROJECT/bazel-out (File exists)
FAIL: //libs/lib1/src:lib1_jest_test (see /Users/WHOAMI/Developer/MY_PROJECT/bazel-out/execroot/melo/bazel-out/darwin-fastbuild/testlogs/libs/lib1/src/lib1_jest_test/test.log)
INFO: From Testing //libs/lib1/src:lib1_jest_test:
==================== Test output for //libs/lib1/src:lib1_jest_test:
PASS libs/lib1/src/lib1.util.spec.ts (23.866 s)
PASS libs/lib1/src/lib1.interceptor.spec.ts (23.977 s)
FAIL libs/lib1/src/lib1.service.spec.ts (24.717 s)
● ApmService › should be defined
Nest can't resolve dependencies of the ApmService (?). Please make sure that the argument dependency at index [0] is available in the RootTestModule context.
Potential solutions:
- If dependency is a provider, is it part of the current RootTestModule?
- If dependency is exported from a separate #Module, is that module imported within RootTestModule?
#Module({
imports: [ /* the Module containing dependency */ ]
})
at Injector.resolveSingleParam (../../../../../../../../node_modules/#nestjs/core/injector/injector.js:134:19)
at resolveParam (../../../../../../../../node_modules/#nestjs/core/injector/injector.js:102:49)
at Array.map (<anonymous>)
at Injector.resolveConstructorParams (../../../../../../../../node_modules/#nestjs/core/injector/injector.js:117:58)
at Injector.loadInstance (../../../../../../../../node_modules/#nestjs/core/injector/injector.js:81:20)
at Injector.loadProvider (../../../../../../../../node_modules/#nestjs/core/injector/injector.js:38:20)
at ../../../../../../../../node_modules/#nestjs/core/injector/instance-loader.js:43:62
at Array.map (<anonymous>)
at InstanceLoader.createInstancesOfProviders (../../../../../../../../node_modules/#nestjs/core/injector/instance-loader.js:43:36)
at ../../../../../../../../node_modules/#nestjs/core/injector/instance-loader.js:28:24
● ApmService › should be defined
expect(received).toBeDefined()
Received: undefined
56 |
57 | it("should be defined", () => {
> 58 | expect(service).toBeDefined();
| ^
59 | });
60 |
61 | it("start should be called", () => {
at Object.<anonymous> (libs/lib1/src/lib1.service.spec.ts:58:21)
...
Test Suites: 2 failed, 2 passed, 4 total
Tests: 27 failed, 3 todo, 6 passed, 36 total
Snapshots: 0 total
Time: 26.102 s
Ran all test suites within paths "libs/lib1/src/lib1.decorator.spec.ts", "libs/lib1/src/lib1.interceptor.spec.ts", "libs/lib1/src/lib1.service.spec.ts", "libs/lib1/src/lib1.util.spec.ts".
================================================================================
Target //libs/lib1/src:lib1_jest_test up-to-date:
dist/bin/libs/lib1/src/lib1_jest_test.sh
dist/bin/libs/lib1/src/lib1_jest_test_loader.js
dist/bin/libs/lib1/src/lib1_jest_test_require_patch.js
INFO: Elapsed time: 83.878s, Critical Path: 59.53s
INFO: 4 processes: 4 local.
INFO: Build completed, 1 test FAILED, 12 total actions
//libs/lib1/src:lib1_jest_test FAILED in 28.2s
/Users/WHOAMI/Developer/MY_PROJECT/bazel-out/execroot/melo/bazel-out/darwin-fastbuild/testlogs/libs/lib1/src/lib1_jest_test/test.log
INFO: Build completed, 1 test FAILED, 12 total actions
Add providers to your RootTestModule. Nest doesn't automatically include the services in your test, depending on if you used the cli vs creating the files/folders directly.
const module: TestingModule = await Test.createTestingModule({
providers: [/** Services goes here **/],
controllers: [CustomersController],
}).compile();
Not working vs Working below
import { Test, TestingModule } from '#nestjs/testing';
import { CustomersController } from './customers.controller';
describe('CustomersController', () => {
let controller: CustomersController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [CustomersController],
}).compile();
controller = module.get<CustomersController>(CustomersController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
it('shoud return customer', async () => {
const tcase = await controller.d({});
expect(tcase).toHaveProperty('firstName');
})
});
Working (I had the exact error message with different filenames ofcourse)
import { Test, TestingModule } from '#nestjs/testing';
import { CustomersController } from './customers.controller';
import { CustomersService } from './customers.service';
describe('CustomersController', () => {
let controller: CustomersController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [CustomersService],
controllers: [CustomersController],
}).compile();
controller = module.get<CustomersController>(CustomersController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
it('shoud return customer', async () => {
const tcase = await controller.d({});
expect(tcase).toHaveProperty('firstName');
})
});
A potential workaround is to declare "empty"
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [{
provide: CustomerService,
useValue: {},
}],
controllers: [CustomersController],
}).compile();
The solution that worked for me was following the unit test examples of the library.
import { Test, TestingModule } from '#nestjs/testing';
import { CreateUserDto } from './dto/create-user.dto';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
const createUserDto: CreateUserDto = {
firstName: 'firstName #1',
lastName: 'lastName #1',
};
describe('UsersController', () => {
let usersController: UsersController;
let usersService: UsersService;
beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
controllers: [UsersController],
providers: [ // <---------- THIS IS THE MOST IMPORTANT SECTION TO SOLVE THIS ISSUE.
{
provide: UsersService,
useValue: {
create: jest
.fn()
.mockImplementation((user: CreateUserDto) =>
Promise.resolve({ id: '1', ...user }),
),
findAll: jest.fn().mockResolvedValue([
{
firstName: 'firstName #1',
lastName: 'lastName #1',
},
{
firstName: 'firstName #2',
lastName: 'lastName #2',
},
]),
findOne: jest.fn().mockImplementation((id: string) =>
Promise.resolve({
firstName: 'firstName #1',
lastName: 'lastName #1',
id,
}),
),
remove: jest.fn(),
},
},
],
}).compile();
usersController = app.get<UsersController>(UsersController);
usersService = app.get<UsersService>(UsersService);
});
it('should be defined', () => {
expect(usersController).toBeDefined();
});
describe('create()', () => {
it('should create a user', () => {
expect(usersController.create(createUserDto)).resolves.toEqual({
id: '1',
...createUserDto,
});
expect(usersService.create).toHaveBeenCalled();
expect(usersService.create).toHaveBeenCalledWith(createUserDto);
});
});
describe('findAll()', () => {
it('should find all users ', () => {
usersController.findAll();
expect(usersService.findAll).toHaveBeenCalled();
});
});
describe('findOne()', () => {
it('should find a user', () => {
usersController.findOne('1');
expect(usersService.findOne).toHaveBeenCalled();
expect(usersController.findOne('1')).resolves.toEqual({
firstName: 'firstName #1',
lastName: 'lastName #1',
id: '1',
});
});
});
describe('remove()', () => {
it('should remove the user', () => {
usersController.remove('2');
expect(usersService.remove).toHaveBeenCalled();
});
});
});
The key change was to update the 'providers' property to use an object instead of just using: providers: [CustomersService],.

NestJS/TypeORM unit testing: Can't resolve dependencies of JwtService

I'm trying to unit test this controller and mock away the services/repositories that it needs.
#Controller('auth')
export class AuthController {
constructor(
private readonly authService: AuthService,
private readonly usersService: UsersService,
) {}
#Post('register')
public async registerAsync(#Body() createUserModel: CreateUserModel) {
const result = await this.authenticationService.registerUserAsync(createUserModel);
// more code here
}
#Post('login')
public async loginAsync(#Body() login: LoginModel): Promise<{ accessToken: string }> {
const user = await this.usersService.getUserByUsernameAsync(login.username);
// more code here
}
}
Here is my unit test file:
describe('AuthController', () => {
let authController: AuthController;
let authService: AuthService;
beforeEach(async () => {
const moduleRef: TestingModule = await Test.createTestingModule({
imports: [JwtModule],
controllers: [AuthController],
providers: [
AuthService,
UsersService,
{
provide: getRepositoryToken(User),
useClass: Repository,
},
],
}).compile();
authController = moduleRef.get<AuthenticationController>(AuthenticationController);
authService = moduleRef.get<AuthenticationService>(AuthenticationService);
});
describe('registerAsync', () => {
it('Returns registration status when user registration succeeds', async () => {
let createUserModel: CreateUserModel = {...}
let registrationStatus: RegistrationStatus = {
success: true,
message: 'User registered successfully',
};
jest.spyOn(authService, 'registerUserAsync').mockImplementation(() =>
Promise.resolve(registrationStatus),
);
expect(await authController.registerAsync(createUserModel)).toEqual(registrationStatus);
});
});
});
But when running this, I get the following error(s):
● AuthController › registerAsync › Returns registration status when user registration succeeds
Nest can't resolve dependencies of the JwtService (?). Please make sure that the argument JWT_MODULE_OPTIONS at index [0] is available in the JwtModule context.
Potential solutions:
- If JWT_MODULE_OPTIONS is a provider, is it part of the current JwtModule?
- If JWT_MODULE_OPTIONS is exported from a separate #Module, is that module imported within JwtModule?
#Module({
imports: [ /* the Module containing JWT_MODULE_OPTIONS */ ]
})
at Injector.lookupComponentInParentModules (../node_modules/#nestjs/core/injector/injector.js:191:19)
at Injector.resolveComponentInstance (../node_modules/#nestjs/core/injector/injector.js:147:33)
at resolveParam (../node_modules/#nestjs/core/injector/injector.js:101:38)
at async Promise.all (index 0)
at Injector.resolveConstructorParams (../node_modules/#nestjs/core/injector/injector.js:116:27)
at Injector.loadInstance (../node_modules/#nestjs/core/injector/injector.js:80:9)
at Injector.loadProvider (../node_modules/#nestjs/core/injector/injector.js:37:9)
at Injector.lookupComponentInImports (../node_modules/#nestjs/core/injector/injector.js:223:17)
at Injector.lookupComponentInParentModules (../node_modules/#nestjs/core/injector/injector.js:189:33)
● AuthController › registerAsync › Returns registration status when user registration succeeds
Cannot spyOn on a primitive value; undefined given
48 | };
49 |
> 50 | jest.spyOn(authService, 'registerUserAsync').mockImplementation(() =>
| ^
51 | Promise.resolve(registrationStatus),
52 | );
53 |
at ModuleMockerClass.spyOn (../node_modules/jest-mock/build/index.js:780:13)
at Object.<anonymous> (Authentication/authentication.controller.spec.ts:50:18)
I'm not quite sure how to proceed so I'd like some help.
There's a few things I'm noticing here:
if you're testing the controller, you shouldn't need to mock more than one level deep pf services
you should almost never have a use case where you need an imports array in a unit test.
What you can do for your test case instead is something similar to the following:
beforeEach(async () => {
const modRef = await Test.createTestingModule({
controllers: [AuthController],
providers: [
{
provide: AuthService,
useValue: {
registerUserAsync: jest.fn(),
}
},
{
provide: UserService,
useValue: {
getUserByUsernameAsync: jest.fn(),
}
}
]
}).compile();
});
Now you can get the auth service and user service using modRef.get() and save them to a variable to add mocks to them later. You can check out this testing repository which has a lot of other examples.
Since you are registering AuthService in the dependency injection container and just spying on registerUserAsync, it requires JWTService to be registered as well.
You need to register dependencies that are injected in AuthService:
const moduleRef: TestingModule = await Test.createTestingModule({
imports: [JwtModule],
controllers: [AuthController],
providers: [
AuthService,
UsersService,
JWTService, // <--here
{
provide: getRepositoryToken(User),
useClass: Repository,
},
],
}).compile();
or register a fully mocked AuthService that doesn't need any other dependency:
const moduleRef: TestingModule = await Test.createTestingModule({
imports: [JwtModule],
controllers: [AuthController],
providers: [
{
provide: AuthService,
useValue: {
registerUserAsync: jest.fn(), // <--here
}
},
{
provide: getRepositoryToken(User),
useClass: Repository,
},
],
}).compile();
If you're building out a full integration test suite for NestJS then it will be easy to hit this error if you import a module that imports the AuthService. That will inevitably require the JwtService which will error out with: Nest can't resolve dependencies of the JwtService (?). Please make sure that the argument JWT_MODULE_OPTIONS at index [0] is available in the RootTestModule context.
Here's how I resolved this. I added:
JwtModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
secret: configService.get('JWT_SECRET'),
signOptions: { expiresIn: '1d' }
})
}),
To my imports: [] function inside my await Test.createTestingModule({ call
The final important thing to do was to not import JwtService directly. Instead, initialize JwtModule with the above code which by extension itself should internally initialize JwtService correctly.

Resources