- [Instructor] So far we've been mocking functions
and modules which replaces.
What if we want to keep the original implementation around,
but still keep track of how it's being used?
With Jest, we can use spies to observe interactions.
The spyOn method creates a Jest mock function
similar to jest.fn and jest.mock,
but it also tracks calls to method name on the object.
Something to keep on mind, spyOn calls the spied method.
If that's not what you need,
use a mock implementation instead
and totally control the behavior.
When you're done with spying on the method,
it's best practice to restore the method back to normal.
Otherwise, other requires may have inconsistent behavior.
The spyOn mocks have a method mockRestore,
which does just that.
Within reservations, what are some things
that can be spied on?
We tested the validate function,
but we can go one step further and test to see
if it was called and how it was called.
We can also spy on validate in the create group
and use it to arbitrarily reject
to see how create handles validation errors.
Ready to get started?
Switch to VS code.
In the Explorer, navigate the lib
and open up reservations.test.js.
Scroll down to the end of validate,
then start a new async test spec.
So it should be called and reject empty input,
and then async, and then an arrow function expression.
We're going to spy on reservations,
specifically the validate method.
So const mock equals jest.spyOn,
and then it'll take reservations
and we're going to use the validate method.
Let's set up the test.
So const value equals, and we'll use the value of undefined.
We're going to await an expectation
that reservations.validate with a value
will reject and throw a message.
This is a bad assumption on the target.
There's no validate method on undefined, so it will throw.
I considered writing this correctly,
but I wanted to make the point
that just because something technically works
doesn't mean that it's working the best way.
So I'm going to check for a .rejects, plural, .toThrow,
then we're going to check for the string,
cannot read property and then escape validate,
then escape that again of undefined,
add a trailing semi-colon.
We can now check our mock.
So expect mock and expect that it was called with a value,
so .toBeCalledWith and then the value.
Finally, restore the mock.
So mock.mock.Restore, add trailing semi-colons,
and save the file.
That's great.
Let's use this technique on create.
Scroll to the end of the file.
After the existing spec, start a new one.
It should reject if validation fails using spyOn
and then async and then an arrow function expression.
Practically, this is going to function
as the same as the one above,
but we're going to be naming it differently
to avoid duplicate test names of best practice,
and we can compare the two approaches.
We're going to create a new mock.
So const mock using jest.spyOn on reservations
and specifically the validate method.
We then going to create a new error,
so const error equals new error
with the same value as above, fail.
This time, we're going to use mock.mockImplementation
with a function that returns a Promise.reject
with the error.
Let's use a value to look for on the other side of this.
I'm pretty sure that the string literal puppy
isn't a reservation.
So const value equals puppy.
Let's execute.
We're going to await expect reservations.create
with a value .rejects.toequal and then the error itself.
Now for the spying, I expect that the mock
toHaveBeenCalledTimes, one,
and I expect that the mock toHaveBeenCalledWith the value.
Finally, let's restore and wrap up.
So mock.mockRestore, execute it,
and add a trailing semi-colon and trailing semi-colon.
Save the file.
Then switch to the terminal.
Let's run our test suites, NPM test.
Excellent.
Two test suites passed out of two total
and 11 passed out of 11 total.
Let's clean up before wrapping up the chapter.
Close out the terminal and any open files.
Throughout this chapter we've been using Jest mocks
for replacing and inspecting using spies, stubs, and mocks.
We started with an overview of different ways
to replace code with test doubles.
We then learned about Jest versions of mocks
with special properties that track
how mocks are interacted with.
We wrote our first Jest mock using jest.fn,
then manually restored the mock function.
Building upon that, we mocked an entire module
with jest.mock, then manipulated the require cache
to mock module dependencies
so we can focus on testing just our code.
Finally, we use Jest spies to observe interactions
between components while controlling
how dependent code response.
We've been testing a portion of our codebase.
Is there any way to get a more comprehensive look
at the health of the entire codebase?