cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.72k stars 3.16k forks source link

Unable to select a value in p-dropdown form PrimeNG (not visible) #3019

Closed remcogeldhof closed 5 years ago

remcogeldhof commented 5 years ago

After two days of searching, after opening a stackoverflow post and after asking it in the Cypress chat, I decided to open an issue. Cypress is working fine on my Angular project, only on my dropdowns I have an issue. I'm unable to select a value.

Current behavior:

HTML CODE:

    <span class="eco-form-component__control">
            <p-dropdown formControlName="provenanceCountry"
                        [options]="countries"
                        [style]="{'width':'100%'}">
            </p-dropdown>
          </span>

Exact HTML:

<div _ngcontent-c11="" class="eco-form-component"><label _ngcontent-c11="" class="eco-form-component__label" ng-reflect-ng-class="eco-form-component__label"> Geïmporteerd uit </label><span _ngcontent-c11="" class="eco-form-component__control"><p-dropdown _ngcontent-c11="" formcontrolname="provenanceCountry" class="ng-tns-c14-7 ui-inputwrapper-filled ng-untouched ng-pristine ng-invalid" ng-reflect-style="[object Object]" ng-reflect-options="[object Object],[object Object" ng-reflect-name="provenanceCountry"><div class="ng-tns-c14-7 ui-dropdown ui-widget ui-state-default ui-corner-all ui-helper-clearfix" ng-reflect-ng-class="[object Object]" ng-reflect-ng-style="[object Object]" style="width: 100%;"><!--bindings={
  "ng-reflect-ng-if": "true"
}--><div class="ui-helper-hidden-accessible ng-tns-c14-7 ng-star-inserted"><select class="ng-tns-c14-7" aria-hidden="true" tabindex="-1" aria-label=" "><!--bindings={}--><!--bindings={}--><!--bindings={
  "ng-reflect-ng-if": "true"
}--><!----><!--bindings={
  "ng-reflect-ng-for-of": "[object Object],[object Object"
}--><option class="ng-tns-c14-7 ng-star-inserted" value=" "> </option><option class="ng-tns-c14-7 ng-star-inserted" value="BELGIUM">BELGIUM</option><option class="ng-tns-c14-7 ng-star-inserted" value="FRANCE">FRANCE</option><!----></select></div><div class="ui-helper-hidden-accessible"><input class="ng-tns-c14-7" readonly="" role="listbox" type="text" aria-label=" "></div><!--bindings={
  "ng-reflect-ng-if": "true"
}--><label class="ng-tns-c14-7 ui-dropdown-label ui-inputtext ui-corner-all ng-star-inserted" ng-reflect-ng-class="[object Object]"><!--bindings={
  "ng-reflect-ng-if": "true"
}--><!----> <!--bindings={
  "ng-reflect-ng-template-outlet-context": "[object Object]"
}--></label><!--bindings={
  "ng-reflect-ng-if": "false"
}--><!--bindings={}--><!--bindings={}--><div class="ui-dropdown-trigger ui-state-default ui-corner-right"><span class="ui-dropdown-trigger-icon ui-clickable pi pi-caret-down" ng-reflect-klass="ui-dropdown-trigger-icon ui-cl" ng-reflect-ng-class="pi pi-caret-down"></span></div><!--bindings={}--></div></p-dropdown></span><!--bindings={
  "ng-reflect-ng-if": "false"
}--></div>

typescript:

countries: any[];
this.countries = ([{label: ' ', value: ' '}, {label: 'Belgium', value: 'Belgium'}, {label: 'France', value: 'France'}]);

CYPRESS:

When I use these methods below, I get an error or I get the default value selected. On of my dropdowns:

Cypress methods that doesn't work:

cy.get('select').select('FR').should('have.value', 'FR')

Error:

> CypressError: Timed out retrying: cy.select() failed because this element is not visible:
> <select class="ng-tns-c16-2" aria-hidden="true" tabindex="-1" aria-label="Nederlands">...</select>
> This element '' is not visible because its content is being clipped by one of its parent elements, which has a CSS property of overflow: 'hidden', 'scroll' or 'auto'

When using {force: true} I won't get an error, but it's not working either.

Not working:

cy.get('select').select('FR',{force:true}).should('have.value', 'FR')

Not working:

cy.get('option').eq(2).click({force: true});

Not working:

cy.get('p-dropdown[formControlName="provenanceCountry"]').click();
    cy.get('p-dropdown[formControlName="provenanceCountry"]').get('select').then(option => {
      cy.wrap(option).get('p-dropdown[formControlName="provenanceCountry"]').contains('FRANCE').click();
    });
Error: 
> CypressError: Timed out retrying: cy.click() failed because this element is not visible:
>  <option class="ng-tns-c9-15 ng-star-inserted" value="[object
>  Object]">FRANCE</option>
> This element '<option.ng-tns-c9-15.ng-star-inserted>' is not visible because it has an effective width and height of: '0 x 0' pixels.
> Fix this problem, or use {force: true} to disable error checking.
> https://on.cypress.io/element-cannot-be-interacted-with

