To do some tests, I need to set fields to a value. I'm having some trouble to set a droplist the best way. Other suites seem to already start before a suite with the droplist is done. I'm looping through fields, and per field made a suite, specifically to ensure they are not done parallel. The suite sets and checks the field.
For the droplist (quasar q-select) the situation is I don't know how many options there are, and after n options, new options are added to the selection content and old ones removed. This means if you just select the div which contains all the options, it will work if you value would be in that amount.
Right now I have this custom function for a droplist. Each time you press the arrow down, the selection moves down, and when needed it will add the next options to the list. Hence I keep need to get the content.
Cypress.Commands.add('selectOption', (strOptionValue) => {
function funcSelect (strOptionValue, iIndex) {
cy.get('.q-select__options--content')
.find('.q-item')
.eq(iIndex)
.then($oOption => {
cy.wrap($oOption)
.find('[class=q-item__label]')
.then($oOptionLabel => {
const strListValue = $oOptionLabel.text();
cy.log('['+strOptionValue+']-['+strListValue+']');
if (strListValue === strOptionValue) {
cy.wrap($oOption)
.click();
} else {
cy.wrap($oOption)
.type('{downarrow}');
funcSelect(strOptionValue, iIndex + 1);
}
});
});
}
funcSelect(strOptionValue, 0);
});
What I think is not right: using the index. The amount doesn't change in the list, and now it keeps checking the whole list. I think it should somehow be possible to do:
Any ideas here?
EDIT: There are two additional challenges: a. The start is sometimes at the middle of the total amount of items. The arrow down, at the last item moves to the first. This is okay, but it means a break out needs to be on the item where you first started too. b. The 'arrowdown' does the same as the click, it selects the item. I'm still checking, but it might cause a problem in continuing with the test cycle before the actual value is clicked
I think you're on the right track with the recursive function, but it needs a break-out guard to stop infinite recursion.
Then I'd get all existing option labels that Cypress can currently pick up (i.e loaded into DOM) and see if the search value is in the list.
Since the list changes each recursion, I would re-query the option inside the if/else rather than wrapping.
Lastly I would chain the recursion call inside a .then()
, since .type('{downarrow}')
happens on the Cypress command queue and you only want to move to next call after that step finishes. You may also want to use a small wait or use an intercept wait if the items are fetched from an API.
function selectOption(searchForValue, attempt = 0) {
if (attempt > 10 ) throw 'Too many attempts - item not found';
cy.get('.q-select__options--content')
.find('[class=q-item__label]')
.then($labels => {
const listValues = [...$labels].map(label => label.innerText)
if (listValues.includes(searchForValue) {
cy.contains('.q-select__options--content .q-item', searchForValue)
.click()
} else {
cy.contains('.q-select__options--content .q-item', searchForValue)
.type('{downarrow}')
.then(() => {
cy.wait(100) // or wait on an intercept alias if API involved
selectOption(searchForValue, attempt + 1)
})
}
})
}
selectOption(searchForValue);
BTW I think func
and str
prefixes were officially deprecated in 1996 ;).
Overcoming problem with down arrow
Based on your comment about down-arrow, I tried it out on the "Standard" quasar select with 1000 items.
Some of the selectors needed adjusting, but the principle works.
function selectOption(searchValue, attempt = 0) {
if (attempt > 100 ) throw 'Too many attempts - item not found';
cy.get('.q-item__label')
.then($labels => {
const listValues = [...$labels].map(label => label.innerText)
if (listValues.includes(searchValue)) {
cy.contains('.q-item__label', searchValue).click()
} else {
const lastItem = listValues[listValues.length -1]
cy.contains('.q-item__label', lastItem)
.type('{downarrow}')
.then(() => {
selectOption(searchValue, attempt + 1) // next batch
})
}
})
}
const searchValue = '500'
cy.get('.q-field__append').click(); // open dropdown
selectOption(searchValue); // find value
cy.get('.q-field__control-container span') // confirm value
.should('have.text', searchValue) // passes ✅