I’m encountering an issue verifying if my mocked save
method is being called in my tests. Each time I run my tests, I receive information indicating that the number of calls is 0
. However, everything works correctly in the production environment: new data is saved, and the ORM’s save method is called as expected.
Here's my example test
describe('updateEmail', () => {
it('should update user email', async () => {
const user: User = {
id: 'abc',
email: 'old@email.org',
password: 'password',
};
const updatedUser: User = Object.assign({}, user);
updatedUser.email = 'new@email.org';
const findOneSpy = jest
.spyOn(repository, 'findOne')
.mockResolvedValue(user);
const saveSpy = jest
.spyOn(repository, 'save')
.mockResolvedValue(updatedUser);
expect(
service.updateEmail({
oldEmail: user.email,
newEmail: updatedUser.email,
}),
).resolves.toEqual(updatedUser);
expect(findOneSpy).toHaveBeenCalledWith({ where: { email: user.email } });
expect(saveSpy).toHaveBeenCalledWith(updatedUser);
});
});
And a simple logic for that
async updateEmail({ oldEmail, newEmail }: UpdateEmailDto) {
const user = await this.findByEmail(oldEmail);
if (!user) throw new NotFoundException();
user.email = newEmail;
return this.usersRepository.save(user);
}
There's also an error that I got.
expect(jest.fn()).toHaveBeenCalledWith(...expected)
Expected: {"email": "new@email.org", "id": "abc", "password": "password"}
Number of calls: 0
133 | expect(findOneSpy).toHaveBeenCalledWith({ where: { email: user.email } });
134 |
> 135 | expect(saveSpy).toHaveBeenCalledWith(updatedUser);
| ^
136 | });
137 | });
138 | });
at Object.<anonymous> (users/users.service.spec.ts:135:23)
```
Just to add a bit of guidance, that could prevent any similar issues in the future : I would advocate for a cleaner test structure.
describe('updateEmail', () => {
it('should update user email', async () => {
// First, a section with your declarations and the mocked values, just like you had, but without the extra spaces
const user: User = {
id: 'abc',
email: 'old@email.org',
password: 'password',
};
const updatedUser: User = { ...user, email: 'new@email.org' };
const findOneSpy = jest
.spyOn(repository, 'findOne')
.mockResolvedValue(user);
const saveSpy = jest
.spyOn(repository, 'save')
.mockResolvedValue(updatedUser);
// Then, a section with your test execution, returning a result
const result = await service.updateEmail({
oldEmail: user.email,
newEmail: updatedUser.email,
});
// Finally, your assertion section
expect(result).toEqual(updatedUser);
expect(findOneSpy).toHaveBeenCalledWith({ where: { email: user.email } });
expect(saveSpy).toHaveBeenCalledWith(updatedUser);
});
});
Since you had the 2nd and 3rd section mixed up together, it probably led to some confusion and a hard time debugging for you. By splitting your test this way, I feel like it would have been easier to see that your service.updateEmail
call was not awaited. I hope this helps you in future developments!