- how to spy on / stub network calls
- how to wait for the network calls from tests
- how to use network calls in assertions
+++
- keep
todomvc
app running - open
cypress/integration/05-xhr/spec.js
cy.route
is deprecated, usecy.intercept
📖 Fun read: https://glebbahmutov.com/blog/cypress-intercept-problems/
- there is no resetting the state before each test
- the test passes but something is wrong
it('starts with zero items', () => {
cy.visit('/')
cy.get('li.todo').should('have.length', 0)
})
+++
- page loads
- web application makes XHR call "GET /todos"
- meanwhile it shows an empty list of todos
- Cypress assertion passes!
- "GET /todos" returns with 2 items
- they are added to the DOM
- but the test has already finished
// 05-xhr/spec.js
it('starts with zero items (waits)', () => {
cy.visit('/')
cy.wait(1000)
cy.get('li.todo').should('have.length', 0)
})
+++
// todomvc/app.js
axios.get('/todos')
...
.finally(() => {
// an easy way for the application to signal
// that it is done loading
document.body.classList.add('loaded')
})
TODO: write a test that waits for the body to have class "loaded" after the visit
⌨️ test "starts with zero items (check body.loaded)"
+++
better to wait on a specific XHR request. Network is just observable public effect, just like DOM.
+++
Use the test "starts with zero items" in the file 05-xhr/spec.js
- spy on specific route with "cy.intercept"
- should we set the spy before or after
cy.visit
?
- should we set the spy before or after
- save as an alias
- wait for this XHR alias
- then check the DOM
tips: cy.intercept
, Network requests guide
+++
💡 No need to cy.wait(...).then(...)
. All Cypress commands will be chained automatically.
cy.intercept('GET', '/todos').as('todos')
cy.visit('/')
cy.wait('@todos')
// cy.get() will run AFTER cy.wait() finishes
cy.get('li.todo').should('have.length', 0)
Read Introduction to Cypress "Commands Run Serially"
add to the test "starts with zero items":
- wait for the XHR alias like before
- its response body should be an empty array
Update test "starts with zero items (stubbed response)"
- instead of just spying on XHR call, let's return some mock data
// returns an empty list
// when `GET /todos` is requested
cy.intercept('GET', '/todos', [])
+++
it('starts with zero items (fixture)', () => {
// stub `GET /todos` with fixture "empty-list"
// visit the page
cy.visit('/')
// then check the DOM
cy.get('li.todo').should('have.length', 0)
})
tip: use cy.fixture
command
+++
it('loads several items from a fixture', () => {
// stub route `GET /todos` with data from a fixture file "two-items.json"
// THEN visit the page
cy.visit('/')
// then check the DOM: some items should be marked completed
// we can do this in a variety of ways
})
When you add an item through the DOM, the app makes POST
XHR call.
Note: It is important to be able to use DevTools network tab to inspect the XHR and its request and response.
+++
Todo 1/3
- write a test "posts new item to the server" that confirms that new item is posted to the server
Note:
see instructions in the 05-xhr/spec.js
for the test
+++
Todo 2/3
- write a test "posts new item to the server response" that confirms that RESPONSE when a new item is posted to the server
Note:
see instructions in the 05-xhr/spec.js
for the test
+++
Todo 3/3
- after you waited for the intercept once, you can use
cy.get('@alias')
to get its as many times as needed. Verify the request body and the response body of the intercept. Implement the test "'confirms the request and the response"
Note:
see instructions in the 05-xhr/spec.js
for the test
Network requests guide at https://on.cypress.io/network-requests, blog post https://glebbahmutov.com/blog/network-requests-with-cypress/
Question: which requests do you spy on, which do you stub?
⌨️ test "shows the items loaded from the server"
In the application we are showing (very quickly) "Loading" state
<div class="loading" v-show="loading">Loading data ...</div>
+++
- delay the loading XHR request
- assert the UI is showing "Loading" element
- assert the "Loading" element goes away after XHR completes
⌨️ test "shows loading element"
Note: most querying commands have the built-in should('exist')
assertion, thus in this case we need to use should('be.visible')
and should('not.be.visible')
assertions.
// can you fix this test?
const id = cy.wait('@postTodo').then((intercept) => {
// assert the response fields
return intercept.response.body.id
})
console.log(id)
⌨️ test "refactor example"
User cannot enter blank titles. What if our database has old data records with blank titles which it returns on load? Does the application show them? Does it crash?
Todo: write the test handles todos with blank title
The application loads Todos every minute
// how would you test the periodic loading of todos?
setInterval(() => {
this.$store.dispatch('loadTodos')
}, 60000)
+++
- learn about controlling the web page clock using cy.clock command
- set up a test "loads todos every minute" that intercepts the
GET /todos
with different responses usingtimes: 1
option - advance the clock by 1 minute and confirm different responses are displayed
⌨️ test "test periodic loading"
You can spy on every network request and keep track of its timestamp. Waiting for network idle means waiting for the network request to be older than N milliseconds before continuing the test.
Todo: implement the test "waits for the network to be idle for 2 seconds". Bonus for logging the timings.
- confirm the REST calls
- stub random data
➡️ Pick the next section