When I use {force: true} in my click, the error is just not shown.

Not working:

 cy.get('p-dropdown[formControlName="provenanceCountry"]').click();
 cy.get('[formcontrolname="provenanceCountry"]').find('select').select('FRANCE');

Desired behavior:

Select a value in my dropdown (not the default).

Versions

I'm using windows 7, google chrome

jennifer-shehane commented 5 years ago

Using the provided HTML, I am unable to reproduce this issue. I suspect the issue involves something from your css stylings - that Cypress is wrongly interpreting as not visible. Can you provide any relevant css styles to reproduce the issues with the provided HTML above?

screen shot 2019-01-02 at 4 00 55 pm screen shot 2019-01-02 at 4 01 01 pm
remcogeldhof commented 5 years ago

The html with all the divs around the dropdown, this html is used as a component.

<div class="row">
  <div class="col-xs-12">
    <div class="eco-card">
        <form [formGroup]="form" novalidate>
          <div class="eco-form-component">         
          <!-- Label  -->
          <span class="eco-form-component__control">
            <p-dropdown formControlName="provenanceCountry"
                        [options]="countries"
                        [style]="{'width':'100%'}">
            </p-dropdown>
          </span>
          <!-- Error message-->
        </div>
      </form>
    </div>
  </div>
</div>

Flexboxgrid css:

.row 
.col-xs-12

Other css:
.eco-card {
  background-color: #ffffff;
  padding: 30px;
  border: 1px solid #e5e5e5;
  margin-bottom: 25px;
}

.eco-form-component {
  margin-bottom: 20px;
&__control {
    margin: 10px 0;
    display: block;
    width: 100%;
  }
}
jennifer-shehane commented 5 years ago

I'm sorry. I'm still unable to replicate an error with what it provided. You will need to provide a repo with the exact reproducible error - the application code and test code that we can open and run.

Make an html page with the html, css, and js code to replicate exactly with the test code. Thanks.

viloskovic commented 5 years ago

Hello @jennifer-shehane and @remcogeldhof

On the website of PrimeNG this is the output of a p-dropdown-tag:

<p-dropdown optionlabel="name" placeholder="Select a City" class="ng-tns-c3-1 ng-pristine ng-valid ng-touched">
    <div class="ng-tns-c3-1 ui-dropdown ui-widget ui-state-default ui-corner-all ui-helper-clearfix ui-dropdown-clearable" style="width: 129px;">
        <div class="ui-helper-hidden-accessible ng-tns-c3-1 ng-star-inserted">
            <select class="ng-tns-c3-1" aria-hidden="true" tabindex="-1" aria-label=" ">
                <option class="ng-tns-c3-1 ng-star-inserted">Select a City</option>
                <option class="ng-tns-c3-1 ng-star-inserted" value="[object Object]">New York</option>
                <option class="ng-tns-c3-1 ng-star-inserted" value="[object Object]">Rome</option>
                <option class="ng-tns-c3-1 ng-star-inserted" value="[object Object]">London</option>
                <option class="ng-tns-c3-1 ng-star-inserted" value="[object Object]">Istanbul</option>
                <option class="ng-tns-c3-1 ng-star-inserted" value="[object Object]">Paris</option>
            </select>
        </div>
        <div class="ui-helper-hidden-accessible">
            <input class="ng-tns-c3-1" readonly="" role="listbox" type="text" aria-label=" ">
            </div>
            <label class="ng-tns-c3-1 ui-dropdown-label ui-inputtext ui-corner-all ui-placeholder ng-star-inserted">Select a City</label>
            <div class="ui-dropdown-trigger ui-state-default ui-corner-right">
                <span class="ui-dropdown-trigger-icon ui-clickable pi pi-caret-down"></span>
            </div>
        </div>
    </p-dropdown>

However if we take something more styled like the 'Ultima' theme, we get this:

