Cómo seleccionar la opción en las pruebas desplegables de protractorjs e2e

121

Estoy tratando de seleccionar una opción de un menú desplegable para las pruebas angulares e2e usando un transportador.

Aquí está el fragmento de código de la opción de selección:

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

Yo he tratado:

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

Esto me da el siguiente error:

Se especificó una cadena no válida o ilegal Información de compilación: versión: '2.35.0', revisión: 'c916b9d', hora: '2013-08-12 15:42:01' Información del sistema: os.name: 'Mac OS X' , os.arch: 'x86_64', os.version: '10 .9 ', java.version:' 1.6.0_65 'Información del controlador: driver.version: desconocido

También he probado:

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

Esto me da el siguiente error:

ElementNotVisibleError: El elemento no está visible actualmente y, por lo tanto, no se puede interactuar con la duración o el tiempo de espera del comando: 9 milisegundos Información de compilación: versión: '2.35.0', revisión: 'c916b9d', hora: '2013-08-12 15:42: 01 'Información del sistema: os.name:' Mac OS X ', os.arch:' x86_64 ', os.version: '10 .9', java.version: '1.6.0_65' ID de sesión: bdeb8088-d8ad-0f49-aad9 -82201c45c63f Información del controlador: org.openqa.selenium.firefox.FirefoxDriver Capabilities [{plataforma = MAC, acceptSslCerts = true, javascriptEnabled = true, browserName = firefox, rotatable = false, locationContextEnabled = true, version = 24.0, cssSelectorsEnabled = true = true, handleAlerts = true, browserConnectionEnabled = true, nativeEvents = false, webStorageEnabled = true, applicationCacheEnabled = false, takesScreenshot = true}]

¿Alguien puede ayudarme con este problema o arrojar algo de luz sobre lo que podría estar haciendo mal aquí?

Ranjan Bhambroo
fuente

Respuestas:

88

Tuve un problema similar y, finalmente, escribí una función auxiliar que selecciona valores desplegables.

Finalmente decidí que estaba bien seleccionando por número de opción y, por lo tanto, escribí un método que toma un elemento y el optionNumber, y selecciona ese optionNumber. Si optionNumber es nulo, no selecciona nada (dejando el menú desplegable sin seleccionar).

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

Escribí una publicación de blog si desea más detalles, también cubre la verificación del texto de la opción seleccionada en un menú desplegable: http://technpol.wordpress.com/2013/12/01/protractor-and-dropdowns-validation/

PaulL
fuente
1
No funcionó para mí, get element.findElements no es una función.
Justin
251

Para mi funciono como un encanto

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

Espero eso ayude.

Fatz
fuente
2
Nota menor: solo v0.22 (acabo de reemplazar mi código con esto hoy y tuve que actualizarlo para obtenerlo)
PaulL
¿Hay alguna forma de orientar elementos utilizando esto? Como tener menús de selección de estado duplicados.
Christopher Marshall
11
Christopher, ElementFinderes capaz de encadenar, por lo que puede hacer:element(by.css('.specific-select')).element(by.cssContainingText('option', 'BeaverBox Testing')).click();
Joel Kornbluh
6
Tenga en cuenta que puede obtener coincidencias parciales, por lo que 'Pequeño' coincidirá con 'Extra pequeño'.
TrueWill
3
Para agregar al comentario de TrueWill: El lado negativo de esta solución es que si tiene dos opciones similares, usará la última opción encontrada, que arrojó errores basados ​​en la selección incorrecta. Lo que funcionó para mí fue stackoverflow.com/a/25333326/1945990
Mike W
29

Un enfoque elegante implicaría hacer una abstracción similar a lo que ofrecen otros enlaces de lenguaje de selenio listos para usar (por ejemplo, Selectclases en Python o Java).

Hagamos un contenedor conveniente y ocultemos los detalles de implementación dentro:

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;

Ejemplo de uso (tenga en cuenta lo legible y fácil de usar que es):

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

