Reputation: 3
I'm new to testing and going for good code coverage.
I have a pre-save hook on my user model that deals with hashing a password, now I only want this to run when the password field has been modified.
How do I test this if statement? Is it a case of saving a user, updating a user, then saving it again and testing for the password?
Another question. What is the best practice here? To have it as a pre-save hook or a method on the user model?
UserSchema.pre('save', async function(next) {
// Only run this function if password was modified
if (!this.isModified('password')) return next();
// Hash the password
this.password = await bcrypt.hash(this.password, 12);
// Remove passwordConfirm field
this.passwordConfirm = undefined;
next();
});
Upvotes: 0
Views: 902
Reputation: 102207
Here is a unit test solution:
index.js
:
import { Schema } from 'mongoose';
import bcrypt from 'bcrypt';
const UserSchema = new Schema();
UserSchema.pre('save', userPreSaveHook);
export async function userPreSaveHook(next) {
// Only run this function if password was modified
if (!this.isModified('password')) return next();
// Hash the password
this.password = await bcrypt.hash(this.password, 12);
// Remove passwordConfirm field
this.passwordConfirm = undefined;
next();
}
index.spec.js
:
import { userPreSaveHook } from './';
describe('userPreSaveHook', () => {
test('should execute next middleware when password is modified', async () => {
const mNext = jest.fn();
const mContext = {
isModified: jest.fn()
};
mContext.isModified.mockReturnValueOnce(false);
await userPreSaveHook.call(mContext, mNext);
expect(mContext.isModified).toBeCalledWith('password');
expect(mNext).toBeCalledTimes(1);
});
test('should has password and remove passwordConfirm field', async () => {
const mNext = jest.fn();
const mContext = {
isModified: jest.fn(),
passwordConfirm: 'aaa',
password: '123456'
};
mContext.isModified.mockReturnValueOnce(true);
await userPreSaveHook.call(mContext, mNext);
expect(mContext.isModified).toBeCalledWith('password');
expect(mNext).toBeCalledTimes(1);
expect(mContext.passwordConfirm).toBeUndefined();
expect(mContext.password).not.toBe('123456');
});
});
Unit test result with 100% coverage:
PASS src/stackoverflow/58701700/index.spec.js (12.23s)
userPreSaveHook
✓ should execute next middleware when password is modified (9ms)
✓ should has password and remove passwordConfirm field (295ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.js | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 12.689s, estimated 14s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58701700
Upvotes: 3