22

I need to test a dropdown on angularjs application using cypress.

I would need to click on a dropdown and select or click an item from the dropdownlist. I tried as below which worked for one instance but not other time because the id number in the second get() method keeps changing as its dynamically generated. This is not a standard select with options as in html.

1) Is there anyway I can set an unique attribute on each option and just select the required one or can I just select based on the description of the list item? How can I do that?

2) Is the following right way of testing for a dropdown? I am sure there could be better way than this?

Please can anyone help

cy.get('[name="countries"]').click().get.('[id="selection_option_375"]').click()

DOM

 <md-select ng-model="target.countryType" name="countries" ng-required="requiredData.AssertRequiredFields" ng-change="oncountryTypeChanged($event)" 
  md-container-class="large" class="ng-pristine ng-untouched ng-empty ng-invalid ng-invalid-required" tabindex="0" aria-disabled="false" 
  role="listbox" aria-expanded="false" aria-multiselectable="false" id="select_297" aria-owns="select_container_298" aria-required="true" 
  required="required" aria-invalid="true" aria-label="country type" style=""><md-select-value class="md-select-value md-select-placeholder" 
  id="select_value_label_288">
  <span>country type</span><span class="md-select-icon" aria-hidden="true"></span>
  </md-select-value>
  <div class="md-select-menu-container large" aria-hidden="true" id="select_container_298"><md-select-menu class="_md"><md-content class="_md md-no-flicker">
                            <!-- ngRepeat: countryType in refData.countryDetails.countryType.Items --><md-option ng-repeat="countryType in refData.countryDetails.countryType.Items" ng-value="countryType" tabindex="0" class="ng-scope md-ink-ripple" role="option" aria-selected="false" id="select_option_369" aria-checked="true" value="[object Object]" style=""><div class="md-text ng-binding">
                                Country one
                            </div></md-option><md-option ng-repeat="countryType in refData.countryDetails.countryType.Items" ng-value="countryType" tabindex="0" class="ng-scope md-ink-ripple" role="option" aria-selected="false" id="select_option_370" aria-checked="true" value="[object Object]" style=""><div class="md-text ng-binding">
                                Country two
                            </div></md-option><md-option ng-repeat="countryType in refData.countryDetails.countryType.Items" ng-value="countryType" tabindex="0" class="ng-scope md-ink-ripple" role="option" aria-selected="false" id="select_option_371" aria-checked="true" value="[object Object]" style=""><div class="md-text ng-binding">
                                Country three
                            </div></md-option><md-option ng-repeat="countryType in refData.countryDetails.countryType.Items" ng-value="countryType" tabindex="0" class="ng-scope md-ink-ripple" role="option" aria-selected="false" id="select_option_372" aria-checked="true" value="[object Object]" style=""><div class="md-text ng-binding">
                                Country four
                            </div></md-option><md-option ng-repeat="countryType in refData.countryDetails.countryType.Items" ng-value="countryType" tabindex="0" class="ng-scope md-ink-ripple" role="option" aria-selected="false" id="select_option_373" aria-checked="true" value="[object Object]" style=""><div class="md-text ng-binding">
                                Country five
                            </div></md-option><md-option ng-repeat="countryType in refData.countryDetails.countryType.Items" ng-value="countryType" tabindex="0" class="ng-scope md-ink-ripple" role="option" aria-selected="false" id="select_option_374" aria-checked="true" value="[object Object]" style=""><div class="md-text ng-binding">
                                Country six
                            </div></md-option><md-option ng-repeat="countryType in refData.countryDetails.countryType.Items" ng-value="countryType" tabindex="0" class="ng-scope md-ink-ripple" role="option" aria-selected="false" id="select_option_375" aria-checked="true" value="[object Object]" style=""><div class="md-text ng-binding">
                                Country seven
                            </div></md-option><md-option ng-repeat="countryType in refData.countryDetails.countryType.Items" ng-value="countryType" tabindex="0" class="ng-scope md-ink-ripple" role="option" aria-selected="false" id="select_option_376" aria-checked="true" value="[object Object]" style=""><div class="md-text ng-binding">
                                Country eight
                            </div></md-option><md-option ng-repeat="countryType in refData.countryDetails.countryType.Items" ng-value="countryType" tabindex="0" class="ng-scope md-ink-ripple" role="option" aria-selected="false" id="select_option_377" aria-checked="true" value="[object Object]" style=""><div class="md-text ng-binding">
                                Country nine
                            </div></md-option><md-option ng-repeat="countryType in refData.countryDetails.countryType.Items" ng-value="countryType" tabindex="0" class="ng-scope md-ink-ripple" role="option" aria-selected="false" id="select_option_378" aria-checked="true" value="[object Object]" style=""><div class="md-text ng-binding">
                                Country ten
                            </div></md-option><md-option ng-repeat="countryType in refData.countryDetails.countryType.Items" ng-value="countryType" tabindex="0" class="ng-scope md-ink-ripple" role="option" aria-selected="false" id="select_option_379" aria-checked="true" value="[object Object]" style=""><div class="md-text ng-binding">
                                Country eleven
                            </div></md-option><!-- end ngRepeat: countryType in refData.countryDetails.countryType.Items -->
                        </md-content></md-select-menu></div>
                        </md-select>
