Jak wybrać opcję w rozwijanych testach kątomierza e2e


121

Próbuję wybrać opcję z listy rozwijanej dla testów kątowych e2e przy użyciu kątomierza.

Oto fragment kodu opcji wyboru:

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

Próbowałem:

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

To daje mi następujący błąd:

Podano nieprawidłowy lub niedozwolony ciąg Informacje o kompilacji: wersja: „2.35.0”, wersja: „c916b9d”, godzina: „2013-08-12 15:42:01” Informacje o systemie: nazwa.os .: „Mac OS X” , os.arch: 'x86_64', os.version: '10 .9 ', java.version:' 1.6.0_65 'Informacje o sterowniku: driver.version: nieznany

Próbowałem też:

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

To daje mi następujący błąd:

ElementNotVisibleError: Element nie jest obecnie widoczny i nie można na niego wchodzić z czasem trwania lub limitem czasu polecenia: 9 milisekund Informacje o kompilacji: wersja: „2.35.0”, wersja: „c916b9d”, godzina: „12.08.2013 15:42: 01 'Informacje o systemie: os.name:' Mac OS X ', os.arch:' x86_64 ', os.version: '10 .9', java.version: '1.6.0_65' Identyfikator sesji: bdeb8088-d8ad-0f49-aad9 -82201c45c63f Informacje o sterowniku: org.openqa.selenium.firefox.FirefoxDriver Możliwości [{platforma = MAC, acceptSslCerts = true, javascriptEnabled = true, browserName = firefox, rotatable = false, locationContextEnabled = true, version = 24.0, cssSelCerts = true, javascriptEnabled = true, browserName = firefox, rotatable = false, locationContextEnabled = true, version = 24.0, cssSelectors, databaseEnabled = true, handlesAlerts = true, browserConnectionEnabled = true, nativeEvents = false, webStorageEnabled = true, applicationCacheEnabled = false, takesScreenshot = true}]

Czy ktoś może mi pomóc z tym problemem lub rzucić trochę światła na to, co tutaj robię źle.

Odpowiedzi:


88

Miałem podobny problem i ostatecznie napisałem funkcję pomocniczą, która wybiera rozwijane wartości.

Ostatecznie zdecydowałem, że mogę wybrać numer opcji, dlatego napisałem metodę, która przyjmuje element i opcję optionNumber, i wybiera tę opcję optionNumber. Jeśli optionNumber ma wartość null, to nic nie wybiera (pozostawiając niezaznaczone menu).

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

Napisałem wpis na blogu, jeśli chcesz więcej szczegółów, obejmuje również weryfikację tekstu wybranej opcji w menu rozwijanym: http://technpol.wordpress.com/2013/12/01/protractor-and-dropdowns-validation/


1
U mnie nie zadziałało, dostałem element.findElements nie jest funkcją.
Justin

251

U mnie zadziałało jak urok

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

Mam nadzieję, że to pomoże.


2
Drobna uwaga - tylko v0.22 (właśnie poszedłem dzisiaj zastąpić mój kod tym i musiałem go zaktualizować, aby go zdobyć)
PaulL

Czy jest sposób na kierowanie elementów za pomocą tego? Na przykład posiadanie zduplikowanych menu wyboru stanu.
Christopher Marshall,

11
Christophera, ElementFindermożna łączyć łańcuchami, więc możesz to zrobić:element(by.css('.specific-select')).element(by.cssContainingText('option', 'BeaverBox Testing')).click();
Joel Kornbluh

6
Pamiętaj, że możesz uzyskać częściowe dopasowania, więc „Mały” będzie pasował do „Bardzo małego”.
TrueWill

3
Aby dodać do komentarza TrueWill: Wadą tego rozwiązania jest to, że jeśli masz dwie podobne opcje, użyje ostatniej znalezionej opcji - która spowodowała błędy wynikające z niewłaściwego wyboru. To, co mi zadziałało, to stackoverflow.com/a/25333326/1945990
Mike W

29

