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.