Cypress unable to select multiselect with loop

1.2k views Asked by At

I am writing a React application that I'm testing with Cypress. In my integration tests I've written a cypress command that takes an array of strings, in order to select items in a multi-value select box.

The code I'm using looks roughly like this:

Cypress.Commands.add("command", (options) => {
  options.forEach((option) => {
    cy.get("div[data-g-portal-id='1']") // this is the container for the select box dropdown
      .find("div[role='menubar']")
      .contains(option)
      .click({ force: true });
  });
}

I've tried various iterations of this, including things like cy.wrap and .each. Whatever I do, when the array contains more than one item, it clicks one item, the item is marked as selected successfully, then it clicks the other item, marks it as selected, but the first item loses its selection state. Its as if the internal state of the component never really got the initial change.

I've confirmed this is not a bug in my application; when testing it manually, the multi-select works fine. But Cypress just doesn't want to know. Any help would be much appreciated.

1

There are 1 answers

0
Richard Matsen On

The v2.grommet.io/select uses a "portal" to display the dropdown options.

The portal is just a div that's appended to body when the dropdown opened and removed again when an option is clicked.

Problem is, there isn't a property to connect the dropdown and portal containing the options. There may be other portals present e.g the Layer component uses a portal.

The options portal we need to target will always be the last portal on the page (since we just opened the dropdown). In the custom command, applying the .last() command will select the options portal.

Cypress.Commands.add("multiselect", (options) => {
  options.forEach((option) => {

    cy.get(`[data-g-portal-id]`)
      .last()            // just opened the dropdown so option are in the last portal
      .find("div[role='menubar']")
      .contains(option)
      .click();
  });
});


cy.get('input[name="my-select"]')
  .click();                           // open dropdown
  .multiselect(['First', 'Third']);

cy.get('input[name="my-select"]')
  .click();                           // close dropdown

cy.get('input[name="my-select"]')
  .should('have.value', 'multiple')

The test ends with dropdown displaying the text "multiple".


Configuration of the Select,

<Select
  multiple               // allow multiple selected options
  closeOnChange={false}  // do not close the dropdown between selections
  name="my-select"       
  options={myOptions}
  ...
/>