Check out a free preview of the full Enterprise UI Development: Testing & Code Quality course

The "Spying on Methods" Lesson is part of the full, Enterprise UI Development: Testing & Code Quality course featured in this preview video. Here's what you'd learn in this lesson:

Steve explains that spies are similar to mocks except they watch a single method of an object. An alias can be used to call the underlying method. The method can also be added to tests to ensure it's called correctly.


Transcript from the "Spying on Methods" Lesson

>> A spy is like a mock, but you can spy on just one method of an object, right? It's basically the same idea otherwise, so I've got that arithmetic on I can also, let's do it actually with this one. So I could say, let's say we'll deal with log, and we'll say vi.spyOn(the console object.

And why don't you look at its log method for me, right? Cool, and then we could do stuff like either that log that we saw before. And we could say log, I didn't realize that if I call it log and I try to use console log, it's log log, but life's hard.

1, 2, and 3, you can see that with a spy, it still did its thing, it's still logged to the console. If you don't want that to happen, you could do something like .mockImplementation. You can also fake a promise returning. There's lots of useful cases where you would do all these things.

And they're very specific and you'll know it when you see it, but again, treat it. So you can either mock the return value just once and then put it back the way it was. You can just mock the return value, you can change with this, you can do all sorts of things that you need to do.

Keep in mind, the more clever that you get, the more, what are you doing, [LAUGH] right? You can do mockImplementation. And where I could make it a no-op, and then it won't log to the console. This could also be useful if you have a library that has a console log in it, right?

For that test, you could get it to be quiet for a moment, right? There are times, there's very specific times in places where it's like, I need this thing that, especially if it's a third party library, you might choose to do something, right? There are lots of cases, I'll show you how to do this for a third party library as well, but this will, in fact, work.

And so now I could also look at now like expect. It gives the same API as a mock. Expect(console.log), which is not in my test, as you notice. My log function is, it calls console.log under the hood, right? And this could be local storage.set item, here's a time where you're allowed to use a mock or a spy, ready?

Geolocation, right? Time also, but that's a separate topic. The browser APIs that you don't fully control, and you wanna be if low battery don't run this worker, right? In this zone, I wanna see if my distance algorithm works. I would argue it should be able to take the actual latitude, longitude, and return that, that's what you should test, but sometimes you don't control the code.

This whole course is about you came to a code base that you didn't make the mess, you have to clean it up. There are things that you can do that you can use strategically. So expect(console.log) toHaveBeenCalled. Yeah, we didn't call console.log in this file, and we also made it be quiet and not do its thing, but we were able to track that it was called like at all.

And BeenCalledWith, Right, and so you can get some introspection. I am okay with you using it to test your code was called the way you thought. If you start mocking out everything, we're gonna have words, right? And so it is useful tool, it exists. The other thing that I will show you is if you need to do it for a third party library.

Maybe you have this very high-level function that you use throughout your application, even one that I have in my code base, and we can maybe take a look at it later, is I have one, and this is a pattern I really like. And so now we go less from the test and more from a thing that I think you should just do when your code base, is I don't use fetch in my code base, I use this request from API.

Do you know what it does under the hood? It calls fetch, right? But I might have that with this string to be typed to only allow my known API endpoints so that if I mistype something, TypeScript tells me, right? Or maybe if it catches, it sends something to Sentry, which is an error logging tool, or to my logs.

And if it's successful, it sends something to Segment, which is user tracking or whatever, right? They're always things that you do over and over and over and over again, don't type that and have this request from API in place and just use that. And we have a certain kind of pagination where we don't know the number of pages, you just get the token for the next page, right?

And I only get for some API's 50, so if I need 100, I can say get 100, and we'll requestFromApi, it will keep iterating down to the next page token until I get the note. Very specific business logic for the thing that I work on with the APIs that I have, right?

It will do things, and so I might want that to use fetch or something along those lines of Axios, and that is a case where they might be purposely tightly coupled, right? So you can have something like this, and that's a point where you might choose to do something like this, where you can verify that did fetch get called are the things that should have gotten called.

Cuz if someone breaks that, or yeah, in this case, I do wanna put this response in there real quickly. But you can do some really interesting things but-
>> Where does requestFromApi come from?
>> This is a fake function I just made.
>> Okay.
>> I would say you could call it request, you could even call it fetch if you want it and just import it in the same way.

You only made that render function that kinda uses testing libraries render but different. That's basically I'm saying hey, fetch, but with some of the nuances of my specific use case, please, right? And that might be a case where, then you wanna make sure fetch got called right, right?

And maybe don't wanna do then also send the fetch, now you can start to get my permission, right? But if you find yourself mocking stubbing, I said this earlier in the course, if find yourself mocking and stubbing code you control, fix your code. Do it for now, yeah, fine, but fix it, right?

It's mostly for things you don't fully control to make sure that got called the way that you think it does.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now