I started learning cypress today and trying to write the test below
it('Validate Price High - Low sorting', () => {
let unsortedItemPrices = [];
const sortedItemPrices = [];
unsortedItemPrices.sort((a, b) => parseFloat(a) - parseFloat(b)).reverse();
cy.get(inventoryPage.itemsPrice).each((item) => {
unsortedItemPrices.push(item.text().replace('$', ''));
});
cy.get(inventoryPage.sortDropdown).get('option').should('have.length', 4);
cy.get(inventoryPage.sortDropdown).select('hilo');
cy.get(inventoryPage.itemsPrice).each(($item) => {
sortedItemPrices.push($item.text().replace('$', ''));
});
cy.task('log', unsortedItemPrices.sort((a, b) => parseFloat(a) - parseFloat(b)).reverse());
cy.task('log', sortedItemPrices);
expect(sortedItemPrices).to.deep.equal(unsortedItemPrices.sort().reverse());
});
The 2 log statements returns these lines, which is weird as when I try separately I see the data sorted properly. However the expect().to.deep.equal() statement above doesn't return an error.
[ '29.99', '9.99', '15.99', '49.99', '7.99', '15.99' ]
[ '49.99', '29.99', '15.99', '15.99', '9.99', '7.99' ]
What is more weird that if I edit the log with like this
cy.task('log', unsortedItemPrices.sort((a, b) => parseFloat(a) - parseFloat(b)).reverse().push(1));
then I do get an error, but it says
AssertionError: expected [] to deeply equal [ 1 ]
+ expected - actual
-[]
+[ 1 ]
Can someone please explain what is going on? This is totally confusing for me :|
In your test, you have some cy.get()
commands to get the values off the page, but you go ahead and run the expect().to.deep.eq()
before these command have completed.
That's because cy.get()
commands are asynchronous, and need to be waited on before using the values extracted from the page.
So your expect is comparing the empty arrays, equivalent to
expect([]).to.deep.equal([])
which explains this message after you push(1)
AssertionError: expected
[]
to deeply equal[ 1 ]
How to fix
Just wrap your comparison in a cy.then()
to ensure it is performed after the values are extracted.
Also note .sort()
and .reverse()
are in-place methods that affect the original array, so you don't want to call then twice (which you have correctly avoided doing, but it's easy to overlook that issue).
const sortFn = (a, b) => parseFloat(a) - parseFloat(b)
let unsortedItemPrices = [];
const sortedItemPrices = [];
cy.get(inventoryPage.itemsPrice).each($item => {
unsortedItemPrices.push($item.text().replace('$', ''))
})
cy.get(inventoryPage.sortDropdown).get('option').should('have.length', 4);
cy.get(inventoryPage.sortDropdown).select('hilo');
cy.get(inventoryPage.itemsPrice).each($item => {
sortedItemPrices.push($item.text().replace('$', ''))
})
cy.then(() => {
// sort() and reverse() work in-place, so we can apply first
unsortedItemPrices.sort(sortFn).reverse()
// then compare
expect(sortedItemPrices).to.deep.equal(unsortedItemPrices)
})
A clearer test
IMO a cleaner way to structure the test is to map elements to values instead of using .each()
const sortFn = (a, b) => parseFloat(a) - parseFloat(b)
const mapFn = ($items) => [...$items].map(item => item.innerText.replace('$', '')
cy.get(inventoryPage.itemsPrice)
.then(mapFn)
.then(unsortedItemPrices => {
// create a new array for expected values
const expectedSortedItemPrices = [...unsortedItemPrices.sort(sortFn).reverse()]
cy.get(inventoryPage.sortDropdown).get('option')
.should('have.length', 4);
cy.get(inventoryPage.sortDropdown).select('hilo');
cy.get(inventoryPage.itemsPrice)
.then(mapFn)
.should(sortedItemPrices => {
// using should() instead of then() gives some retry
// in case the page sorting happens asynchronously
// (not likely but you don't know the internal implementation)
expect(sortedItemPrices).to.deep.equal(expectedSortedItemPrices)
})
})