art
art

Reputation: 1412

Do something "if an element with some text is not present"

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.

Edit


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

Answers (2)

Fody
Fody

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();
    }
  })

Exact match

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

Ca&#237;que Coelho
Ca&#237;que Coelho

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

Related Questions