Testing Web Apps with Cypress

Network Requests & Intercept

Steve Kinney

Steve Kinney

Testing Web Apps with Cypress

Check out a free preview of the full Testing Web Apps with Cypress course

The "Network Requests & Intercept" Lesson is part of the full, Testing Web Apps with Cypress course featured in this preview video. Here's what you'd learn in this lesson:

Steve introduces the intercept method which allows Cypress to catch network requests to a particular API. An interception can either test if a network request occurs or replace the response from the request with mock data.


Transcript from the "Network Requests & Intercept" Lesson

>> Let's look at something else real quick, which is this works because we are seeding the database. And we're making real network calls to the real database and we're just putting the database back together again. Where are all the places that this won't work? Anyone wanna take a guess?

Well, one, things that I don't control, [LAUGH] right? I can reset my database, I can't reset a third party database. I might not even be able to reset another team's database. Right, like when I worked at Twilio, yeah. I didn't have access to the user store I couldn't make users, right, that was not a thing, and so there was a lot of cases where even internally I didn't have the ability to do the things that I wanted to do, right?

Could you, so Cypress has this limitation where it doesn't allow you to spawn new windows or additional tabs. This is like an intentional design, but even if you could, you don't want your test breaking, cuz Google changed their OAuth page, right? Also, you just don't wanna do that.

But also, even if you did pull it off with a super command that, okay, we'll actually like move to that page. And we'll take, the target new all that kind of stuff. The chance that Google changes the name of a button or anything that you don't control is an area where flakiness enters your tests, right?

And so you really want is listen I need depending on what it is like is it a job, a JSON Web token, is it a cookie? Like what did I need in place for this to happen? Because again, if I'm testing like filtering or sorting or some interaction pattern, right, then I don't always want to do all those things cuz yeah, those are all slow even.

We have less code for signing in and signing up, the act is still happening, right? So, yeah, internal API's that we don't own, which is a large set of them in my case. Any kind of OAuth logic from Google auth zero or what have you, that could change.

API's that you just don't control like you're pulling in from the GitHub API, you're not gonna see their data base, their production database, it's not something, you're welcome or invited to do. So you need to figure out what you're gonna do along those lines. Also you might wanna create conditions, right, like what happens if we get a 500 from the server, right.

The one thing I have learned from doing these workshops I create bugs all the time. Have you ever intentionally tried to create a bug? You ever tried to intentionally make an app slow, or have something that shoots out five hundreds, like randomly or on purpose when you want it to?

It's not easy. And so the ability to just say like, Listen, I'm going to hit that API, you're going to tell me that things went poorly, right? It's a lot easier than trying to create Fictitious cuz then you're writing more code to simulate failure, [LAUGH] Right? That you could get wrong than anything else, so it becomes a kinda useful way to do it.

So let's kind of look at just kinda one example here. We've got this side dot intercept, and it's a whole bunch of different API footprints, right. You can just pass it a URL or you can pass a URL and a method or you can give an object that has multiple things in it.

This is a slightly more sophisticated one, but It could just be a string, it could just be get and then a URL. So the first part though is what kind of HTTP requests do we want to intercept? Right, so this would be get to anything from our base URL/users, after that you're welcome to use globs.

So like a star will be just one thing star, star/star will be sub directories and a greedier glob. In that case, you want to use regex, you can use regex. It's just what is the matching logic for the URL that we want to intercept and also what methods do we want to intercept.

And then effectively what do we want to F, sometimes you just wanna make sure the API got called, right? As I'm working on the filter logic for temporal, right, I trust the temporal server is going to filter my workflows with their API contract, right, like, it's rock solid in production use, I trust it, right?

They have their tests, right? So I wanna make sure that with all the fidgeting of slacks and radio buttons that I'm sending the right set of parameters there. So in that case, I wanna intercept, I don't necessarily need to mock out a response or stub in a response.

I just wanna say when they change that input field, I should fire off an Ajax request appropriately. All right, but if you did wanna mock out a response, that's the second argument, which is cool. What if we never talked to the server? And we just gave you back some JSON that you could expect from the server?

Right, and this is great because it now means you want to run this in CI CD, right isolated from everything else. You can totally do that. You might also have a set of integration tests, but like for your general kind of, fast tests you wanna run all the time.

This is great, you might also have the integration test running. And then most of the time, we will give it an alias, right, because we might wanna need to refer to this later. Did this get called, right, at all? Sometimes you wanna be like, hey, they hit the fetch button.

That I want don't this same way that a times out after four seconds of a thing is on the page is if the API never got called that's problematic. The other thing you have the four folders that were created for us is a fixture which is you can put in a JavaScript object.

