简体   繁体   中英

Select value in p-dropdown from PrimeNG using Cypress

I try to select a value in my dropdown list using Cypress. I have tried several ways to do so, but none of them worked. It always select the value that is already selected.

In the Cypress documenation I found this:

cy.get('select').select('apples').should('have.value', '456')

When I apply this on my code ... :

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

... I get this 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'

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, the error is skipped, but it still doesn't work.

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

I also tried it without using select, but using click. This also just select the selected one, not the third selected.

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

Using .type({downarrow}) also fails because it is not a text input field.

So I'm really out of ideas right now.

I want to test multiptle dropdowns, this is one of them:

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

EDIT:

I also tried the following, here I get the right value (France), but he cannot click on it.

  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.

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>

I'm Not familiar with angular, but it seems the generated HTML for <option> has value attr set to [object Object] which means you're passing an object to it instead of a primitive value which can be serialized via its .toString() method.

Also note, that if you can't use <options> 's value attribute for some reason (eg it's not present), cypress' .select() also considers the textContent value (the text between the <option> tags):

describe('test', () => {
    it('test', () => {
        cy.window().then( win => {
            win.document.write(`
                <select>
                    <option>empty</option>
                    <option value="nyc">New York</option>
                    <option>Paris</option>
                </select>
            `);
        });
        cy.get('select').select('nyc'); // value attribute
        cy.get('select').select('Paris'); // textContent value
    });
});

EDIT: from the HTML code you posted, it seems you're not calling cy.select() on a <select> element, which you should:

cy.get('[formcontrolname="provenanceCountry"]').find('select').select('FRANCE');

I have used the above HTML given in the question. Using the cypress invoke text method, received all the drop-down list box text and passed into a getCityText(text) function as an argument. Then I have assigned the text received into an array called listText . Further, I have removed all the extra things that found inside the array, like newlines, commas, carriage returns etc. Then return the proper array value and later assert it with actual vs expected . Now the test is passing successfully.

The reason why I have to choose an extra js function is to handle the following assertion error that cypress was throwing .. expected **, , BELGIUM, FRANCE, ** to deeply equal [ BELGIUM, FRANCE ] Happy to know if any other easy way to handle newlines, commas etc

describe('Verify the list box values are selected', function () {
        it.only('Test the drop down values', function () {
         cy.visit('urlgoeshere')
         cy.get('select[aria-hidden="true"]').parents('.ui-helper-clearfix').find('div').find('select').invoke('text')
            .then(text=>{
              var finalArr =  new Array();
              finalArr = getCityText(text);
              console.log(finalArr);
              expect(finalArr).to.contain(['BELGIUM', 'FRANCE'])
               })
            })
        })

// Function which handles the text received and return values after removing all un necessary 'new lines, commas etc'

function getCityText(text){
  var listText = new Array();
  var trimText;
  listText = text;
  for(var i=0; i<=listText.length; i++){
    trimText = listText.replace(/\n|\r+/g, ' ');
    var nText = trimText.trim();
    var fText = nText.replace(" ", ",")
  }
  return fText;
}

在此处输入图像描述

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 theme of PrimeNG 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 cypress shouldn't run in that much trouble. However in the second case, the one I believe you are 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 at the moment but here is my guess for your problem:

cy.get('p-dropdown[formControlName="provenanceCountry"]').click().find('ul li > span').contains('France').click();
or if I read the documentation correctly and `.contains()` has indeed the option to pass selectors:
 cy.get('p-dropdown[formControlName="provenanceCountry"]').click().contains('ul li > span', 'France').click();

I 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 });

这对我有用...您需要在点击事件中提供强制选项 true

cy.get('p-dropdown[formControlName="countryName"]').click().contains('ul li > span', 'France').parent('li').click({force: true});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM