Waiting for Browser API Calls | Bondar Academy
Course: Cypress UI Testing with JavaScript
Module: Working with APIs
Instructor: Artem Bondar
Lesson Summary
In this lesson, we explore how to dynamically wait for browser API responses and its significance in ensuring test stability. The focus is on automating a scenario where the text "Ponder Academy" must be located on a webpage. Key Concepts Flakiness in Tests: Initial tests may fail due to timing issues, especially when elements are not yet loaded. Assertions: Using should assertions allows Cypress to retry until the expected condition is met. Steps to Implement Dynamic Waiting Identify the locator for the articles, e.g., AppArticlesList . Log into the application and set up the test. Use cy.intercept to declare an interception for the API call without mocking the response. Assign an alias to the intercepted request, e.g., articleAPIcall . Before invoking the text extraction, use cy.wait with the alias to ensure the API response is received. Benefits of Dynamic Waiting This technique allows tests to be more stable by ensuring that data is fully loaded before assertions are made. It also enables access to the API request and response details, which can be used for further validations. Example Validation After waiting for the API response, you can validate specific properties from the response object: expect(apiArticleObject.response.body.articles[0].title).to.contain('Ponder Academy'); In summary, dynamically waiting for API responses is essential for creating reliable tests in applications with asynchronous data loading. This method enhances test accuracy and stability.
Video Transcript
All right, guys, in this lesson, I will show you how you can dynamically wait for the browser API response and why this feature can be very useful. Let's jump into it. So imagine in our application, we want to automate the scenario that the TextBonderAcademy have to be located somewhere on this page. It doesn't matter what article, is it number 1, number 2, and so on, it should be somewhere on this page. So let's automate this scenario, then I introduce the flakiness, and then I will show you how you can overcome this flakiness using the waiting for the APIs. So right-click Inspect, and let's find what locator we can use. So we want to look into all articles. Let me make it slightly smaller. So this is the all individual articles, and the tag that is responsible for all articles is this one, AppArticlesList. So let me take this guy, and we'll make sure that it has the text that we are looking for, and I will create a new test. It's .onlyWaitingForAPIs, and I will need to log into the application as a first step, and the second step, sciGet, and let me copy this guy one more time. So this is the AppArticlesList, and then I want to make the assertion that it should contain text, and the text that I'm expecting is Ponder Academy. It seems correct. Let me remove it only over here, and I will run this test. Here's the Cypress running this test. Running the test, and test passed successfully. So if I run it one more time, it passed successfully, so test working correctly. It is working correctly, and it will be stable because of how should assertion behave. So remember, when we're talking about the assertion, I was mentioning that should will retry the assertion until it satisfies the result. So until this web element contain the text Ponder Academy, Cypress will patiently wait for this text. So that's scenario number 1. But let me modify this test, just different scripting style to make it intentionally failing, like to make it intentionally flaky, and let's see what's gonna happen. So I would use the same locator, sci.get to get the list of the articles. But instead of running the assertion right away, I want to invoke all text from this element. So I'll get invoke-text. Then I take all those articles, all-article-texts, or all-article-texts. And then I want to run expect all-article-texts like this, and then to contain, and then I expect to have this text. And I remove this assertion. So technically, it should work, right? But let's run it and see what's gonna happen. So running this test, and the test failed. And look, an assertion error. Expected loading articles to include Bonder Academy. But we clearly see that, hey, we have all the articles over here. So let me run this one more time, and nope, the test fails. Why does that happen? Because over here, look, when the articles are not displayed yet on the page, the actual message on the page that is displayed is loading articles, is this one. And since this is a text that is already available, Cypher is just getting this text. It's saving this text over here, and then it's trying to validate that the text loading article contains Bonder Academy. So it's not retrying for new text available, because it's already got the text from this locator. And that's why it has failed. So how can we overcome this? We know that the value for the articles is coming from the API. So if we can dynamically wait for the API to make sure that the API call is completed that responsible for loading this data, that way we can make this scenario stable again. How to wait for the API? So go in back over here, and first of all, we need to define the intercept. So I take my intercept that we used before for the article and put it over here. But instead of the mocking the response, we don't need to mock it. We need just to declare the interception, the intention that we want to intercept this request. And we want to save it as alias as our variable. For example, we call it article API call. Something like this. And then before over here, after we log into application, before we actually invoking the text, we can call CyWait and then call the alias CyWait at and then name of this alias like this. So CyWait now will look into the object related to this article's intercept and wait for the response until continuing to the next step of actually getting all the texts from the page. So let's run this test and let's see what's gonna happen. So running the test and test pass successfully right now. So if I rerun it again, it again will pass and it will be stable. So if I scroll a little bit up, look where it has happened. So this is CyWait, click, and this is found one alias. And now we are waiting for this alias to be loaded. So if I click over here, so this is request loading the articles and after we waited and received the response, here we go, this is our response. If we scroll a little bit down, also in the route section, we see that alias is defined for this interception, just for our debugging purposes. And this is how you can dynamically wait. This is super, super useful technique in case you have very dynamic data, asynchronous data coming from your API and it's hard to manage from the UI perspective. You can wait and identify which API responsible for the particular data and wait for that particular API to make sure that data is loaded and your application is in the correct state before moving on with your scenario. But that's not it. So this alias actually, so this object is not what you know, just can wait for it. You can also extract all the data related to this API request and API response and to use with this data whatever you need for your scenario. For that, you just call then and then, for example, let's call it API article object. I don't know, we can give it any name. So and then if I print it to console.log, let me just show you what is it inside. So console.log, I run the test one more time. Test passed and let me open the console. So that's the console, making it bigger. So look, this is the object that is available inside of this alias. It has all information about this API call. It has a request information. Look, this is a request object with headers, with query parameters. If this would be a post request, you would have information about the request body. And also response details. So this is a response object. It has a body, it has a headers, it has everything you need. And you can access all of those properties individually for whatever case you may need in your test scenario. Let's make, I don't know, some validation of this response object. I just want to show you how you can use it. So let's say we want to make a response body validation that the first article. Why is it not showing? Okay, hold on, I need to rerun it, I guess. Working with API, okay, and body, okay, let me run it one more time. Inspect, console, object, response, here we go. Now we have response, body, and articles. Okay, now all information is available. So now let's access this object and make a validation that the first title contains Bonder Academy. So here's how you do it. I type here, for example, expect, then I get my API article object dot. Now we are looking through the dot notations. We are looking for a response dot, we are looking for body dot. And now we need to provide the exact property inside of this body. So we're looking for articles. It will be, I think you know, articles like this. We're looking for the first article, and we are looking inside of this article for the title property. Where is that? Title property, okay, dot title, title. And this title should contain Bonder Academy, Bonder Academy. All right, so let me close this and run this test one more time. And test pass successfully. So scrolling a little bit down, here is our validation. So look, we intercepted this API call. We waited for the response to come back. And then we accessed the alias and from the alias extracted the information about the API response and validated this property directly. And then we continued our scenario validating pretty much the same thing on the UI perspective. So that's the main idea, guys. And let's quickly summarize what we did in this lesson. So waiting for the API is a very powerful technique to make your test more stable. You need to declare your interception before your scenario and provide the alias name for your API. Then somewhere inside of your test where you want to wait for this API call to be completed, you call CyWait and provide the reference to the alias. Additionally, through the then method, you can get access to all information related to this API call to request information or response information. And use any properties from this object for your test scenario. All right, that's it, guys, and I'll see you in the next lesson.