'Cypress: How to properly close a mat-select

So I'm using Cypress for testing our Angular application, but for some reason I always have an issue with closing mat-select components which are multiselect. Has anyone got a good solution for this?

function selectValue(id: string, value: string) {
    return cy.get(`mat-select[id="${id}"]`)
             .click()
             .then(() => 
                cy.get('mat-option')
                  .contains(value)
                  .click();
}


Solution 1:[1]

To close the list on a multi-select dropdown, do what a user does and click outside the list, e.g on the body

it('selects, closes, verifies', () => {

  cy.visit('https://material.angular.io/components/select/overview#multiple-selection')

  cy.get('div[role="listbox"]').should('not.exist')    // check list isn't open    

  cy.get('select-multiple-example').click()            // open
  cy.get('div[role="listbox"]').should('exist')        // check list is open    

  cy.contains('Extra cheese').click()                  // select an item
  cy.contains('Onion').click()                         // select an item
  cy.contains('Tomato').click()                        // select an item

  cy.get('body').click()                               // click outside the list

  cy.get('div[role="listbox"]').should('not.exist')    // check list isn't open    
  
  cy.get('select-multiple-example')
    .should('contain', 'Extra cheese, Onion, Tomato')  // verify
    
  cy.get('select-multiple-example')
    .should('not.contain', 'Mushroom')                 // verify contra
    
})

Solution 2:[2]

Another thing that worked in my case was

cy.get(`mat-select[data-testid="${dropdownTestId}"]`).focus().type('{esc}');

Solution 3:[3]

I suggest something like this:

Cypress.Commands.add('selectValue', (value) => {
  cy
      .get('mat-select').first().click()
      .get('.mat-option-text').contains(value).click()
      .get('.mat-option-text').should('not.visible')
      .get('.mat-select-value-text').first().should(([{ innerText }]) => {
        expect(innerText).equal(value)
      })
});

I tested it on https://material.angular.io/components/select/overview and it works on my local machine.

If something fails, feel free to ask questions

Solution 4:[4]

A better way is to use the new feature components harnesses

https://material.angular.io/cdk/test-harnesses/overview

for your problem it should work like this, first you create harness loader from the fixture in beforeEach statement

loader = TestbedHarnessEnvironment.loader(fixture);

then you can get the select harness by doing something like this

let selectHarness = await loader.getHarness(MatSelectHarness.with({selector: '#select-id'}));

now you can simply use the close method

selectHarness.close()

Solution 5:[5]

in my case it was not possible to click outside of the select box because overlay issue is blocking everything, for my case this "weird solution" worked:

cy.get('mat-option').contains(text).click().type('{end}').type('{esc}');

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Bat0u89
Solution 3 Przemyslaw Jan Beigert
Solution 4 Nichola
Solution 5 Yuqiu G.