Jest Mock Extended - Writing Typescript Friendly Tests
If you are writing tests in Typescript and aren’t utilizing the Jest Mock Extended library,
you are missing out on a fantastic testing experience and doing it the hard way.
The jest-mock-extended library
provides the mock
test utility. This utility helps create mocks that are typescript friendly,
so types do not get in the way of writing your tests.
Often when writing a test, you have specific objects and properties that are critical to the test.
The mock
utility allows you to create a mock object with just the properties you care about and nothing else.
This saves you time by not having to create a full mock object.
Example of Hello User Function
interface User {
id: string;
name: string;
profile: {
age: number;
phone: string;
address: string;
zip: string;
state: string;
}
}
function helloUser(user: User) {
return `hello ${user.name}`
}
Example of Testing without Jest Mock Extended
const user = {
id: '123',
name: 'John Doe',
profile: {
age: 30,
phone: '555-555-5555',
address: '123 Main St',
zip: '12345',
state: 'CA'
}
}
const res = helloUser(user)
expect(res).toBe('hello John Doe')
Example of Testing with Jest Mock Extended
import { mock } from 'jest-mock-extended';
const user = mock<User>({
name: 'John Doe'
});
const res = helloUser(user);
expect(res).toBe('hello John Doe');
The example above is actually a simple scenario but you can imagine how ugly it can get when you have more complex
classes and objects that you are testing. The mock
utility also mocks entire classes and their methods.
Example of Mocking a Class
import { mock } from 'jest-mock-extended';
class User {
constructor(public name: string) {}
sayHello() {
return `hello ${this.name}`
}
sayGoodbye() {
return `goodbye ${this.name}`
}
}
const user = mock<User>(); // all the methods are mocked automatically
user.sayHello();
user.sayHello.toHaveBeenCalled(); // => true
user.sayGoodbye.not.toHaveBeenCalled(); // => false
user.sayGoodbye.mockReturnValue('goodbye X');
user.sayGoodBye() // => goodbye X
The above is extremely useful in scenarios where you are injecting classes and want to mock their behavior.
Imagine trying to mock a class without the mock
utility. It would be a nightmare to mock all the methods and
properties.
class UserService {
constructor(private user: User) {
}
sayHello() {
return this.user.sayHello();
}
}
// you can now instantiate and test say hello with a simple mock
const user = mock<User>({ name: 'John Doe' });
const userService = new UserService(user);
expecet(userService.sayHello()).toBe('hello John Doe'); // => true