I am using nodemailer in my NestJS application to send emails. To prevent real emails from being sent whenever I run tests, I want to create a mocking object of nodemailer that I can use in my tests. However, I am not sure how to create this object properly.
When I tried to make a mocking object, there is "connect ECONNREFUSED 127.0.0.1:587". This error is that "nodemailer needs an access connect to gmail". So it added the setting values using docenv code.
dotenv.config({
path: path.resolve(`src/config/env/.development.env`),
});
After that, test is success and it always send the verification mail.But I don't want to send emails when running test and want to use mocking object.
I have uploaded the entire code to CodeSandBox except .env, so I hope it is helpful for reference.
Source code (codeSandbox) : https://codesandbox.io/p/sandbox/crazy-bouman-2tvq79
You can mock your EmailService
from your UsersService
. Also, if you want to test EmailService
you can either use jest.mock()
, or you inject nodemailer as a dependency to your service, and then you will be able to mock it easily by using Nest's testing module.
EmailService
in UsersService
describe('UsersService', () => {
let module: TestingModule;
let service: UsersService;
let sendUserVerficationEmailMock;
beforeAll(() => {
dotenv.config({
path: path.resolve(`src/config/env/.development.env`),
});
});
beforeEach(async () => {
sendUserVerficationEmailMock = jest
.fn()
.mockImplementation(() => console.log('email sent'));
module = await Test.createTestingModule({
imports: [
TypeOrmModule.forRoot({
type: 'sqlite',
database: ':memory:',
entities: [UserEntity],
synchronize: true,
}),
UsersModule,
],
})
.overrideProvider(EmailService)
.useValue({
sendUserVerficationEmail: sendUserVerficationEmailMock,
})
.compile();
service = module.get(UsersService);
await service.createUser('tom', '[email protected]', '!@#$');
});
it('should throw Error when email is existed', async () => {
const result = service.createUser('tom', '[email protected]', '!@#$');
expect(sendUserVerficationEmailMock).toBeCalledTimes(1);
await expect(result).rejects.toThrowError(
new UnprocessableEntityException('이미 가입된 이메일 입니다.'),
);
});
});
There are many examples online on how to mock third-party libraries with jest. You can try the different approaches mentioned here: https://jestjs.io/docs/jest-object.
Or even better (IMO), is to inject NodeMailer into your service and follow the same approach as we did in the previous example
You may also want to consider using a NestJS wrapper module for NodeMailer, something like NestJS Mailer
as it offers these dependencies as NestJS modules and providers which are easier to mock.