web-dev-qa-db-fra.com

Comment sélectionner une option dans le test de menu déroulant e2e

J'essaie de sélectionner une option dans une liste déroulante pour les tests angulaires e2e à l'aide de rapporteur.

Voici l'extrait de code de l'option select:

<select id="locregion" class="create_select ng-pristine ng-invalid ng-invalid-required" required="" ng-disabled="organization.id !== undefined" ng-options="o.id as o.name for o in organizations" ng-model="organization.parent_id">
    <option value="?" selected="selected"></option>
    <option value="0">Ranjans Mobile Testing</option>
    <option value="1">BeaverBox Testing</option>
    <option value="2">BadgerBox</option>
    <option value="3">CritterCase</option>
    <option value="4">BoxLox</option>
    <option value="5">BooBoBum</option>
</select>

J'ai essayé:

ptor.findElement(protractor.By.css('select option:1')).click();

Cela me donne l'erreur suivante:

Une chaîne non valide ou illégale a été spécifiéeInformations sur la construction: version: '2.35.0', révision: 'c916b9d', heure: '2013-08-12 15:42:01' Informations système: os.name : 'Mac OS X', os.Arch: 'x86_64', os.version: '10.9 ', Java.version:' 1.6.0_65 ' Informations sur le pilote: driver.version: inconnue

J'ai aussi essayé:

ptor.findElement(protractor.By.xpath('/html/body/div[2]/div/div[4]/div/div/div/div[3]/ng-include/div/div[2]/div/div/organization-form/form/div[2]/select/option[3]')).click();

Cela me donne l'erreur suivante:

ElementNotVisibleError: L'élément n'est pas visible et ne peut donc pas être interagi avec Durée de la commande ou délai d'attente: 9 millisecondes Informations de construction: version: '2.35.0', révision: 'c916b9d', heure: '2013-08-12 15:42:01' Informations système: os.name: 'Mac OS X', os.Arch: 'x86_64', os.version: '10.9 ', Java.version:' 1.6.0_65 ' ID de session: bdeb8088-d8ad-0f49-aad9-82201c45c63f Informations sur le pilote: org.openqa.Selenium.firefox.FirefoxDriver Capabilities [{platform = MAC, acceptSslCerts = true, javascriptEnabled = true, browserName = firefox, rotatable = false, locationContextEnabled = true, version = 24.0, cssSelectorsEnabled = true, databaseEnabled = true, handlesAlerts = true, browserConnectionEnabled = true, nativeEvents = true , webStorageEnabled = true, applicationCacheEnabled = false, takesScreenshot = true}]

Est-ce que n'importe qui peut m'aider s'il vous plaît avec ce problème ou jeter un peu de lumière sur ce que je pourrais faire mal ici.

107
Ranjan Bhambroo

J'ai eu un problème similaire et j'ai finalement écrit une fonction d'assistance qui sélectionne les valeurs de liste déroulante.

J’ai finalement décidé que j’allais bien à la sélection par numéro d’option et j’ai donc écrit une méthode qui prend un élément et l’optionNumber, et sélectionne cette optionNumber. Si l'optionNumber est null, elle ne sélectionne rien (en laissant le menu déroulant non sélectionné).

var selectDropdownbyNum = function ( element, optionNum ) {
  if (optionNum){
    var options = element.all(by.tagName('option'))   
      .then(function(options){
        options[optionNum].click();
      });
  }
};

J'ai écrit un article de blog si vous voulez plus de détails, il couvre également la vérification du texte de l'option sélectionnée dans un menu déroulant: http://technpol.wordpress.com/2013/12/01/protractor-and-dropdowns-validation/

76
PaulL

Pour moi a travaillé comme un charme

element(by.cssContainingText('option', 'BeaverBox Testing')).click();

J'espère que ça aide.

236
Fatz

Une approche élégante impliquerait faire une abstraction similaire à ce que les autres liaisons de langage Selenium proposent immédiatement (par exemple, une classe Select en Python ou Java).

