I want to store a value, then perform an action and assert that the value has not changed. I do have a code that works but I would like to have input if there is a more elegant solution.
The basic idea is:
- Get the number or results displayed ('counts'), store it in a .then() function
- Change the use
- Get the number of results displayed ('new_counts'), store it in a new .then function
- Compare counts and new_counts in the 2nd .then() function
describe('Store and compare a value', () => {
it('store and compare', () => {
cy.login()
cy.visit('url2')
cy.get('.total-count-results').invoke('text')
.then((text) => {
const counts = text
cy.get('.medium.col100 > .filterwrapper > input').type('Test Dummy',{force: true})
cy.get('.medium.col100 > .filterwrapper > input').type('{enter}')
cy.get('.total-count-results').invoke('text')
.then((text) => {
const new_counts = text
expect(new_counts).to.eq(counts)
})
})
})
})
That is the best I could come up with to handle asynchronicity.
I want to store a value, then perform an action and assert that the value has not changed. I do have a code that works but I would like to have input if there is a more elegant solution.
The basic idea is:
- Get the number or results displayed ('counts'), store it in a .then() function
- Change the use
- Get the number of results displayed ('new_counts'), store it in a new .then function
- Compare counts and new_counts in the 2nd .then() function
describe('Store and compare a value', () => {
it('store and compare', () => {
cy.login()
cy.visit('url2')
cy.get('.total-count-results').invoke('text')
.then((text) => {
const counts = text
cy.get('.medium.col100 > .filterwrapper > input').type('Test Dummy',{force: true})
cy.get('.medium.col100 > .filterwrapper > input').type('{enter}')
cy.get('.total-count-results').invoke('text')
.then((text) => {
const new_counts = text
expect(new_counts).to.eq(counts)
})
})
})
})
That is the best I could come up with to handle asynchronicity.
Share Improve this question edited Sep 28, 2021 at 9:41 jonrsharpe 122k30 gold badges266 silver badges473 bronze badges asked Sep 28, 2021 at 9:33 cypher_nullcypher_null 6721 gold badge14 silver badges24 bronze badges 2- 1 You could simplify by actually naming the arrow function parameters what you want the variables to be called, and asserting directly rather than nesting another then, but otherwise this is what docs.cypress.io/guides/core-concepts/variables-and-aliases suggests. – jonrsharpe Commented Sep 28, 2021 at 9:42
- Thanks. I will take a look at that part of the documentation again. Also, thanks for editing my post to match SO standards better! – cypher_null Commented Sep 28, 2021 at 10:52
3 Answers
Reset to default 8I don't think aliases are required. Here is my solution that I tested locally. I kept most of the code in Alapan Das' answer so it's easier to compare. To me, it seems more concise and easier to read without aliases.
describe('Store and compare a value', () => {
it('store and compare', () => {
cy.login()
cy.visit('url2')
cy.get('.total-count-results').invoke('text')
.then((previousText) => {
cy.get('.medium.col100 > .filterwrapper > input').type('Test Dummy',{force: true})
cy.get('.medium.col100 > .filterwrapper > input').type('{enter}')
cy.get('.total-count-results').invoke('text').should("eq", previousText)
})
})
})
You can use aliases for this and do something like this:
describe('Store and compare a value', () => {
it('store and compare', () => {
cy.login()
cy.visit('url2')
cy.get('.total-count-results').invoke('text').as('counts')
cy.get('.medium.col100 > .filterwrapper > input').type('Test Dummy', {
force: true,
})
cy.get('.medium.col100 > .filterwrapper > input').type('{enter}')
cy.get('.total-count-results').invoke('text').as('new_counts')
cy.get('@counts').then((counts) => {
cy.get('@new_counts').then((new_counts) => {
expect(new_counts).to.eq(counts)
})
})
})
})
A good solution for comparing values like this can be to use a closure variable, as per the example in Cypress' documentation at https://docs.cypress.io/api/commands/should#Compare-text-values-of-two-elements. In your example, something like this:
describe('Store and compare a value', () => {
it('store and compare', () => {
let counts // closure variable
cy.login()
cy.visit('url2')
cy.get('.total-count-results').invoke('text')
.then(text => counts = text) // set closure variable
cy.get('.medium.col100 > .filterwrapper > input').type('Test Dummy',{force: true})
cy.get('.medium.col100 > .filterwrapper > input').type('{enter}')
cy.get('.total-count-results').invoke('text')
.then(new_counts => expect(new_counts).to.eq(counts)) // compare closure variable
//.should("eq",counts) // won't work: counts still undefined when run
})
})
This is reasonably concise, and avoids having nested '.then' clauses, which can become like callback hell as complexity grows.
(See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures for background on closures: in short, "a closure gives you access to an outer function's scope from an inner function". The inner functions here are the two .then
functions: they access the counts
variable from the outer it
function's scope.)