API Mocking | Bondar Academy
Course: Cypress UI Testing with JavaScript
Module: Working with APIs
Instructor: Artem Bondar
Lesson Summary
In this lesson, we learn how to intercept browser API calls and provide our own responses, a process known as mocking . This is particularly useful for testing applications without relying on live data. Overview of the Test Application The test application loads a list of articles and tags from an API. We can observe the API requests in the Networking tab of the browser's developer tools. Using cy.intercept in Cypress To intercept API calls in Cypress, we use the cy.intercept method. Here are the key steps: Identify the API endpoint you want to intercept. Use cy.intercept with the appropriate arguments: Method type (e.g., GET , POST ) Endpoint URL Custom response object or fixture file Creating Fixture Files For larger responses, it's recommended to save the response in a fixture file . This keeps the code clean and manageable. For example: cy.intercept('GET', '/api/tags', { fixture: 'tags.json' }) Debugging Intercepts In the Cypress runner, you can view the routes tab to see how many times the API was intercepted and whether the mock response was provided. This helps in debugging issues related to API calls. Best Practices Define all mocks before executing the test scenario. Use wildcards in URLs to simplify intercepts. Check the routes section for debugging information. By following these steps, you can effectively mock API responses in your tests, ensuring a more controlled testing environment.
Video Transcript
Hey guys, welcome back. And in this lesson, we will talk about how to intercept browser API calls and provide your own response. And this process of providing own response also called mocking. So this is what we're gonna do. All right, this is our test application. And so far, application loads the list of articles and list of tags. So this is 10 articles loaded on the global feed, and these are the tags. Those tags are coming from the API. So I make right-click in spec, Networking tab, click on Refresh button. And here we go, these are two API requests to the tags endpoint. This is the tags endpoint, and response is the list of the tags. And this is the articles endpoint. Same here, this is the API articles and the response with the list of articles. So how about we intercept both of those API requests and provide our own articles? Let's say two articles and three tags, something like this. So let's do this. I'm going back to the test application, and this is the initial test that we have. So how would you intercept API calls? In Cypress, you have a special method called CyIntercept, like this. And then let's look how to use it. I'm going back to documentation, to the intercept. And there are different patterns that you can use for the arguments that you can provide for the method. So we're gonna use this one for the spine and response stubbing. We will use this example. So you can either provide just a URL that you want to intercept, and then a response that you want to provide. Or you can provide three arguments, which is method, which is post, put, get, or delete, then URL and the response. Or you can provide a router matcher. We're gonna talk about router matcher a little bit later. So in this example, I will use the example number two. I will provide the method type, then provide the URL, and then provide a custom response that I want to use for the API response. So going back, for the CyIntercept, let's start with the tags and point. This is the application, tags and point. And the tags and point is a get endpoint. So I type here first argument as get. Then the second argument will be the URL. I take the API URL, copy it, and paste it as a second argument like this. And the third argument will be a response that I want to use instead of our current list of the tags. I can either provide the object, so it should not be a string, it should be an object like this. I can either provide the object like this, if my request is kind of small, I can paste the response right here and it will be returned as a result. Or I can save my response as a file, as a fixture file, and then provide just the name of this file where I want to get response from. And this is actually a more recommended approach because typically responses are quite big. So if you save this response into the fixture file and then provide the reference to the fixture file, it will be more understandable and compact way. So let me create under the fixture folders, I create a new file and I will call it tags.json. And inside of this file, I will put the response that I want to be returned. So I click on the response tab and I copy the exact structure of the object that is related to this API, going back and paste it over here. So this is the current list of the articles, and let me update this list with the articles that I want to return. So I remove these one, and let's say our tags will be Cypress, then test, and let's say automation, something like this. So three tags, sounds about good. And going back over here, and then in this object, I type fixture like this, put colon, and provide the name of the fixture file, which is a tags.json. Okay, we are a little bit missing the space, I think it's good, and that's it. So we provided the URL that we want to intercept and the object that we want to return. And let's do the same for the articles and point. So articles and point is also a get endpoint, all right, going back. So I type get over here, second argument will be a URL. I need to get exactly the URL that our browser is calling. So I will have exact match for the URL that I want to intercept. So this is the API URL that browser is requesting, like this. And the last argument, again, it will be a fixture. So first, I need to create this fixture file. New file, and it will be the articles.json. And let me grab the response from the browser. Response, Command-A, Command-C, going back, Command-V. And look, this response is a lot bigger. So look, it has 200 lines. So imagine if I would put this response, or at least portion of this response, directly into the source code. It would be like a mess. So that's why using a fixture reference as your file, where you keep your mock responses, would be like a better idea. So instead of returning all ten articles, I want to return, let's say, just two articles. Let me delete the rest of those. So I selecting all of not necessary articles. I think it's right here. Okay, I delete the comma. And let me modify those articles as well. So let me modify the title for the article, first mock article. And let me modify the title for the second article. You can modify all the values, actually. But for this demo, I am modifying just the title. So you will see how it's gonna work. So this is bs-second-mock-article, like this. All right, looks good. And we're doing the same thing. We provide the fixture with the name of the file, article.json, like this. Okay, looks good. Now let's try if it's working. So going back to the Cypress, and I'm trying to run this test. So running the test. All right, so where is the error? An error through the processing network event. The fixture file could not be found in any of the following paths. So I think I mistyped something. So my file is articles, but the fixture is articles. So I need to type articles. All right, so now it should work. Going back, running this. Yeah, now it is working. So and look, we logged into the application. What we see in the runner, we successfully loaded our mock articles. First mock article, second mock article. And we also have three tags that are also loaded from the mock. So interception and mocking of the API worked perfectly. And also look into the runner interface. You have some additional information here for future debugging. So if you scroll up to the test, you have a routes tab. So if you expand it, this route tab showing you all the routes or all intercepts that you are doing during this test. So we have two intercept endpoints created for the tags endpoint and for the articles endpoint. Both of those are get. Also Cypress telling us that it was stopped, both of those. And one means it's how many times the endpoint was intercepted. So let me try to rerun it. Maybe I'll show you a little bit more. And yeah, right now look, it's showing two types is intercepted. So why is that? Remember previously when we run the application, sometimes our application able to make API request before we start signing in. So before this step, so that's why we made the initial call to those endpoints. They were intercepted and the response, mock response was provided. And then after we logged in again, the mock response was provided one more time. Also look at the status, how it was changed. For example, this is a login endpoint. You see the green dot. It means that API request was actually went through and reached the endpoint, reached the server. But these dots are like a black color, just a contour over here. It means that this API call was made, but it was intercepted. And the response, the mock response was provided. So this is also additional information for you to understand, okay, this API call went through and this one was intercepted and was mocked. Also about this information. So you see it says stopped. It means that we provided a mock API response. But if I, let's say, go back and modify our API URL to something invalid. Let's say I put tags one, let's say. We don't have this API URL going back. So now what we see in the browser, the real tags were loaded, right? Because we were waiting for different API URL. And right here you can see that we are waiting for the tags one endpoint and it was not called. You see a dash over here. It means what? We were waiting for tags endpoint. We defined it the route. We defined intercept, but our application didn't make a call for that. It's also useful when you debug in your application. For example, you define a bunch of mocks for your test. And then you run the test and you see the test for some reason did not mock the data that you have provided. Then you open this route section and look, okay, was my API call was actually mocked? And was it called, first of all? You are looking into this numbers and it can give you the idea. Was it working or not? And also look over here. The tags endpoint right now is green because it reached the actual server. And also, let's talk about this stuff. So we provided a mock response, but if I will remove this mock completely, so I will just use sci-intercept with a get and the actual URL. But I just intercepted, but don't do anything with this. So no mock is provided. If I remove this one and go back to the routes over here and look, stopped right now showing as no. It means that what? We define the intercept, but we didn't do anything with this. We just tried to intercept it. It was not stopped. It was not called. It's technically a dummy configuration. And also alias over here, no alias was provided. And we will talk about it a little bit later. So let me revert everything back. I will fix it right here. So is it working? Yeah, it's working again. And one important point, guys, so when you define your mocks, it is very important that you define those before the actual steps are executed. So those intercepts have to be created before the actual calls are made by the browser. If you put this call after we made the login, for example, if I put it right here, it's not gonna work. So where is that? So let's try it one more time. Yeah, it's working in this example, but if I will add some delay, for example, if I add something like site, wait and add some delay. Going back right here, where is the Cypress? Yeah, and look, right now the actual tags were loaded to the application. Why? Because application called real API and only after that we decided to intercept this API call. So as a rule of thumb, when you run your code, when you define your mocks for your application, do all of your mocks. Let me quickly reformat. Do all of your mocks before the actual test scenario. So what you can do is before the test, pull all the intercept that you want to do and then run your scenario. In this case, you will not miss any of those and you will match those. And the final thing, I want to show you the thing called wildcard. So here we provided the entire URL. You see that Conduit API, Bondar Academy API, and we repeat this again and again. So not very nice thing. Instead, you can replace it with a wildcard and just replace it with a double star. So if I put star stars, it means that we are expecting to match any base API URL for this tags endpoint. And whatever base URL will be called, we want to match it, intercept, and provide our own response. And the same thing I can do right here. I provide star star. It means I won't intercept any base URL. Going back, you see it's working as before. And also, you can provide the wildcard as a single star for the query parameters. So these parameters can be changed, depends on your scenario. So for example, if there here will be query limit, I don't know, 9, and you're explicitly waiting for 10, then match will not happen and you will not intercept your API call. For such scenarios, if those query parameters can change in your case, you can replace them with a wildcard as well. So I, including the question mark, I put just star right here and will also work as expected. Going back, we still have two articles and three tags. Everything is working as expected. All right guys, so let's quickly summarize what we did in this lesson. So when you want to intercept any API call in the browser, you need to provide the URL. You can use a wildcard to match the base URL. You need to provide the method name for this API call and save the desired response under the fixture files as a JSON file and provide the third argument for the JSON file. Make sure you define all your marks before the scenario. So all methods site intercept have to be defined before the scenario, then execute your scenario. And for additional debugging information, you can look into the route section where you can find additional information, how many times your mock was called, was it stopped or not, intercepted or not, and so on. All right, that's it guys, and I'll see you in the next lesson.