Solución tomada del siguiente tema: Seleccione -> abstracción de opciones .


Para su información, creó una solicitud de función: Seleccione -> abstracción de opciones .

Alecxe
fuente
¿Por qué utiliza 'retorno' en las funciones seleccionadas? ¿Es eso necesario?
Michiel
1
@Michiel buen punto. Puede ser necesario si desea resolver explícitamente la promesa devuelta por click(). Gracias.
alecxe
20
element(by.model('parent_id')).sendKeys('BKN01');
Sandesh Danwale
fuente
1
Es el más correcto para mí. Con cssContainingText no te aseguras de capturar el campo deseado. Solo piense si tiene 2 selectbox con los mismos valores. +1
YoBre
4
Lo siento, ¿qué es BKN01?
Gerfried
1
@Gerfried BKN01 es el texto que desea seleccionar del menú desplegable.
MilanYadav
@GalBracha Lo siento no te entendí
MilanYadav
Si tiene otra opción que comparte el mismo prefijo que BKN01, no funcionará. Se recogerá uno al azar.
zs2020
15

Para acceder a una opción específica, debe proporcionar el selector nth-child ():

ptor.findElement(protractor.By.css('select option:nth-child(1)')).click();
bekite
fuente
Esto no proporciona una respuesta a la pregunta. Para criticar o solicitar una aclaración de un autor, deje un comentario debajo de su publicación.
jpw
@jpw es mi respuesta incorrecta. ¿O es simplemente la formulación de mi respuesta lo que está mal?
bekite
La formulación de una respuesta como pregunta es por qué. No sé si es la respuesta correcta. Si es así, debe formularlo como tal.
jpw
3
@bekite No funcionó para mí. Aún aparece el error Error de elemento no visible cuando probé tu sugerencia
Ranjan Bhambroo
8

Así es como hice mi selección.

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

Así es como lo hice:

$('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();
Droogans
fuente
Para esperar a que angular termine el procesamiento pendiente, use el waitForAngular()método del transportador .
Avi Cherry
5

Prueba esto, me está funcionando:

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

Puedes probar esto espero que funcione

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
});
Zahid Afaque
fuente
4

Otra forma de configurar un elemento de opción:

var select = element(by.model('organization.parent_id'));
select.$('[value="1"]').click();
surya narayana raju g
fuente
var orderTest = element (by.model ('ctrl.supplier.orderTest')) orderTest. $ ('[valor = "1"]'). click (); Recibo un error de (selector de CSS, [valor = "3"])
Anuj KC
3

Para seleccionar elementos (opciones) con identificadores únicos como aquí:

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

Estoy usando esto:

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

Escribimos una biblioteca que incluye 3 formas de seleccionar una opción:

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 característica adicional de estas funciones es que esperan a que se muestre el elemento antes de realizar cualquier acción en el select.

Puede encontrarlo en npm @ hetznercloud / protractor-test-helper . También se proporcionan tipificaciones para TypeScript.

crashbus
fuente
2

Quizás no súper elegante, pero eficiente:

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

Esto solo envía la tecla hacia abajo en la selección que desea, en nuestro caso, estamos usando modelSelector pero obviamente puede usar cualquier otro selector.

Luego, en mi modelo de objeto de página:

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

Y de la prueba:

myPage.selectMyOption(1);
Calahad
fuente
2

El problema es que las soluciones que funcionan en cuadros de selección angulares regulares no funcionan con Angular Material md-select y md-option usando transportador. Este fue publicado por otro, pero funcionó para mí y todavía no puedo comentar su publicación (solo 23 puntos de repetición). Además, lo limpié un poco, en lugar de browser.sleep, usé 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
});
Peterhendrick
fuente
Solo uso esto:element(by.model('selectModel')).click(); element(by.css('md-option[value="searchOptionValue"]')).click();
Luan Nguyen
Aquí hay otro enfoque: mdSelectElement.getAttribute('aria-owns').then( function(val) { let selectMenuContainer = element(by.id(val)); selectMenuContainer.element(by.css('md-option[value="foo"]')).click(); } );
gbruins
1

