Reputation: 23
I'm new to cypress framework and trying to achieve the below functionality using cypress.
I have a page with table rows and a dropdown menu on page header. On selecting the option, the dropdown menu gets closed and the body content gets changed/loaded up according to the selected menu options.
Problem: Getting the same length for the table rows for all the menu options selected sequentially, although the table rows count is different for the options.
Here is my code:
it.only('Validate table Row changed length on menu option selection', {defaultCommandTimeout: 10000}, () => {
// opening the dropdown menu
page.openDropdownMenu();
// getting the dropdown options and calculating the length
cy.get('dropdownOptions').then($options => {
// calculating the length
const menuOptionCount = $options.length;
// closing the dropdown menu
page.closeDropdownMenu();
for (let i = 0; i < menuOptionCount; i++) {
// opening the dropdown menu
page.openDropdownMenu();
// clicking the menu option
$options[i].click();
// closing the dropdown menu
page.closeDropdownMenu();
cy.get("body").then($body => {
// always getting the same length for the table rows for all selected options
const rowsLength = $body.find('.table.rows').length;
cy.log('****************Rows length************', rowsLength);
});
}
});
});
Is there any way to write the asynchronous statement to synchronous like (await async in promises) without using any external utility in cypress. As in my previous assignment using Protractor the same thing could be handled using async await as below.
const elementCount = await element(
by.css('[title="Locked By"] .med-filter-header-button div')
).count();
Upvotes: 2
Views: 468
Reputation: 31882
After click()
the app rewrites the table, but Cypress does not know that happens and gets the row count before the change occurs.
TLDR - You need to give Cypress more information test correctly. Generally, your test data should be known (not "discovered" by the test code).
Problem #1
You need some way to wait for the row change to finish. Either some text element changes (maybe the first row text), or by adding a .should()
on the actual row count.
Something like
const expectedRowCount = [5, 4, 3, 2]
cy.get('dropdownOptions').each(($option, index) => {
page.openDropdownMenu()
$option.click()
page.closeDropdownMenu()
cy.get('.table.rows')
.should('have.length', expectedRowCount[index]) // this will retry until rowsLength changes
.then(rowsLength => {
cy.log('****************Rows length************', rowsLength)
})
})
Problem #2
If "the body content gets changed/loaded" means that the dropdown also gets rewritten with every click, then the loop will fail because $options
gets refreshed each time.
You might use the expectedRowCount
to loop instead
const expectedRowCount = [5, 4, 3, 2]
expectedRowCount.forEach((expectedCount, index) => {
page.openDropdownMenu()
cy.get('dropdownOptions').eq(index).click()
page.closeDropdownMenu()
cy.get('.table.rows')
.should('have.length', expectedCount) // retries until rowsLength changes
.then(rowsLength => {
cy.log('****************Rows length************', rowsLength)
})
})
The above strategies do not really give you the most solid test.
If you can, check some text that changes upon each iteration,
page.openDropdownMenu()
cy.get('dropdownOptions').then($options => {
let firstRowText = ''; // to control the loop, waiting for this to change
const menuOptionCount = $options.length;
page.closeDropdownMenu();
for (let i = 0; i < menuOptionCount; i++) {
page.openDropdownMenu();
cy.get('dropdownOptions').eq(i).click(); // fresh query each time through the loop
page.closeDropdownMenu();
cy.get('.table.rows').first().invoke('text')
.should('not.eq', firstRowText); // retry until text has changed
.then(newText => firstRowText = newText); // save for next loop
cy.get('.table.rows').then($rows => {
const rowsLength = $rows.length;
cy.log('****************Rows length************', rowsLength);
});
}
})
Upvotes: 2
Reputation: 18650
You can condense your code to something like this. Instead of using a for loop, use each
which is a cypress inbuilt method for looping.
it.only(
'Validate table Row changed length on menu option selection',
{defaultCommandTimeout: 10000},
() => {
page.openDropdownMenu()
cy.get('dropdownOptions').each(($options, index) => {
cy.wrap($options).eq(index).click()
page.closeDropdownMenu()
cy.get('.table.rows')
.its('length')
.then((rowsLength) => {
cy.log('****************Rows length************', rowsLength)
})
page.openDropdownMenu()
})
page.closeDropdownMenu()
}
)
Upvotes: 0