Come selezionare l'opzione nei test di protractorjs e2e a discesa


121

Sto cercando di selezionare un'opzione da un menu a discesa per i test e2e angolari utilizzando il goniometro.

Ecco lo snippet di codice dell'opzione di selezione:

<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>

Ho provato:

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

Questo mi dà il seguente errore:

È stata specificata una stringa non valida o non valida. Informazioni build: versione: "2.35.0", revisione: "c916b9d", ora: "2013-08-12 15:42:01" Informazioni di sistema: os.name: "Mac OS X" , os.arch: 'x86_64', os.version: '10 .9 ', java.version:' 1.6.0_65 'Informazioni driver: driver.version: sconosciuto

Ho anche provato:

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();

Questo mi dà il seguente errore:

ElementNotVisibleError: L'elemento non è attualmente visibile e quindi non può essere interagito con la durata o il timeout del comando: 9 millisecondi Informazioni build: versione: '2.35.0', revisione: 'c916b9d', ora: '2013-08-12 15:42: 01 'Informazioni di sistema: os.name:' Mac OS X ', os.arch:' x86_64 ', os.version: '10 .9', java.version: '1.6.0_65' ID sessione: bdeb8088-d8ad-0f49-aad9 -82201c45c63f Informazioni sui driver: 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, handleAlerts = true, browserConnectionEnabled = true, nativeEvents = false, webStorageEnabled = true, applicationCacheEnabled = false, takesScreenshot = true}]

Qualcuno può aiutarmi con questo problema o fare luce su cosa potrei fare di sbagliato qui.

Risposte:


88

Ho avuto un problema simile e alla fine ho scritto una funzione di supporto che seleziona i valori a discesa.

Alla fine ho deciso che stavo selezionando in base al numero di opzione, e quindi ho scritto un metodo che prende un elemento e il optionNumber e seleziona quell'opzioneNumber. Se optionNumber è nullo, non seleziona nulla (lasciando deselezionato il menu a discesa).

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

Ho scritto un post sul blog se vuoi maggiori dettagli, copre anche la verifica del testo dell'opzione selezionata in un menu a discesa: http://technpol.wordpress.com/2013/12/01/protractor-and-dropdowns-validation/


1
Non ha funzionato per me, ottenuto element.findElements non è una funzione.
— Justin

251

Per me ha funzionato a meraviglia

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

Spero che sia d'aiuto.


