Reputation: 722
With my team we are trying to implement a command for a really common operation for the business logic but I'm having issues handling its implementation. Basically:
We have to retrieve an array of objects (GET).
For each of that objects we have to retrieve (GET) another object inside its parent.
For each of that sub-objects (childs) we have to check a condition and if it is the wanted condition we retrieve the child, otherwise we pass null.
Q: How do I handle multiple API calls that depends from a single API call without getting outside the CY chain?
This is my current implementation (doesn't works but kinda explains the wanted logic)
Cypress.Commands.add('myCommand', (sumCriteria: Function, anotherCriteria: Function) => {
// I only retrieve parents with certain criteria
return cy.request('GET', parentsUrl).its('body').then(parentObjects => {
return parentObjects.filter(parent => parent.childs.length && parent.childs.find(sumCriteria))
}).then(filteredParents => {
filteredParents.forEach(parent => {
// For each parent I retrieve a single child
const targetChildId = parent.childs.find(sumCriteria).id;
// For each single child I retrieve its data and evaluate if it has the needed criteria
cy.request('GET', `${childsUrl}/${targetChildId}`)
.its('body')
.then(property => anotherCriteria(property))
})
});
})
Thanks in advance!
Upvotes: 2
Views: 2707
Reputation: 31944
You almost have the correct pattern, but instead of returning results, put them on the queue.
Cypress does two things to make this work
Cypress.Commands.add('myCommand', (sumCriteria, anotherCriteria) => {
cy.request('GET', fathersUrl)
.its('body')
.then(fatherObjects => {
const filteredFathers = fatherObjects.filter(father => {
return father.childs.find(sumCriteria)
});
const results = []
filteredFathers.forEach(father => {
cy.request('GET', father) // waits for all these to resove
.its('body')
.then(property => anotherCriteria(property))
})
cy.then(() => results) // returns this last queued command
})
})
A reproducible example:
Cypress.Commands.add('myCommand', (sumCriteria, anotherCriteria) => {
const fathersUrl = 'https://jsonplaceholder.typicode.com/todos/1'
cy.request('GET', fathersUrl)
.then(() => {
// simulated url extraction
const filteredFathers = [
'https://jsonplaceholder.typicode.com/todos/2',
'https://jsonplaceholder.typicode.com/todos/3'
]
const results = []
filteredFathers.forEach(father => {
cy.request('GET', father)
.then(res => {
results.push(res.body.id)
})
});
cy.then(() => results)
});
})
cy.myCommand()
.should('deep.eq', [2,3]) // ✅ passes
Upvotes: 3