ChinnaR
  • 797
  • 3
  • 9
  • 24

6 Answers6

21

Material Design Select and Cypress

This is the same basic problem as Access element whose parent is hidden - cypress.io, except this question is angularjs + md-select and that question was angular + mdc-select.

Nevertheless, the two versions of material design select use the same trick of making the parent control invisible (by setting width and height to 0) after clicking it to open the options.

cypress will not allow a click of an option, because it think options are invisible because the parent is invisible.

The work around is to use .then() to get access to the unwrapped list item, and use jquery click to select it instead of cypress click.

I have tested it on an Angular 5 setup, and because of the similarity of the problem expect it to work with an AngularJS setup.


AngularJS with md-select

describe('Testing material design select', function() {

  it('selects an option by click sequence (fails due to visibility issue)', function() {

    const doc = cy.visit('http://localhost:4200');
    cy.get('[name="countries"]').click();
    cy.get('md-option').contains('Country seven').click();

  });

  it('selects an option by click sequence', function() {

    const doc = cy.visit('http://localhost:4200')
    cy.get('[name="countries"]').click()
    cy.get('md-option').contains('Country seven').then(option => {

      // Confirm have correct option
      cy.wrap(option).contains('Country seven');  

      option[0].click();  // this is jquery click() not cypress click()

      // After click, md-select should hold the text of the selected option
      cy.get('[name="countries"]').contains('Country seven')  
    });
  });

});


Angular 2+ with mdc-select