But if I think about the workflows in 10 portal, it's like, I think Max says 1, 000, and they all it's a big payload. I don't want that my test file. So I have a JSON file, which is literally, I went to the Network tab in Chrome, copied the response, put in a JSON file.

Now I run against those tests which are real ish, right? But I don't have to have a Docker retainer up and running with temporal and all those kinds of things. I just wanna make sure that the things I expect on the page are there, so on and so forth.

Right, cuz we had a bug last week where the height wasn't big enough on the table, which made the Virtual lists library not render anything. Tests would have caught that a lot faster, right, there's a test for now, but yeah. I don't necessarily need the responses to be real to make sure that my virtual list library didn't eat some of the responses.

So there's a bunch of different kinda footprints, you can just give it a URL and then save it, that will be nice for just, what's it called? You can give the method in the URL, I only want put requests that I'm looking for to this URL or delete requests.

A route matcher is effectively a function where it gives you the request and you JavaScript things until you figure out what you want in this case. And refer to the docs or some of the stuff. Second argument can either be a static response as well or another route handler where we're gonna give you the response object.

If you've ever written any matter like express with like request and response objects and the bodies and the prams and stuff along those lines. It's basically you can you can either just given an object or you can play with those and get all JavaScript as well, right? So here's the static responses, we could just say a body.

I can give it a status code, right, as you need these different things, as you're creating different situations. You can say what headers you want, what bar do you want? What status code basically simulate, all of these different cases, as well. So if you make a post to greatest-bands, you can maybe have it 500 if they have Oasis in there, right, or something along those lines.

Again, with the request and the response you can also like reply to it the same way you would do an express basically your own little mock server for the purposes of writing your tests. And I'm not gonna go through all of this but for the different things that you might need you can do all sorts of different stuff to simulate whatever your API works.

Could you theoretically there's also side out requests that allows you to fire them could you theoretically test your API with Cypress. Yes, I'm not sure, I don't, there's a reason why you might want to, I don't think you need to, but you could, right? With a lot of these pieces as well I think it is more interesting to mock and stub and make sure that the right requests are being made or stub in a response.

So spying either on the requests or stubbing in a response so that I can figure out is my app doing the right things cuz that's if the API breaks. Yeah, I'm like, that's not good. I'm also not gonna be the one that fixes it. All right, and I don't need my builds breaking because of that, right?

I need to know for my things doesn't matter. All right, so let's jump into a file. We'll see some of these in action for a little bit. We'll do the parts that are interesting to us. And then there's a second app where you can take a little bit of this for a spin your self.

So in my collection of apps, I have this other one here called Pokemon search, yes.
>> In terms of to a socket communication, would you use a mock server or spin up to cyphers instances somehow?
>> I would do the mock server at that point. Right, the same way that I have my dev server running that I'm hitting, right, like that dev server, if I have sockets I'm likely.

I'm probably not talking, I wanna know that the things show up in the socket at the right time. Right, I might use tasks to kick off different sockets from happening, but in the same way, this is again running at localhost 3000 and serving my application. I technically have a server running that Cypress is going to visit, I would do something very similar for any kind of WebSocket like work as well.

Yeah, you don't have to send out your requests in Cyprus, you could have a fake server that is serving the API requests as well. That is something we did at Sendgrid, worked to great effect, my buddy Alex worked on it. The product was called Neko, the mock server was called Mako.

I'm just really proud of his naming convention there. You can do that as well. You don't have to do any of this if you don't want to if it is easy for you to have a mock API server that you spin up concurrently with your web development server, that is a total option that works.

I just not gonna cover because it's not necessary Cypress is setting up an express server, right. There are libraries where you can like record network responses and like playback the last good ones and stuff along those lines. There's a bunch of ways that you can handle this. We're gonna talk about the Cypress ones.

So few things that this app does, I can type in this box. As I do that, you can see that fires off a network request that shows loading, it updates the query frame like I was talking about with temporals UI. It shows you the results, and if I click on that one it routes me with the query frame intact to send an additional request.

Right, and also shows it here cuz I got carried away. I don't know why I did that, so effectively it's sending requests on every keystroke showing a loading indicator, showing the results has some routing string if I refresh this page or even Changes to char not in actual ciphers or as I'll probably get me in trouble you can see that pre populates the input field.

So it's basically taking a pattern that we have in our real world app and I'm making it slightly different. I work on an open source project now, so I don't have to worry about lawyers if I pull out real code anymore, but it was also, I didn't need to explain what workflow executions were at this exact moment.

Pokemon seemed easier at the time. So it fills all of that in for us.

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