Hay un problema con la selección de opciones en Firefox que el truco de Droogans corrige que quiero mencionar aquí explícitamente, con la esperanza de que pueda ahorrarle algunos problemas a alguien: https://github.com/angular/protractor/issues/480 .

Incluso si sus pruebas pasan localmente con Firefox, es posible que estén fallando en CircleCI o TravisCI o lo que sea que esté usando para CI e implementación. Ser consciente de este problema desde el principio me habría ahorrado mucho tiempo :)

Julia Jacobs
fuente
1

Ayudante para configurar el elemento de una opción:

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

Si a continuación se muestra el menú desplegable

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

Entonces el código de protractorjs puede ser-

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

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

Ajay Patil
fuente
1

Seleccione la opción por índice:

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

He mejorado un poco la solución escrita por PaulL. En primer lugar, arreglé el código para que fuera compatible con la última API de transportador. Y luego declaro la función en la sección 'onPrepare' de un archivo de configuración de Protractor como miembro de la instancia del navegador , por lo que se puede hacer referencia a ella desde cualquier especificación 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();
        });
    };
  },
Trunikov
fuente
1

He estado buscando en la red una respuesta sobre cómo seleccionar una opción en el menú desplegable de un modelo y he usado esta combinación que me ha ayudado con el material angular.

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

parece que al lanzar el código todo en una línea podría encontrar el elemento en el menú desplegable.

Tomó mucho tiempo para esta solución, espero que esto ayude a alguien.

tony2tones
fuente
0

Queríamos usar la elegante solución de allí usando material de angularjs, pero no funcionó porque en realidad no hay etiquetas option / md-option en el DOM hasta que se haya hecho clic en md-select. Así que la forma "elegante" no funcionó para nosotros (¡tenga en cuenta el material angular!). Esto es lo que hicimos, no sé si es la mejor manera, pero definitivamente funciona ahora.

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

Necesitábamos tener 4 selecciones seleccionadas y mientras la selección está abierta, hay una superposición en la forma de seleccionar la siguiente selección. es por eso que tenemos que esperar 500ms para asegurarnos de que no nos metemos en problemas con los efectos materiales que aún están en acción.

pascalwhoop
fuente
0

Otra forma de configurar un elemento de opción:

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


});
Pramod Dutta
fuente
0

Puede seleccionar opciones desplegables por valor: $('#locregion').$('[value="1"]').click();

Sander Lepik
fuente
0

A continuación, se explica cómo hacerlo por valor de opción o índice . Este ejemplo es un poco burdo, pero muestra cómo hacer lo que quiere:

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
KVarmark
fuente
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();
                   }
               }            
        }

    })

}
Javed Ali
fuente
0

Podemos crear una clase DropDown personalizada para esto y agregar un método como:

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

Además, para verificar qué valor está seleccionado actualmente, podemos tener:

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

El siguiente ejemplo es la forma más sencilla. He probado y aprobado en la versión de transportador5.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

Código 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();

  });
});
Sameera De Silva
fuente
0

Esta es una respuesta simple de una línea en la que angular tiene un localizador especial que puede ayudar a seleccionar e indexar de la lista.

element.all(by.options('o.id as o.name for o in organizations')).get(Index).click()
Vaibhav Dixit
fuente
Si bien este código puede resolver la pregunta, incluir una explicación de cómo y por qué esto resuelve el problema realmente ayudaría a mejorar la calidad de su publicación y probablemente resultaría en más votos a favor. Recuerde que está respondiendo la pregunta a los lectores en el futuro, no solo a la persona que pregunta ahora. Por favor, editar su respuesta para agregar explicaciones y dar una indicación de lo que se aplican limitaciones y supuestos. De la opinión
doble pitido
-1

Seleccione la opción por propiedad CSS

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

o

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

Donde locregion (id), organization.parent_id (nombre del modelo) son los atributos del elemento seleccionado.

Kanhaiya Kumar
fuente