Faisons un wrapper commode} et cachons les détails de l'implémentation à l'intérieur:

var SelectWrapper = function(selector) {
    this.webElement = element(selector);
};
SelectWrapper.prototype.getOptions = function() {
    return this.webElement.all(by.tagName('option'));
};
SelectWrapper.prototype.getSelectedOptions = function() {
    return this.webElement.all(by.css('option[selected="selected"]'));
};
SelectWrapper.prototype.selectByValue = function(value) {
    return this.webElement.all(by.css('option[value="' + value + '"]')).click();
};
SelectWrapper.prototype.selectByPartialText = function(text) {
    return this.webElement.all(by.cssContainingText('option', text)).click();   
};
SelectWrapper.prototype.selectByText = function(text) {
    return this.webElement.all(by.xpath('option[.="' + text + '"]')).click();   
};

module.exports = SelectWrapper;

Exemple d'utilisation (notez à quel point il est lisible et facile à utiliser):

var SelectWrapper  = require('select-wrapper');
var mySelect = new SelectWrapper(by.id('locregion'));

# select an option by value
mySelect.selectByValue('4');

# select by visible text
mySelect.selectByText('BoxLox');

Solution provenant du sujet suivant: Sélectionnez -> option abstraction .


FYI, créé une demande de fonctionnalité: Sélectionnez -> option abstraction .

26
alecxe
element(by.model('parent_id')).sendKeys('BKN01');
20
Sandesh Danwale

Pour accéder à une option spécifique, vous devez fournir le sélecteur nth-child ():

ptor.findElement(protractor.By.css('select option:nth-child(1)')).click();
15
bekite

C'est comme ça que j'ai fait ma sélection.

function switchType(typeName) {
     $('.dropdown').element(By.cssContainingText('option', typeName)).click();
};
7
Xotabu4

Voici comment je l'ai fait:

$('select').click();
$('select option=["' + optionInputFromFunction + '"]').click();
// This looks useless but it slows down the click event
// long enough to register a change in Angular.
browser.actions().mouseDown().mouseUp().perform();
5
Droogans

Essayez ceci, cela fonctionne pour moi:

element(by.model('formModel.client'))
    .all(by.tagName('option'))
    .get(120)
    .click();
5
Javeed

Vous pouvez essayer cet espoir que cela fonctionnera

element.all(by.id('locregion')).then(function(selectItem) {
  expect(selectItem[0].getText()).toEqual('Ranjans Mobile Testing')
  selectItem[0].click(); //will click on first item
  selectItem[3].click(); //will click on fourth item
});
4
Zahid Afaque

Une autre façon de définir un élément d'option:

var select = element(by.model('organization.parent_id'));
select.$('[value="1"]').click();
3

Nous avons écrit une bibliothèque qui comprend 3 façons de sélectionner une option:

selectOption(option: ElementFinder |Locator | string, timeout?: number): Promise<void>

selectOptionByIndex(select: ElementFinder | Locator | string, index: number, timeout?: number): Promise<void>

selectOptionByText(select: ElementFinder | Locator | string, text: string, timeout?: number): Promise<void>

La fonction supplémentaire de ces fonctions est qu’ils attendent que l’élément soit affiché avant d’effectuer toute action sur la variable select.

Vous pouvez le trouver dans npm @ hetznercloud/protractor-test-helper . Des typages pour TypeScript sont également fournis.

3
crashbus

Pour sélectionner des éléments (options) avec des identifiants uniques comme ici:

<select
    ng-model="foo" 
    ng-options="bar as bar.title for bar in bars track by bar.id">
</select>

J'utilise ceci:

element(by.css('[value="' + neededBarId+ '"]')).click();
2
Vladius

