Reputation: 21
Currently, I use cy.route to observe API-calls as so:
cy.server();
cy.route({
method: 'POST',
url: '/api/some-route',
}).as('some-api-call');
Let's presume the response body for said API-call is something like this:
{
someProperty: 'some-value'
}
Now, somewhere else in my tests, in order to do something with this "some-value", I will have to write recurring boiler-plate such as:
cy.get('@some-api-call')
.then(
// Note: this complication is not the topic of this question. Please disregard.
xhr => JSON.parse(new Response(xhr.responseBody).text()).someProperty
)
.then(doSomethingWithSomeProperty);
Instead, I would like access the latest "someProperty" using a dedicated alias, say "@some-alias-name", to produce something simpler such as:
cy.get('@some-alias-name').then(doSomethingWithSomeProperty)
I have tried to make this happen with something like:
cy.route({
method: 'POST',
url: '/api/some-route',
}).then(
// Again, please disregard.
xhr => JSON.parse(new Response(xhr.responseBody).text()).someProperty
).as('some-alias-name');
...but it does not work, as ".then()" for ".route()" does not support such behaviour.
I have also tried:
cy.route({
method: 'POST',
url: '/api/some-route',
onResponse:
xhr => {
// Keep disregarding.
const someProperty = JSON.parse(new Response(xhr.responseBody).text()).someProperty;
cy.wrap(someProperty).as('some-alias-name');
}
});
...but it does not work, as Cypress will not tolerate commands, such as ".wrap()", inside async callbacks, such as onResponse.
However, I have tried to cheat that using:
cy.route({
method: 'POST',
url: '/api/some-route',
onResponse:
xhr => {
// Yup.
const someProperty = JSON.parse(new Response(xhr.responseBody).text()).someProperty;
// This is the previously mentioned cheat.
Cypress.once('command:end', {
cy.wrap(someProperty).as('some-alias-name');
});
}
});
...but it does not work, as the alias gets somehow registered outside of normal Cypress-flow, so that the alias cannot be found or accessed from anywhere.
I have tried solutions which attempt to declare an alias from another alias, but that does not work, as it prematurely starts waiting for the original alias which will have no chance to resolve, as the actual API-calls will only happen later in test.
I have made a custom Cypress-command to reduce the boiler-plate for finding a specific value in an API-call, but that hurts design by dictating that the "specific value" needs to originate from an API-call. This is not always the case, and for clean abstractions, I would much prefer not to be required to know where a required value originates.
More specifically, this hurts the reusability and simplicity of my step-definitions when using cypress-cucumber-preprocessor. But this is irrelevant to the core-problem.
Thanks?
Upvotes: 0
Views: 1345
Reputation: 1425
You shoud use Cypress Request command instead of route and add it as a custom command:
Cypress.Commands.add('aliasRequestedValue', (allias) => {
cy.request({
method: 'POST',
url: '/api/some-route',
})
.then(xhr => {
cy.wrap(JSON.parse(new Response(xhr.responseBody).text()).someProperty)
.as(allias)
})
})
And in the test code you can use it to get the response with the required allias
cy.aliasRequestedValue('some-alias-name')
cy.get('@some-alias-name')
.then(propertyValue => {
//code that uses the value
})
Upvotes: 1