<p-dropdown class="ng-tns-c4-30 ui-inputwrapper-filled ng-pristine ng-valid ng-touched">
    <div class="ng-tns-c4-30 ui-dropdown ui-widget ui-state-default ui-corner-all ui-helper-clearfix ui-dropdown-open">
        <div class="ui-helper-hidden-accessible">
            <input class="ng-tns-c4-30" readonly="" role="listbox" type="text" aria-label="Select City">
            </div>
            <label class="ng-tns-c4-30 ui-dropdown-label ui-inputtext ui-corner-all ng-star-inserted">
                Select City
            </label>
            <div class="ui-dropdown-trigger ui-state-default ui-corner-right">
                <span class="ui-dropdown-trigger-icon ui-clickable pi pi-caret-down"></span>
            </div>
            <div class="ng-trigger ng-trigger-overlayAnimation ng-tns-c4-30 ui-dropdown-panel ui-widget ui-widget-content ui-corner-all ui-shadow ng-star-inserted" style="z-index: 1002; top: 23px; left: 0px; transform: translateY(0px); opacity: 1;">
                <div class="ui-dropdown-items-wrapper" style="max-height: 200px;">
                    <ul class="ui-dropdown-items ui-dropdown-list ui-widget-content ui-widget ui-corner-all ui-helper-reset">
                        <li class="ng-tns-c4-30 ui-dropdown-item ui-corner-all ui-state-highlight ng-star-inserted" style="">
                            <span class="ng-tns-c4-30 ng-star-inserted">Select City</span>
                        </li>
                        <li class="ng-tns-c4-30 ui-dropdown-item ui-corner-all ng-star-inserted" style="">
                            <span class="ng-tns-c4-30 ng-star-inserted">New York</span>
                        </li>
                        <li class="ng-tns-c4-30 ui-dropdown-item ui-corner-all ng-star-inserted" style="">
                            <span class="ng-tns-c4-30 ng-star-inserted">Rome</span>
                        </li>
                        <li class="ng-tns-c4-30 ui-dropdown-item ui-corner-all ng-star-inserted" style="">
                            <span class="ng-tns-c4-30 ng-star-inserted">London</span>
                        </li>
                        <li class="ng-tns-c4-30 ui-dropdown-item ui-corner-all ng-star-inserted" style="">
                            <span class="ng-tns-c4-30 ng-star-inserted">Istanbul</span>
                        </li>
                        <li class="ng-tns-c4-30 ui-dropdown-item ui-corner-all ng-star-inserted" style="">
                            <span class="ng-tns-c4-30 ng-star-inserted">Paris</span>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    </p-dropdown>

In the first case (I believe you, @jennifer-shehane tested this one) cypress shouldn't run in that much trouble. However in the second case, the one I believe @remcogeldhof is having, cypress will run in some trouble.

In the first case this will probably work without any problem because it searches for <select> and after that the <option>-tags( .select() searches for the <option>-tags):

cy.get('select').select('London')

In the second case we don't have any <select> or <option>-tags.. So we have to find another solution. I am unable to run local but here is my guess for @remcogeldhof his problem:

cy.get('p-dropdown[formControlName="provenanceCountry"]').click().find('ul li > span').contains('France').click();

The only thing that is bothering me about this solution is that it's going for all the countries in a span and checks them one by one.. I don't think that performance-wise that's a good approach. Maybe someone got suggestions for this?

EDIT: Since .contains() can also use selectors I think it is shorter to say:

cy.get('p-dropdown[formControlName="provenanceCountry"]').click().contains('ul li > span', 'France').click();
remcogeldhof commented 5 years ago

Thank you for your reply @viloskovic. Both of your solutions are working fine!

Like you said, the second solution is the best one. When the dropdown contains a lot of values, the select takes more time than it should take.

So performance-wise this is the best solution for my problem: cy.get('p-dropdown[formControlName="provenanceCountry"]').click().contains('ul li > span', 'France').click();

testtek commented 3 years ago

cy.get('p-dropdown[formControlName="country"]').click().contains('ul li > span', 'Indian').click();

This solution doesn't work after Cypress version 5.2.0 (most probably after this bug fix https://github.com/cypress-io/cypress/issues/8494) ; get below error

`Timed out retrying: cy.click() failed because this element is detached from the DOM.

Indian

Cypress requires elements be attached in the DOM to interact with them.

The previous command that ran was:

cy.contains()

This DOM element likely became detached somewhere between the previous and current command.

Common situations why this happens:

You typically need to re-query for the element or add 'guards' which delay Cypress from running new commands`

tfossoul commented 3 years ago

Hi,

This doesn't work in cypress 8.0.0. Does someone know how to do it ?

In my case I am able to click on the list, open and see items. Then I programmatically click on the first element of the list, the list disappear and... that's all... The item is never selected..

andi-dev commented 2 years ago

@tfossoul I have the same issue you describe. Did you figure out what was wrong in your case?

solangeDev commented 2 years ago

I do found one solutions this instruction selected the first option. version "cypress": "^9.1.0",

cy.get('p-dropdown[formControlName="category"]') .find('.p-dropdown') .click({ force: true }) .find('.p-dropdown-items-wrapper > .p-dropdown-items') .click({ force: true }) .get('.p-dropdown-item') .children() .first() .click({ force: true });

upotekhi commented 2 years ago

@tfossoul I have the same issue you describe. Did you figure out what was wrong in your case?

Try to use click with { force: true } - it helped me.

Aulerien commented 1 year ago

I do found one solutions this instruction selected the first option. version "cypress": "^9.1.0",

cy.get('p-dropdown[formControlName="category"]') .find('.p-dropdown') .click({ force: true }) .find('.p-dropdown-items-wrapper > .p-dropdown-items') .click({ force: true }) .get('.p-dropdown-item') .children() .first() .click({ force: true });

That hasn't work for me. I make some change like this, and it works: cy.get('p-dropdown[formControlName="category"]') .find('.p-dropdown') .click({ force: true }) .get('.p-dropdown-items-wrapper > .p-dropdown-items') .click({ force: true }) .find('.p-dropdown-item') .children() .first() .click({ force: true });