skip to Main Content

I’m attempting to select an item which renders a drop-down list of items that match a search.

I select the correct item once the drop-down list has been opened. The id values changes so they cannot be used.

This is the script in Cypress:

cy.get('input[placeholder="Search Something"]').type('Your search query').type('{enter}');
cy.contains('div span', 'XXXXX XXX').click();

or 

cy.get('div[role="listbox"]')
  .contains('span', 'XXX XXX')
  .should('exist')
  .click();

Below is the inspection from the page:

<div 
  class="w-full" 
  id="headlessui-combobox-button-137" 
  tabindex="-1" 
  aria-haspopup="listbox" 
  aria-expanded="true" 
  data-headlessui-state="open" 
  aria-controls="headlessui-combobox-options-139"
>
    <input 
      placeholder="Search Subscribers"  
      class="w-full inputFocus px-4 rounded-3xl text-ever-green  font-beatrice font-normal transition-colors focus:border-cornflower-blue focus:outline-none outline-none placeholder:text-slate-gray h-smButtonHeight text-sm border-2 border-duck-egg-blue"  
      id="headlessui-combobox-input-138"  
      role="combobox"  
      type="text"  
      aria-expanded="true"  
      aria-autocomplete="list"  
      data-headlessui-state="open"  
      value="Prod"  
      aria-controls="headlessui-combobox-options-139"  
      aria-activedescendant="headlessui-combobox-option-156"
    >
</div>

Below is the extract from the page the drop down:

<div 
  class="absolute z-10 w-full mt-2 overflow-auto text-base bg-white rounded-md shadow-dropdown max-h-60 focus:outline-none sm:text-sm left-0 right-0 mx-auto p-0"  
  aria-labelledby="headlessui-combobox-button-137"  
  role="listbox"  
  aria-multiselectable="true"  
  id="headlessui-combobox-options-139"  
  data-headlessui-state="open"
>
    <div  
      class="relative h-full max-h-60 p-2 overflow-y-auto"   
      role="none"
    >
        <div   
          class="relative"    
          style="height: 32px;"    
          role="none"   
        >   
        <div    
          class="absolute top-0 left-0 w-full"     
          id="headlessui-combobox-option-156"     
          role="option"     
          tabindex="-1"     
          aria-selected="true"     
          data-headlessui-state="active selected"     
          style="transform: translateY(0px);"    
        >    
          <span     
            class="cursor-pointer flex items-center gap-x-2 py-1.5 px-4.5 font-medium text-sm transition-colors lg:truncate text-cornflower-blue bg-ice-blue"   
          >   
              <span    
                class="w-1/2 xl:w-1/3 inline-block text-xs">+1 251 230 8828   
              </span>   
              <span    
                class="w-1/2 xl:w-1/3 inline-block text-xs"   
              >   
                  <div class="text-ever-green">Prod 701</div>
              </span>
              <span class="w-1/3 hidden xl:inline-block text-xs"> 
                  <div> 

Any solutions welcomed.

2

Answers


  1. Here is a function which I have adapted from my own for Mantine dropdown boxes. It should be able to be called simply as a function within your test specs.

    Cypress.Commands.add('selecter', (selectSelector, value) => {
      cy.get(selectSelector).scrollIntoView();
      cy.get(selectSelector).click({ force: true });
    
      const options = () =>
        cy.get('listbox').find('option');
      if (typeof value === 'string') {
        // If the given value is a string, select the option with that label
        return options()
          .contains(value, { matchCase: false })
          .click({ force: true });
      }
      if (typeof value === 'number') {
        // Else if it's a number, select the option at that index
        return options()
          .eq(value)
          .click({ force: true });
      }
      throw new Error(
        `value should be a string or number, but was '${value}' (${typeof value}).`,
      );
    });
    
    Login or Signup to reply.
  2. This is a HeadlessUi component that constructs components from divs, as shown in the code sample.

    Avoiding changing ids
    To access the parts needed for testing, you can use [role="listbox"] and [role="option"], which would be the equivalent to <select> and <option> in plain HTML5.

    Using the correct command sequence
    The relationship between listbox and options is parent-child, so instead of get().contains() I recommend get().find().

    The way you have done it, the "subject" (the queried element) is the listbox instead of the option, and click the parent listbox doesn’t make an option selection.

    cy.get('[role="listbox"]')
      .find('[role="option"]:contains("XXX XXX")')  // be careful with brackets and quote marks
      .click();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search