Eleganckie podejście polegałoby na stworzeniu abstrakcji podobnej do tego, co inne wiązania języka selenowego oferują po wyjęciu z pudełka (np.Select Klasa w Pythonie lub Javie).

Zróbmy wygodny wrapper i ukryjmy w nim szczegóły implementacji:

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;

Przykład użycia (zwróć uwagę, jak jest czytelny i łatwy w użyciu):

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

Rozwiązanie zaczerpnięte z tematu: Wybierz -> abstrakcja opcji .


FYI, utworzyłem żądanie funkcji: Wybierz -> abstrakcja opcji .


Dlaczego w wybranych funkcjach używasz zwrotu? Czy to konieczne?
Michiel

1
@Michiel dobra uwaga. Może być konieczne, jeśli chcesz wyraźnie wywiązać się z obietnicy zwróconej przez click(). Dzięki.
alecxe

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

1
To jest dla mnie najbardziej poprawne. Z cssContainingText nie upewniasz się, że przechwycisz żądane pole. Pomyśl tylko, jeśli masz 2 pola wyboru z tymi samymi wartościami. +1
YoBre

4
Przepraszam, co to jest BKN01?
Gerfried

1
@Gerfried BKN01 to tekst, który chcesz wybrać z listy rozwijanej.
MilanYadav

@GalBracha Niestety, nie udało mi się
MilanYadav

Jeśli masz inną opcję, która ma ten sam prefiks co BKN01, to nie zadziała. Wybrany zostanie losowy.
zs2020

15

Aby uzyskać dostęp do określonej opcji, musisz podać selektor nth-child ():

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

To nie daje odpowiedzi na pytanie. Aby skrytykować lub poprosić autora o wyjaśnienie, zostaw komentarz pod jego postem.
jpw

@jpw to moja odpowiedź zła. czy też jest to po prostu błędne sformułowanie mojej odpowiedzi?
bekite,

Sformułowanie odpowiedzi jako pytania to dlaczego. Nie wiem, czy to poprawna odpowiedź. Jeśli tak, powinieneś to tak sformułować.
jpw

3
@bekite Nie działa dla mnie, nadal pojawia się błąd Element Niewidoczny błąd, kiedy wypróbowałem twoją sugestię
Ranjan Bhambroo

8

W ten sposób dokonałem wyboru.

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

5

Oto jak to zrobiłem:

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

Aby poczekać na zakończenie przetwarzania przez Angular, użyj waitForAngular()metody kątomierza .
Avi Cherry

5

Spróbuj tego, to działa dla mnie:

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

4

Możesz spróbować tej nadziei, że zadziała

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

Inny sposób ustawienia elementu opcji:

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

var orderTest = element (by.model ('ctrl.supplier.orderTest')) orderTest. $ ('[value = "1"]'). click (); otrzymuję błąd przez (selektor css, [wartość = "3"])
Anuj KC

3

Aby wybrać elementy (opcje) z unikalnymi identyfikatorami, jak tutaj:

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

Używam tego:

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

3

Napisaliśmy bibliotekę, która zawiera 3 sposoby wyboru opcji:

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>

Dodatkową cechą tych funkcji jest to, że czekają na wyświetlenie elementu przed wykonaniem jakiejkolwiek akcji na elemencie select.

Możesz go znaleźć na npm @ hetznercloud / protractor-test-helper . Dostępne są również czcionki TypeScript.


2

Może nie super eleganckie, ale wydajne:

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

To po prostu wysyła klucz w dół do wybranego selektora, w naszym przypadku używamy modelSelector, ale oczywiście możesz użyć dowolnego innego selektora.

Następnie w moim modelu obiektów strony:

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

A z testu:

myPage.selectMyOption(1);

2

Problem polega na tym, że rozwiązania, które działają na zwykłych kątowych polach wyboru, nie działają z materiałami kątowymi md-select i md-option używającymi kątomierza. Ten został opublikowany przez innego, ale zadziałał i nie mogę jeszcze skomentować jego postu (tylko 23 punkty rep). Ponadto trochę go wyczyściłem, zamiast browser.sleep, użyłem 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
});