describe('Testing material design select', function() {

  it('selects an option by click sequence (fails due to visibility issue)', function() {

    const doc = cy.visit('http://localhost:4200');
    cy.get('[name="countries"]').click();
    cy.get('mdc-select-item').contains('Country seven').click();

  });

  it('selects an option by click sequence', function() {

    const doc = cy.visit('http://localhost:4200')
    cy.get('[name="countries"]').click()
    cy.get('mdc-select-item').contains('Country seven').then(option => {

      // Confirm have correct option
      cy.wrap(option).contains('Country seven');

      option[0].click();

      // After click, mdc-select should hold the text of the selected option
      cy.get('[name="countries"]').contains('Country seven');
    });
  });

});
Richard Matsen
  • 20,671
  • 3
  • 43
  • 77
  • That didn't work. Firstly, there are 118 results of md-option, this is taking the account of all the md-option on the page I think. It is not selecting the item required. Secondly, it is timing out retrying cy.click() because this element is not visible. There is another dropdown which autopopulates based on the selection of item in the first, that dropdown is invisible because parent has css property:display:none. I tried force:true but it didn't work – ChinnaR Jan 23 '18 at 10:27
  • For the first point, I'm aiming for `.get('md-option')` to pick up the wole array of options, but then `.contains('Country seven')` to select just that option containing the text. Normally this should work (I think) - but is being clobbered by the 2nd problem. – Richard Matsen Jan 23 '18 at 10:34
  • For the 2nd problem see [Access element whose parent is hidden - cypress.io](https://stackoverflow.com/questions/47551639/access-element-whose-parent-is-hidden-cypress-io/47625195#47625195) - this question has a problem with `mdc-select`. Since yours is `md-select` I was hoping it was not the same issue, but since you mention visibility it is likely to be the same root cause. I will expand the answer tomorrow WRT to visibility issue. – Richard Matsen Jan 23 '18 at 10:39
  • Just to clarify, is it the second `click()` that fails? – Richard Matsen Jan 23 '18 at 10:41
  • yes, it's the second click that fails. First click is working fine by displaying items in there but is not selecting the required item. IS there anyway I can get into that particular block of code and select the option by using get('md-option').nth(6) ... – ChinnaR Jan 23 '18 at 11:14
  • Error with your code is throwing :This element '' is not visible because its parent '
    ' has Css property:'display:none' Fix this problem, or use {force:true} to disable error checking
    – ChinnaR Jan 23 '18 at 11:14
  • It works if it's a single dropdown, but then again if there is another dropdown having the same item name, it would fail – ChinnaR Jan 23 '18 at 17:02
  • The error you gave is exactly the same as the error on the other question I linked earlier. – Richard Matsen Jan 23 '18 at 17:40
  • **if there is another dropdown having the same item name, it would fail**, yes obviously - but why name two dropdown's the same? – Richard Matsen Jan 23 '18 at 17:42
  • second dropdown is selecting with the right item based on the selection of item in the first dropdown, but the first dropdown is not populating with 'country seven'. It's throwing error at the line "cy.get('[name="countries"]').contains('Country seven')" retrying:expected to find content: 'country seven' but never did. Second dropdown is populated with right item, but the first dropdown is just blank.'country seven' should appear as selected item – ChinnaR Jan 24 '18 at 10:22
  • You refer to two dropdowns, but the question only shows one dropdown. Are you talking about the two `cy.get()` commands? Most confusing. – Richard Matsen Jan 24 '18 at 10:32
  • I just mean the dropdown is not showing up with 'country seven' as the selected item. However the subsequent action when the selection of 'country seven' supposed to happen are fine. This is part of cascading dropdown, based on the selection of 'country seven' in the first dropdown, other dropdown will populate with corresponding item related to it. With your code, dropdown is not showing up 'country seven' as the selected item, it's just blank. Apologies for the confusion – ChinnaR Jan 24 '18 at 10:43
  • You said **Secondly, it is timing out retrying cy.click() because this element is not visible**. I think I solved that problem in my answer. I'd like to know if you are confirming that, because I can't test it on AngularJS without a lot of effort. Please confirm that error has gone away. – Richard Matsen Jan 24 '18 at 10:50
  • But I did not see any mention of a second dropdown linked to the first in your question. It sounds like another problem altogether. If so, please ask it in another question, and show the code which links the two dropdowns. – Richard Matsen Jan 24 '18 at 10:52
  • Really sorry for all the confusion. This is the error I am getting with your code: Timed out retrying: Expected to find content: 'Country Seven' within the element: but never did – ChinnaR Jan 24 '18 at 11:26
  • It's working for all other selection of items except that one item(country seven), which I will look into. Thank you for your help – ChinnaR Jan 24 '18 at 21:06
  • Wow is that weird or what? Thanks for the feedback, I was set to build an AngularJS version to try and figure it out. – Richard Matsen Jan 24 '18 at 21:15
5

For Angular using material dropdown:

cy.get('mat-select').contains('CA').click({ force: true })
Leo Davtyan
  • 203
  • 4
  • 11
3

If you use a select element with several options, try this:

cy.get('select').should('be.visible').select('OptionName', {force: true})
Torben
  • 217
  • 1
  • 3
  • 9
2

Triggering 'mousemove' solved this issue for me.

cy.get('[name="countries"]').click()
cy.get.('[id="selection_option_375"]').trigger('mousemove').click()
GonzaSSH
  • 466
  • 3
  • 2
2

If none of above solutions didn't work especially with angular, try this:

cy.get({selectlocator}).find("option:contains('text')").then($el =>
   $el.get(0).setAttribute("selected", "selected")
).parent().trigger("change")

Also, you could refer this link https://github.com/cypress-io/cypress/issues/757

Sathish
  • 43
  • 1
  • 2
1

This worked for me:

cy.get(this.dropdownlocactor).contains(optiontext)
  .then(element => {
    var text = element.text();
    cy.get(this.dropdownlocator).select(text);
});
Priyanshu
  • 3,040
  • 3
  • 27
  • 34