Learn how to verify that a search result came from the cache instead of an HTTP request with Cypress.io
Here we go with another "Pinch of Cypress." I hope you enjoy it!
In the advanced course of testing automation with Cypress from the Talking About Testing School, I challenge my students to put the knowledge they got into practice with an application similar to that of the course. This is a searching application that integrates with the Hackernews API. In this application's version (the one for the challenge), when a search has already happened, the results are stored in a cache, avoiding a new request to the API when a search for the same term occurs again.
How do we test that?
🤔
I'll explain with an example.
describe('Hacker News Search', () => {
const term = 'cypress.io'
beforeEach(() => {
cy.intercept(
'**/search?query=redux&page=0&hitsPerPage=100',
{ fixture: 'empty'}
).as('empty')
cy.intercept(
`**/search?query=${term}&page=0&hitsPerPage=100`,
{ fixture: 'stories'}
).as('stories')
cy.visit('/')
cy.wait('@empty')
})
it('correctly caches the results', () => {
const faker = require('@faker-js/faker')
const randomWord =faker.random.word()
let count = 0
cy.intercept(`**/search?query=${randomWord}**`, req => {
count +=1
req.reply({fixture: 'empty'})
}).as('random')
cy.search(randomWord).then(() => {
expect(count, `network calls to fetch ${randomWord}`).to.equal(1)
cy.wait('@random')
cy.search(term)
cy.wait('@stories')
cy.search(randomWord).then(() => {
expect(count, `network calls to fetch ${randomWord}`).to.equal(1)
})
})
})
})
In the code above, what happens is the following:
- We have a test suite for the search functionality for the Hacker Stories application
- We defined a variable called
term
for code reuse reasons - So we have a function that runs before each test (
beforeEach
)- In the
beforeEach
function, we defined two routes (which use fixtures) so that we don't depend on the Hackernews API. In the first route, which occurs as soon as the application is rendered, the fixtures will return an empty list of stories, and in the second, they will return two stories - We then visit the home page of the application
- And finally, we wait for the initial request to end (the one that returns the empty list of stories)
- In the
- Hence, we have the test itself to ensure that the cache works
- The test uses the
faker
library to generate random words for the search that the app will store in the cache - Right at the beginning, we define a variable called
count
, which is initialized to zero (0
). This variable's value will increase each time a request occurs for the same search term. - Then we have the definition of another
cy.intercept
, which intercepts a search request by the random word, performs a function that increments the counter, and finally, responds to that request with the fixture that returns an empty list of stories. Here's the secret, when a request for such a term occurs, the counter will be incremented - There's a search for a random word, and we soon assert that the counter has been incremented correctly. Now, instead of
0
, it's1
. - A search for another term is done with their respective waiting. In this case, as it's another term, the counter is not incremented. This other term falls into another
cy.intercept
(created inbeforeEach
). - Finally, a new search happens for the random word previously searched, with the verification that the counter has not increased, that is, it continues with a value of
1
, demonstrating that a new request did not occur for such a route, proving that the cache works. Note: if the cache weren't working, a new request would occur, which would increase the counter to2
, and the final test assertion would fail.
- The test uses the
This is an alternative to test how well a search cache works when talking about automated tests with Cypress. I hope you find it useful.
Reference: https://glebbahmutov.com/blog/cypress-intercept-problems/
See the implementation details of the search
custom command:
// cypress/support/commands.js
Cypress.Commands.add('search', term => {
cy.get('input[type="text"]')
.should('be.visible')
.clear()
.type(`${term}{enter}`)
})
And of the fixtures:
// cypress/fixtures/empty.json
{
"hits": []
}
// cypress/fixtures/stories.json
{
"hits": [
{
"title": "Sample 1",
"url": "https://example.com/1",
"author": "Author 1",
"num_comments": 34,
"points": 91,
"objectID": 0
},
{
"title": "Sample 2",
"url": "https://example.com/2",
"author": "Author 2",
"num_comments": 55,
"points": 98,
"objectID": 1
}
]
}
That's it!
So, did you like this “Pinch of Cypress“?
Leave a comment.
Are you curious and want to learn more about testing automation with Cypress? I was hoping you could get to know my Cypress courses on Udemy.
This post was originally published in Portuguese on the Talking About Testing blog.
👋 Until next time and happy testing!
Top comments (2)
Thoroughly enjoyed this read! For those looking to delve deeper, I came across this intriguing implementation of cache methods with Cypress. Thought it might be beneficial for the community here!
Thanks for sharing.