Reputation: 2445
In my Cypress Cucumber test, here is my current feature file scenario (this scenario fails on the final step):
Given I log in
Then I am on the dashboard
And the dashboard displays 0 peers (@Peers is called here, & 0 is the correct value here)
When I go to User 1 page
And I click the Add Peer button (@AddPeer request is successful here)
And I go to the dashboard
Then the dashboard displays 1 peers (@Peers is called here. The actual value is 0, but I am expecting 1. It looks like the code is using the response body from the 1st `Peers` intercept)
Here are my step definitions:
Given('I log in', () => {
cy.intercept('GET', `**/user/peers`).as('Peers')
cy.intercept('POST', `**/Peers/add`).as('AddPeer')
});
Then('I am on the dashboard', () => {
cy.url().should('include', `dashboard`)
})
Then('the dashboard displays {int} peers', expectedPeersCount => {
cy.wait('@Peers').then(xhr => {
const peers = xhr.response.body
expect(peers.length).to.eq(expectedPeersCount)
});
});
When('I click the Add Peer button', () => {
dashboard.btnAddPeer().click()
cy.wait('@AddPeer').then(xhr => {
expect(xhr.response.statusCode).to.eq(200)
})
})
When('I go to the dashboard', () => {
cy.visit('/dashboard');
});
In the backend, @AddPeers()
adds a peer to a list, while @Peers()
returns a list of my peers.
When I go to the dashboard, @Peers()
returns the latest list of peers.
But for some reason, the above code is still using the 'old' response that has an empty response body.
Can someone please point out how I can get the 'latest' @Peers
response?
Here is the 1st Peers
response that is empty:
And here is the 2nd Peers
response that contains 1 array item:
Attempted fix:
Given('I log in', () => {
cy.intercept('GET', `**/user/peers`).as('Peers0')
cy.intercept('GET', `**/user/peers`).as('Peers1')
});
Then('the dashboard displays {int} peers', expectedPeersCount => {
cy.wait(`@Peers${expectedPeersCount }`).then(xhr => {
const peers = xhr.response.body
expect(peers.length).to.eq(expectedPeersCount)
});
});
Cypress logs:
Peers1
looks like it's empty below, but it shouldnt' be:
And then it looks below like Peers0
has the populated array. Note the Matched cy.intercepts()
Upvotes: 3
Views: 2232
Reputation: 5451
I can't see why the original code doesn't work, it looks perfectly good (without a running system to play with).
But the "fix" variation is backwards - the last intercept that is set up is the first to match.
This diagram shows route5
being the first (non-middleware) route checked, followed by route3
, then route1
.
Also, since each intercept is intended to catch only one call, add { times: 1 },
to make it so.
Given('I log in', () => {
cy.intercept('GET', `**/user/peers`, {times: 1})
.as('Peers1') // catches 2nd call
cy.intercept('GET', `**/user/peers`, {times: 1})
.as('Peers0') // catches 1st call
})
You can see it in this screenshot
where Peers1
is matched first then Peers0
, but the following block is expecting the reverse order
Then('the dashboard displays {int} peers', expectedPeersCount => {
cy.wait(`@Peers${expectedPeersCount }`).then(xhr => {
const peers = xhr.response.body
expect(peers.length).to.eq(expectedPeersCount)
});
})
Called with 0 by And the dashboard displays 0 peers
and then called with 1 by Then the dashboard displays 1 peers
Dynamic aliases
You might be able to set the alias dynamically depending on how many peers are in the response.
Given('I log in', () => {
cy.intercept('GET', `**/user/peers`, (req) => {
req.continue().then(res => {
if (re.body.length === 0) {
req.alias = 'Peers0'
}
if (re.body.length === 1) {
req.alias = 'Peers1'
}
})
})
})
If this works, then you don't need to worry about the order of setup.
Upvotes: 4
Reputation: 2555
A bit of misunderstanding here. cy.wait()
for an alias intercept will only wait for the first requesting matching the given params.
cy.intercept('request').as('call')
// some actions to trigger request
cy.wait('@call')
// later in the test trigger same request
// this will refer to the first request made
// by the app earlier in the test
cy.wait('@call')
You can either make another intercept with a unique alias and then use .wait()
on the new unique alias.
cy.intercept('request').as('call')
// some actions to trigger request
cy.wait('@call')
// later in the test trigger same request
cy.intercept('request').as('newCall')
// some actions to trigger same request
cy.wait('@newCall')
or you can use your same approach and use cy.get()
to get the list of matching requests, however, this may be a good choice as cy.get()
will not wait for your new request to complete.
cy.intercept('request').as('call')
// some actions to trigger request
cy.wait('@call')
// later in the test trigger same request
// have to ensure the request is completed by this point
// to get the list of all matching and hopefully
// the last request will be the one you seek
cy.get('@call.all')
// get last matching request
.invoke('at', -1)
Upvotes: 1