Po prostu używam tego:element(by.model('selectModel')).click(); element(by.css('md-option[value="searchOptionValue"]')).click();
Luan Nguyen

Oto inne podejście: mdSelectElement.getAttribute('aria-owns').then( function(val) { let selectMenuContainer = element(by.id(val)); selectMenuContainer.element(by.css('md-option[value="foo"]')).click(); } );
gbruins

1

Występuje problem z wyborem opcji w Firefoksie, który naprawia hack Droogansa, o którym chcę tutaj wyraźnie wspomnieć, mając nadzieję, że może to zaoszczędzić komuś kłopotów: https://github.com/angular/protractor/issues/480 .

Nawet jeśli twoje testy przechodzą lokalnie w Firefoksie, może się okazać, że zawodzą w CircleCI lub TravisCI lub czymkolwiek innym, czego używasz do CI i wdrażania. Świadomość tego problemu od samego początku zaoszczędziłaby mi dużo czasu :)


1

Pomocnik do ustawienia elementu opcji:

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


1

Wybierz opcję według indeksu:

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

1

Poprawiłem nieco rozwiązanie napisane przez PaulLa. Przede wszystkim poprawiłem kod tak, aby był kompatybilny z ostatnim API Protractor. Następnie deklaruję funkcję w sekcji „onPrepare” pliku konfiguracyjnego Protractor jako element członkowski instancji przeglądarki , dzięki czemu można się do niej odwoływać z dowolnej specyfikacji 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

Szukałem w sieci odpowiedzi na pytanie, jak wybrać opcję z menu modelu i użyłem tej kombinacji, która pomogła mi z materiałem Angular.

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

wygląda na to, że rzucając kod w jednym wierszu, mógł znaleźć element na liście rozwijanej.

To rozwiązanie zajęło dużo czasu. Mam nadzieję, że komuś to pomoże.


0

Chcieliśmy użyć eleganckiego rozwiązania używającego materiału angularjs, ale nie zadziałało, ponieważ tak naprawdę nie ma tagów option / md-option w DOM, dopóki nie klikniesz md-select. Więc „elegancki” sposób nie zadziałał dla nas (zwróć uwagę na kanciasty materiał!) Oto, co dla niego zrobiliśmy, nie wiem, czy to najlepszy sposób, ale zdecydowanie działa teraz

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

Musieliśmy mieć zaznaczone 4 zaznaczenia, a gdy wybór jest otwarty, istnieje nakładka na drodze wyboru następnego wyboru. dlatego musimy poczekać 500 ms, aby upewnić się, że nie będziemy mieć problemów z efektami materialnymi, które nadal działają.


0

Inny sposób ustawienia elementu opcji:

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

Możesz wybrać opcje rozwijane według wartości: $('#locregion').$('[value="1"]').click();


0

Oto jak to zrobić za pomocą wartości opcji lub indeksu . Ten przykład jest nieco prymitywny, ale pokazuje, jak robić, co chcesz:

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

Możemy w tym celu stworzyć niestandardową klasę DropDown i dodać metodę jako:

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

Ponadto, aby zweryfikować, jaka wartość jest aktualnie wybrana, możemy mieć:

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

0

Poniższy przykład jest najłatwiejszy. Przetestowałem i zdałem w wersji Protractor5.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

Pełny kod

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

Jest to prosta odpowiedź w jednym wierszu, w której angular ma specjalny lokalizator, który może pomóc w wyborze i indeksowaniu z listy.

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

Chociaż ten kod może rozwiązać problem, w tym wyjaśnienie, jak i dlaczego to rozwiązuje problem, naprawdę pomogłoby poprawić jakość twojego posta i prawdopodobnie zaowocowałoby większą liczbą pozytywnych głosów. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a nie tylko osoba, która zapyta teraz. Proszę edytować swoje odpowiedzi, aby dodać wyjaśnień i dać wskazówkę co zastosować ograniczenia i założenia. Z recenzji
double-beep

-1

Wybierz opcję według właściwości CSS

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

lub

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

Gdzie locregion (id), organization.parent_id (nazwa modelu) to atrybuty wybranego elementu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.