Reputation: 1412
This is basically for a ReactSelect element (behaves like a Select2 element with multi-select enabled), on which I'm trying to select some values which are not already selected.
If an option is selected, then there'll be an element as given below in the DOM
<div class="select__multi-value__label">option1</div>
and hence that options won't be present in the list. So, any code to click() that "option" will fail.
Is there a way to check whether an element with some particular text is available in the DOM?
something like,
options = ['option1','option2','option3'];
options.forEach(option =>{
cy.get('[test-id="react-select"]').then(reactSelect =>{
if(reactSelect.find('[class="select__multi-value__label"]').contains(option).length == 0){
//code to select that option
cy.get('div.select__menu-list > div[role="option"]').contains(option).click();
}
})
})
This find().contains() part doesn't work. How can I achieve this?
Thanks for any help.
Adding to the solution given below, can I get an exact match selector - say using a Regex?
let r = new RegExp("^" + option + "$");
...........
const selector = `div.select__multi-value__label:contains(${r})`;
This somehow doesn't work. Found a thread that recommends using filter(), but I don't know how to use it.
Is it possible?
Upvotes: 1
Views: 504
Reputation: 32042
You can do it by moving the contains()
inside the selector,
options = ['option1','option2','option3'];
options.forEach(option =>{
cy.get('[test-id="react-select"]').then(reactSelect =>{
const selector = `[class="select__multi-value__label"]:contains(${option})`
if(reactSelect.find(selector).length == 0){
//code to select that option
cy.get('div.select__menu-list > div[role="option"]')
.contains(option)
.click();
}
})
})
The .find().contains()
part in your code is using a different .contains()
to to the Cypress .contains()
.
It's invoking the jQuery .contains() which has a different purpose
Description: Check to see if a DOM element is a descendant of another DOM element.
I suppose you could also select the options directly and iterate them
options = ['option1','option2','option3'];
cy.get('div.select__menu-list > div[role="option"]')
.each(option =>{
if (options.includes(option.text()) {
option.click();
}
})
options = ['option1','option2','option3'];
options.forEach(option =>{
cy.get('[test-id="react-select"]').then(reactSelect =>{
const matchedOptions = reactSelect
.find('[class="select__multi-value__label"]')
.filter((index, el) => el.innerText === option) // exact
if(matchedOptions.length === 0){
//code to select that option
cy.get('div.select__menu-list > div[role="option"]')
.contains(option)
.click();
}
})
})
Upvotes: 2
Reputation: 459
You should avoid conditionals in tests as it goes against best practice.
A solution in this case following good practices would be to mock the response that comes from the API for you to handle the request as you want, so you will know exactly when there will be specific text on the screen instead of being a random behavior and you won't have to do conditionals.
You can read more about mocks here: https://docs.cypress.io/api/commands/intercept#Stubbing-a-response
But I also advise you to read this Cypress documentation on testing with conditionals: https://docs.cypress.io/guides/core-concepts/conditional-testing#What-you-ll-learn
Upvotes: 0