2
Nota minore - solo v0.22 (sono appena andato a sostituire il mio codice con questo oggi e ho dovuto eseguire l'aggiornamento per ottenerlo)
— PaulL

C'è un modo per indirizzare gli elementi utilizzando questo? Come avere menu di selezione dello stato duplicati.
— Christopher Marshall

11
Christopher, ElementFinderè incatenabile, quindi puoi fare:element(by.css('.specific-select')).element(by.cssContainingText('option', 'BeaverBox Testing')).click();
— Joel Kornbluh

6
Nota che puoi ottenere corrispondenze parziali, quindi "Piccolo" corrisponderà a "Extra piccolo".
— TrueWill

3
Per aggiungere al commento di TrueWill: Il lato negativo di questa soluzione è che se hai due opzioni simili utilizzerà l'ultima opzione trovata, che ha generato errori basati sulla selezione sbagliata. Quello che ha funzionato per me è stato stackoverflow.com/a/25333326/1945990
— Mike W

29

Un approccio elegante comporterebbe la creazione di un'astrazione simile a ciò che altri legami del linguaggio selenio offrono fuori dagli schemi (ad esempio, una Selectclasse in Python o Java).

Creiamo un comodo wrapper e nascondiamo i dettagli di implementazione all'interno:

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;

Esempio di utilizzo (nota quanto sia leggibile e facile da usare):

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');

Soluzione tratta dal seguente argomento: Seleziona -> opzione astrazione .


Cordiali saluti, ha creato una richiesta di funzionalità: Seleziona -> opzione astrazione .


Perché usi "return" nelle funzioni selezionate? È necessario?
— Michiel

1
@ Michiel buon punto. Potrebbe essere necessario se desideri risolvere esplicitamente la promessa restituita da click(). Grazie.
— alecxe

20
element(by.model('parent_id')).sendKeys('BKN01');

1
È il più corretto per me. Con cssContainText non ti assicuri di catturare il campo desiderato. Pensa se hai 2 selectbox con gli stessi valori. +1
— YoBre

4
Non ho capito, cos'è BKN01?
— Gerfried

1
@ Gerfried BKN01 è il testo che desideri selezionare dal menu a discesa.
— Milan Yadav

@GalBracha Scusa non ti
— ho capito

Se hai un'altra opzione che condivide lo stesso prefex di BKN01, non funzionerà. Ne verrà scelto uno a caso.
— zs2020

15

Per accedere a un'opzione specifica è necessario fornire il selettore nth-child ():

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

Questo non fornisce una risposta alla domanda. Per criticare o richiedere chiarimenti a un autore, lascia un commento sotto il suo post.
— jpw

@jpw è la mia risposta sbagliata. o è semplicemente la formulazione della mia risposta che è sbagliata?
— bekite

La formulazione di una risposta come domanda è perché. Non so se è la risposta corretta. Se lo è, dovresti formularlo come tale.
— jpw

3
@bekite non ha funzionato per me Continuo a ricevere l'errore Elemento Errore non visibile quando ho provato il tuo suggerimento
— Ranjan Bhambroo

8

Ecco come ho fatto la mia selezione.

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

5

Ecco come l'ho fatto:

$('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();

Per attendere che angular termini in attesa di elaborazione, utilizzare il waitForAngular()metodo del goniometro .
— Avi Cherry

5

Prova questo, per me funziona:

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

4

Puoi provare questa speranza che funzioni

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

Un altro modo per impostare un elemento opzione:

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

var orderTest = element (by.model ('ctrl.supplier.orderTest')) orderTest. $ ('[value = "1"]'). click (); ricevo un errore da (selettore CSS, [value = "3"])
— Anuj KC

3

Per selezionare elementi (opzioni) con ID univoci come qui:

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

Sto usando questo:

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

3

Abbiamo scritto una libreria che include 3 modi per selezionare un'opzione:

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>

Una caratteristica aggiuntiva di queste funzioni è che attendono che l'elemento venga visualizzato prima di eseguire qualsiasi azione su select.

Puoi trovarlo su npm @ hetznercloud / protractor-test-helper . Vengono fornite anche le digitazioni per TypeScript.


2

Forse non super elegante, ma efficiente:

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

Questo invia semplicemente la chiave sulla selezione che desideri, nel nostro caso, stiamo usando modelSelector ma ovviamente puoi usare qualsiasi altro selettore.

Quindi nella mia pagina modello di oggetti:

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

E dal test:

myPage.selectMyOption(1);

2

Il problema è che le soluzioni che funzionano su normali caselle di selezione angolare non funzionano con il materiale angolare md-select e md-option utilizzando il goniometro. Questo è stato pubblicato da un altro, ma ha funzionato per me e non sono ancora in grado di commentare il suo post (solo 23 punti rep). Inoltre, l'ho ripulito un po ', invece di browser.sleep, ho usato 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
});

Uso solo questo:element(by.model('selectModel')).click(); element(by.css('md-option[value="searchOptionValue"]')).click();
— Luan Nguyen,

Ecco un altro approccio: mdSelectElement.getAttribute('aria-owns').then( function(val) { let selectMenuContainer = element(by.id(val)); selectMenuContainer.element(by.css('md-option[value="foo"]')).click(); } );
— gbruins

1

C'è un problema con la selezione delle opzioni in Firefox che l'hack di Droogans risolve che voglio menzionare qui esplicitamente, sperando che possa risparmiare qualche problema a qualcuno: https://github.com/angular/protractor/issues/480 .

Anche se i tuoi test vengono superati localmente con Firefox, potresti scoprire che non riescono su CircleCI o TravisCI o qualunque cosa tu stia utilizzando per CI e distribuzione. Essere consapevoli di questo problema fin dall'inizio mi avrebbe risparmiato molto tempo :)


1

Helper per impostare l'elemento an option:

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


1

Seleziona un'opzione per Indice:

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

1

Ho migliorato un po 'la soluzione scritta da PaulL. Prima di tutto ho corretto il codice in modo che fosse compatibile con l'ultima API di Protractor. E poi dichiaro la funzione nella sezione "onPrepare" di un file di configurazione di Protractor come membro dell'istanza del browser , quindi può essere referenziato da qualsiasi specifica 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();
        });
    };
  },