Le problème est que les solutions qui fonctionnent sur les boîtes de sélection angulaires normales ne fonctionnent pas avec Angular Material md-select et md-option en utilisant un rapporteur. Celui-ci a été posté par un autre, mais cela a fonctionné pour moi et je suis incapable de commenter son message pour le moment (seulement 23 points de repère). En outre, j'ai nettoyé un peu, au lieu de browser.sleep, j'ai utilisé browser.waitForAngular ();

element.all(by.css('md-select')).each(function (eachElement, index) {
    eachElement.click();                    // select the <select>
    browser.waitForAngular();              // wait for the renderings to take effect
    element(by.css('md-option')).click();   // select the first md-option
    browser.waitForAngular();              // wait for the renderings to take effect
});
2
peterhendrick

Peut-être pas super élégant, mais efficace:

function selectOption(modelSelector, index) {
    for (var i=0; i<index; i++){
        element(by.model(modelSelector)).sendKeys("\uE015");
    }
}

Ceci envoie simplement la touche vers le bas sur la sélection souhaitée. Dans notre cas, nous utilisons modelSelector mais vous pouvez évidemment utiliser un autre sélecteur.

Puis dans mon modèle d'objet de page:

selectMyOption: function (optionNum) {
       selectOption('myOption', optionNum)
}

Et du test:

myPage.selectMyOption(1);
2
Calahad

Sélectionnez une option par index:

var selectDropdownElement= element(by.id('select-dropdown'));
selectDropdownElement.all(by.tagName('option'))
      .then(function (options) {
          options[0].click();
      });
1
Shardul

Aide pour définir un élément d'option:

selectDropDownByText:function(optionValue) {
            element(by.cssContainingText('option', optionValue)).click(); //optionValue: dropDownOption
        }
1
Adnan Ghaffar

Il y a un problème avec les options de sélection dans Firefox que le piratage de Droogans corrige ce que je veux mentionner ici explicitement, en espérant que cela puisse éviter des ennuis à quelqu'un: https://github.com/angular/protractor/issues/480 .

Même si vos tests réussissent localement avec Firefox, vous constaterez peut-être qu'ils échouent avec CircleCI ou TravisCI, ou avec tout ce que vous utilisez pour le déploiement et le CI. Être conscient de ce problème depuis le début m'aurait fait gagner beaucoup de temps :)

1
Julia Jacobs

Si ci-dessous est la liste déroulante donnée

            <select ng-model="operator">
            <option value="name">Addition</option>
            <option value="age">Division</option>
            </select>

Ensuite, le code protractorjs peut être

        var operators=element(by.model('operator'));
    		operators.$('[value=Addition]').click();

Source - https://github.com/angular/protractor/issues/600

1
Ajay Patil
----------
element.all(by.id('locregion')).then(function(Item)
{
 // Item[x] = > // x is [0,1,2,3]element you want to click
  Item[0].click(); //first item

  Item[3].click();     // fourth item
  expect(Item[0].getText()).toEqual('Ranjans Mobile Testing')


});
0
Pramod Dutta

J'ai un peu amélioré la solution écrite par PaulL . Tout d'abord, j'ai corrigé le code pour qu'il soit compatible avec la dernière API de Protractor. Et puis je déclare la fonction dans la section 'onPrepare' d'un fichier de configuration de Protractor en tant que membre de l'instance browser, afin qu'elle puisse être référencée sous n'importe quelle spécification e2e.

  onPrepare: function() {
    browser._selectDropdownbyNum = function (element, optionNum) {
      /* A helper function to select in a dropdown control an option
      * with specified number.
      */
      return element.all(by.tagName('option')).then(
        function(options) {
          options[optionNum].click();
        });
    };
  },
0
trunikov

Je cherchais des réponses sur la manière de sélectionner une option dans un menu déroulant de modèle et j'ai utilisé cette combinaison qui m'a aidé avec du matériel angulaire.

element (by.model ("ModelName")). click (). element (By.xpath ("emplacement xpath")). click ();

