Tutorial 11 – XHR Testing Introduction in Cypress
What you will Learn :
What is XHR Request?
XHR testing with cypress
When to perform XHR testing?
Understand mocking and spying
Understand cy.server() command
Understand cy.route() command for GET request
Understand cy.route() command for POST request
What is XHR Request
XHR stands for XMLHttpRequest and it is a javascript API that is used for communication between the client and the server. Not only XML, this API can also be used to request JSON/HTML data from web server.
XHR is used as part of the AJAX (Asynchronous Javascript and XML) technique. AJAX utilizes XHR to load data asynchronously from the server in the background without disturbing the behavior of the web page. It is used in most of the dynamic websites that you see today.
Most of the ecommerce websites use AJAX technique when searching for products and while showing the results. XHR is constantly being used as we type in the search box to show the auto-suggestions. XHR is also used to load more results when we scroll to the bottom of the search results pages.
XHR testing with cypress
Cypress provides direct access to XHR methods and hence we can make assertions about the properties (example, if the ‘status’ property equals 200). So cypress can be used for clicking a button on a webpage & simultaneously it can make API calls.
If you want to perform API testing using Selenium, you have to integrate it with 3rd party jars (example Rest Assured APIs). However in cypress, there is no need to integrate any 3rd party to perform API testing.
When to perform XHR testing?
When you want to perform basic API testing using request() method
When you want to mock network responses
When you want to listen to network Request/Responses using route() method
Understand mocking and spying
You will understand mocking when we do practical examples later. As of now, just try to understand the concept.
To mock an application means to mock a backend request. To mock a backend, all you have to do is to use the cypress server command cy.server(). Once you do that, you have a mock server ready.
Once you have the mock server ready, you can start defining routes that you want to spy on. In the below snapshot, we are going to spy on the ‘comments’ route when there is a GET request to it (in the above figure, we are spying on the ‘todos’ route)
The .as(‘getComment’) command allows us to label this route as an alias that we can refer again when required. Once we have mocked this route at the backend, we can go ahead and visit the route of my application using cy.visit command
We can now use cypress wait command to wait on ‘getComment’ route
Now we can make assertions (using ‘should’ as seen below) on the DOM or on the body of the request
Below is syping again, its just that this time we are spying using POST request
Understand cy.server() command
The first thing, in order to work with HTTP requests is: we have to setup a server. cy.server() command initializes network related behaviour.
So, whatever commands you call after cy.server() command, cypress will understand them as network related commands.
Look the url https://example.cypress.io/commands/network-requests
Understand cy.route() command for GET request
cy.route() command initiates listening to network Requests/network Responses viz this command initiates listening the GET/POST/PUT requests.
To understand this, launch https://example.cypress.io/commands/network-requests
Press F12 key.
This would open up the Network tab as seen below.
Click XHR as seen below
Click ‘Get Comment’ button that you see in the figure above (on the left hand side).
So basically, internally, the applicaion is firing a GET method and an XHR request would be seen, see below on the right hand side
Click this XHR request that you see on the right hand side in above figure.
See the below figure.
In the ‘Headers’ section, you would see the Request URL (this is the api call that was made when we had clicked the ‘Get Comment’ button).
In the ‘Headers’ section, you would also see the Request Method (GET), Status code (200) etc.
Go the to ‘Response’ tab now, see below
‘Response’ section shows the response that we get from the server, as seen above.
Notice that the comment can be seen in the “body”
This is same comment that we get when we click ‘Get Comment’button, see below
Now let us try to understand the highlighted section in the figure below
The cy.route() command will keep continously listening if any GET method is fired and as soon as the ‘Get Comment’ is clicked, the response gets saved in the ‘getComment’ variable
Note that the css selctor for ‘Get Comment’ button is .network-btn
The request url in the cy.route command is ‘comments/*’
The star in the request url comments/* represents any comment that is present in database. You don’t have to mention the complete url here (since cypress understands this example)
Let us now understand cy.wait
In the cy.wait statement, we are simply reading the data from ‘getComment’ variable and checking if the status equals 200. If the status equals 200. it means that we have got the most latest comment from the server.
Let us clear the requests by clicking clear
Understand cy.route() command for POST request
See below
Let us now click ‘Post Comment’ to post a new comment in the database.
Now see this POST request in XHR (see above). The status code as 201.
The status code ‘201 Created’ means that the request has been fulfilled and resulted in a new resource being created in the database.
Also notice that we see the text ‘POST successful’ below the ‘Post Comment’ button
On the similar lines we can explain that cy.route() is now listening to any POST request being made. The response is saved to ‘postComment’ variable
Note 1: The css selector for ‘Post Comment’ button is .network-post
Note 2: The POST request url is /comments without any star since we are posting the comments.
Let us now understand the second half of the section
In the above section, we are reading the data in @postComment response and are validating various properties like whether requestBody includes ‘email’
….whether requestHeaders has property content-type and so on…
Thank you for reading!