1

Ho cercato una risposta su come selezionare un'opzione in un menu a discesa del modello e ho usato questa combinazione che mi ha aiutato con il materiale angolare.

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

sembra che quando si lancia il codice tutto in una riga potrebbe trovare l'elemento nel menu a discesa.

Ho impiegato molto tempo per questa soluzione, spero che questo aiuti qualcuno.


0

Volevamo utilizzare l'elegante soluzione lassù utilizzando materiale angularjs ma non ha funzionato perché in realtà non ci sono tag option / md-option nel DOM finché non si fa clic su md-select. Quindi il modo "elegante" non ha funzionato per noi (nota il materiale angolare!) Ecco cosa abbiamo fatto invece per esso, non so se è il modo migliore ma sta sicuramente funzionando ora

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

Dovevamo avere 4 selezioni selezionate e mentre la selezione è aperta, c'è una sovrapposizione nel modo in cui selezionare la selezione successiva. ecco perché dobbiamo aspettare 500 ms per assicurarci di non avere problemi con gli effetti materiali ancora in azione.


0

Un altro modo per impostare un elemento opzione:

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
----------
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

È possibile selezionare le opzioni del menu a discesa in base al valore: $('#locregion').$('[value="1"]').click();


0

Ecco come farlo tramite il valore dell'opzione o l'indice . Questo esempio è un po 'rozzo, ma mostra come fare quello che vuoi:

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
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

Possiamo creare una classe DropDown personalizzata per questo e aggiungere un metodo come:

async selectSingleValue(value: string) {
        await this.element.element(by.xpath('.//option[normalize-space(.)=\'' + value + '\']')).click();
    }

Inoltre, per verificare quale valore è attualmente selezionato, possiamo avere:

async getSelectedValues() {
        return await this.element.$('option:checked').getText();
    }

0

L'esempio seguente è il modo più semplice. Ho testato e superato la versione Goniometro5.4.2

//Drop down selection  using option's visibility text 

 element(by.model('currency')).element(by.css("[value='Dollar']")).click();
 Or use this, it   $ isshort form for  .By.css
  element(by.model('currency')).$('[value="Dollar"]').click();

//To select using index

var select = element(by.id('userSelect'));
select.$('[value="1"]').click(); // To select using the index .$ means a shortcut to .By.css

Codice completo

describe('Protractor Demo App', function() {

  it('should have a title', function() {

     browser.driver.get('http://www.way2automation.com/angularjs-protractor/banking/#/');
    expect(browser.getTitle()).toEqual('Protractor practice website - Banking App');
    element(by.buttonText('Bank Manager Login')).click();
    element(by.buttonText('Open Account')).click();

    //Drop down selection  using option's visibility text 
  element(by.model('currency')).element(by.css("[value='Dollar']")).click();

    //This is a short form. $ in short form for  .By.css
    // element(by.model('currency')).$('[value="Dollar"]').click();

    //To select using index
    var select = element(by.id('userSelect'));
    select.$('[value="1"]').click(); // To select using the index .$ means a shortcut to .By.css
    element(by.buttonText("Process")).click();
    browser.sleep(7500);// wait in miliseconds
    browser.switchTo().alert().accept();

  });
});

0

Questa è una semplice risposta di una riga in cui angular ha un localizzatore speciale che può aiutare a selezionare e indicizzare dall'elenco.

element.all(by.options('o.id as o.name for o in organizations')).get(Index).click()

Sebbene questo codice possa risolvere la domanda, inclusa una spiegazione di come e perché questo risolve il problema aiuterebbe davvero a migliorare la qualità del tuo post e probabilmente si tradurrebbe in più voti positivi. Ricorda che stai rispondendo alla domanda per i lettori in futuro, non solo alla persona che chiede ora. Si prega di modificare la risposta per aggiungere spiegazioni e dare un'indicazione di ciò si applicano le limitazioni e le assunzioni. Dalla recensione
— doppio segnale acustico

-1

Seleziona l'opzione per proprietà CSS

element(by.model("organization.parent_id")).element(by.css("[value='1']")).click();

o

element(by.css("#locregion")).element(by.css("[value='1']")).click();

Dove locregion (id), organization.parent_id (nome modello) sono gli attributi dell'elemento select.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.