il semble que, lorsque le code est jeté sur une seule ligne, il peut trouver l'élément dans la liste déroulante.

J'ai pris beaucoup de temps pour cette solution. J'espère que cela aidera quelqu'un.

0
tony2tones

Voici comment procéder par valeur d’option ou par index . Cet exemple est un peu brut, mais il montre comment faire ce que vous voulez:

html: 

<mat-form-field id="your-id">
    <mat-select>
        <mat-option [value]="1">1</mat-option>
        <mat-option [value]="2">2</mat-option>
    </mat-select>
</mat-form-field>

ts:

function selectOptionByOptionValue(selectFormFieldElementId, valueToFind) {

  const formField = element(by.id(selectFormFieldElementId));
  formField.click().then(() => {

    formField.element(by.tagName('mat-select'))
      .getAttribute('aria-owns').then((optionIdsString: string) => {
        const optionIds = optionIdsString.split(' ');    

        for (let optionId of optionIds) {
          const option = element(by.id(optionId));
          option.getText().then((text) => {
            if (text === valueToFind) {
              option.click();
            }
          });
        }
      });
  });
}

function selectOptionByOptionIndex(selectFormFieldElementId, index) {

  const formField = element(by.id(selectFormFieldElementId));
  formField.click().then(() => {

    formField.element(by.tagName('mat-select'))
      .getAttribute('aria-owns').then((optionIdsString: string) => {
        const optionIds = optionIdsString.split(' ');

        const optionId = optionIds[index];
        const option = element(by.id(optionId));
        option.click();
      });
  });
}

selectOptionByOptionValue('your-id', '1'); //selects first option
selectOptionByOptionIndex('your-id', 1); //selects second option
0
KVarmark

Une autre façon de définir un élément d'option:

var setOption = function(optionToSelect) {

    var select = element(by.id('locregion'));
    select.click();
    select.all(by.tagName('option')).filter(function(elem, index) {
        return elem.getText().then(function(text) {
            return text === optionToSelect;
        });
    }).then(function(filteredElements){
        filteredElements[0].click();
    });
};

// using the function
setOption('BeaverBox Testing');
0
flaviomeira10

Vous pouvez sélectionner les options du menu déroulant par valeur: $('#locregion').$('[value="1"]').click();

0
Sander Lepik
static selectDropdownValue(dropDownLocator,dropDownListLocator,dropDownValue){
    let ListVal ='';
    WebLibraryUtils.getElement('xpath',dropDownLocator).click()
      WebLibraryUtils.getElements('xpath',dropDownListLocator).then(function(selectItem){
        if(selectItem.length>0)
        {
            for( let i =0;i<=selectItem.length;i++)
               {
                   if(selectItem[i]==dropDownValue)
                   {
                       console.log(selectItem[i])
                       selectItem[i].click();
                   }
               }            
        }

    })

}
0
Javed Ali

Nous voulions utiliser la solution élégante en utilisant le matériel angularjs mais cela n’a pas fonctionné car il n’existait aucune balise option/md-option dans le DOM tant que l’on n’avait pas cliqué sur md-select. Donc, la manière "élégante" n'a pas fonctionné pour nous (notez le matériau angulaire!) Voici ce que nous avons fait pour elle à la place, je ne sais pas si c'est la meilleure façon, mais ça marche définitivement maintenant

element.all(by.css('md-select')).each(function (eachElement, index) {
    eachElement.click();                    // select the <select>
    browser.driver.sleep(500);              // wait for the renderings to take effect
    element(by.css('md-option')).click();   // select the first md-option
    browser.driver.sleep(500);              // wait for the renderings to take effect
});

Nous avions besoin de 4 sélections sélectionnées et lorsque la sélection est ouverte, une superposition permet de sélectionner la sélection suivante. C’est la raison pour laquelle nous devons attendre 500 ms pour ne pas avoir de problèmes avec les effets matériels toujours en action. 

0
pascalwhoop