Choosing an option in a dropdown menu during ProtractorJS end-to-end testing

I need to automate the selection of an option from a dropdown menu for angular end-to-end tests using protractor.

Below is the code snippet for the select option:

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

I attempted the following:

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

However, this resulted in the error message:

An invalid or illegal string was specified Build info: version: '2.35.0', revision: 'c916b9d', time: '2013-08-12 15:42:01' System info: os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.9', java.version: '1.6.0_65' Driver info: driver.version: unknown

I also tried this method:

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

However, it resulted in the following error:

ElementNotVisibleError: Element is not currently visible and so may not be interacted with Command duration or timeout: 9 milliseconds Build info: version: '2.35.0', revision: 'c916b9d', time: '2013-08-12 15:42:01' System info: os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.9', java.version: '1.6.0_65' Session ID: bdeb8088-d8ad-0f49-aad9-82201c45c63f Driver info: 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=false, webStorageEnabled=true, applicationCacheEnabled=false, takesScreenshot=true}]

Would appreciate any assistance in resolving this issue or insights into what might be going wrong.

Answer №1

It worked perfectly for me

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

Answer №2

Dealing with a similar issue prompted me to create a helpful function for choosing dropdown values.

After some consideration, I concluded that selecting by option number suited my needs. Thus, I developed a method that accepts an element and the option number, allowing for the selection of that specific option number. If the option number is null, nothing is selected (leaving the dropdown unselected).

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

For further insights and information on verifying the text of the selected option in a dropdown, I shared a blog post here:

Answer №3

A sophisticated method could be to create an abstraction layer similar to what is provided by other selenium language bindings by default (for example, the Select class in Python or Java).

Let's develop a convenient wrapper to encapsulate implementation details:

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

module.exports = CustomSelect;

Here's an example of how to use it (notice how user-friendly and easy to understand it is):

var CustomSelect  = require('custom-select');
var myCustomSelect = new CustomSelect(by.id('location'));

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

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

This solution was inspired by the discussion in this thread: Select -> option abstraction.


Just so you know, I have submitted a feature request here: Select -> option abstraction.

Answer №4

Enter 'BKN01' in the 'parent_id' model using Protractor:

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

Answer №5

If you want to target a particular option, you can use the nth-child() selector:

driver.findElement(By.cssSelector('select option:nth-child(1)')).click();

Answer №6

The process I used to make my choice was as follows:

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

Answer №7

This is the method I used:

$('select').click();
$('select option=["' + optionInputFromFunction + '"]').click();
// Although it may seem unnecessary, the delay created by these lines 
// ensures that the Angular change event is properly registered.
browser.actions().mouseDown().mouseUp().perform();

Answer №8

This code snippet has proven to be effective for my use case:

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

Answer №9

Give this a shot, it could do the trick

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

Answer №10

Here is an alternative method for specifying an option element:

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

Answer №11

When choosing specific items (options) with distinct identifiers like those in this example:

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

I achieve this by:

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

Answer №12

We have developed a library that offers 3 different methods for selecting an 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>

One of the key features of these functions is that they ensure the element is displayed before performing any action on the select.

You can access this library on npm at @hetznercloud/protractor-test-helper. Typings for TypeScript are also available.

Answer №13

While it may not be the most elegant solution, this method is quite efficient:

function pickChoice(selector, position) {
    for (var i=0; i<position; i++){
        element(by.model(selector)).sendKeys("\uE015");
    }
}

By using the pickChoice function, you can easily navigate through options in a select element using the provided selector. Feel free to substitute 'selector' with any other appropriate identifier.

When implementing this in a page object model:

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

Finally, when testing the functionality:

myPage.selectMyOption(1);

Answer №14

Encountering issues with regular Angular select boxes when using Angular Material md-select and md-option with Protractor? Fear not, as I have found a solution that worked for me. Unfortunately, due to low rep points, I am unable to comment on the original post where this solution was shared. To improve upon the original code, I replaced browser.sleep with browser.waitForAngular() for a more efficient execution.

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

Answer №15

One of the challenges faced when selecting options in Firefox is addressed by a helpful solution known as Droogans's hack. I feel it's important to highlight this fix here to potentially assist others encountering the same issue: https://github.com/angular/protractor/issues/480.

It's worth noting that even if your tests are running smoothly on your local Firefox browser, they may start failing on CI/CD platforms like CircleCI or TravisCI. Recognizing this issue early on could have saved me a significant amount of time and effort!

Answer №16

Assisting in setting the value of an option element:

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

Answer №17

If you see the dropdown options provided below-

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

You can use the following Protractor code-

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

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

Answer №18

Choose an option based on its index:

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

Answer №19

I have made some enhancements to the solution provided by PaulL. Firstly, I have updated the code to be compatible with the latest Protractor API. Additionally, I have defined the function within the 'onPrepare' section of a Protractor configuration file as part of the browser instance, allowing it to be accessed from any end-to-end test specification.

onPrepare: function() {
    browser._selectDropdownbyNum = function (element, optionNum) {
      /* This helper function selects an option in a dropdown control based on the specified number. */
      return element.all(by.tagName('option')).then(
        function(options) {
          options[optionNum].click();
        });
    };
},

Answer №20

This example demonstrates the simplest approach. It has been tested and successfully executed in Protractor Version 5.4.2

//Selecting an option from a drop-down based on visibility text

 element(by.model('currency')).element(by.css("[value='Dollar']")).click();
 Alternatively, you can use the following syntax, where '$' is shorthand for '.By.css'
  element(by.model('currency')).$('[value="Dollar"]').click();

//Selecting an option by index

var select = element(by.id('userSelect'));
select.$('[value="1"]').click(); // Using the index for selection. Here, '$' is a shortcut for '.By.css'

Complete code snippet

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

    //Selecting an option from a drop-down based on visibility text
  element(by.model('currency')).element(by.css("[value='Dollar']")).click();

    //Using shorthand notation. Here, '$' is shorthand for '.By.css'
    // element(by.model('currency')).$('[value="Dollar"]').click();

    //Selecting an option by index
    var select = element(by.id('userSelect'));
    select.$('[value="1"]').click(); // Using the index for selection. Here, '$' is a shortcut for '.By.css'
    element(by.buttonText("Process")).click();
    browser.sleep(7500);// wait in miliseconds
    browser.switchTo().alert().accept();

  });
});

Answer №21

After extensive searching online, I finally found a solution for selecting an option in a model dropdown using Angular material. The combination of code below proved to be the key:

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

Surprisingly, placing all the code on one line made it easier to locate the element in the dropdown.

It took a significant amount of time to discover this solution, so I hope it can assist others facing the same issue.

Answer №22

If none of the above solutions worked for you, give this a try

Async/await is supported as well

If you need to select options based on text

let textOption = "option2"
await element(by.whichever('YOUR_DROPDOWN_SELECTOR'))
  .getWebElement()
  .findElement(by.xpath(`.//option[text()="${textOption}"]`))
  .click();

Alternatively, you can select options by number

let optionNumber = 2
await element(by.whichever('YOUR_DROPDOWN_SELECTOR'))
  .getWebElement()
  .findElement(by.xpath(`.//option[${optionNumber}]`))
  .click();

You may need to adjust the xpath of child options as needed

For some reason, this is the only method that worked for automating my dropdowns when all hope seemed lost


Update

There was one situation where even this method didn't work. The workaround was a bit messy but effective - I had to select the value twice

Answer №23

We initially tried to implement a sleek solution using angularjs material, but encountered a roadblock. The issue stemmed from the fact that the DOM did not contain any option or md-option tags until the md-select was clicked. This made the "elegant" approach ineffective for us (note angular material!). In response, we devised an alternative method that, while not necessarily the optimal choice, successfully resolved the issue.

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

Our objective was to have 4 selects chosen simultaneously. However, a challenge arose when an overlay obstructed the selection of subsequent selects while one was open. Consequently, we implemented a delay of 500ms to ensure that we did not encounter issues with material effects still in progress.

Answer №24

Here is an alternate method for selecting an option element:

function chooseOption(optionName) {
    var selection = element(by.id('locregion'));
    selection.click();
    selection.all(by.tagName('option')).filter(function(element, index) {
        return element.getText().then(function(text) {
            return text === optionName;
        });
    }).then(function(filteredOptions){
        filteredOptions[0].click();
    });
}

// Example of how to use the function
chooseOption('BeaverBox Testing');

Answer №25

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

  items[3].click();     // clicking the fourth item
  expect(items[0].getText()).toEqual('Ranjans Mobile Testing')
});

Answer №26

To choose dropdown options based on value, use the following code:

$('#locregion').$('[value="1"]').click();

Answer №27

To achieve this, you can select an option based on its value or index. While this example may seem basic, it effectively demonstrates how to accomplish your goal:

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

Answer №28

function chooseDropdownItem(dropdownElement, dropdownListElement, itemToSelect) {
    let selectedItem = '';
    WebLibraryUtils.getElement('xpath', dropdownElement).click();
    WebLibraryUtils.getElements('xpath', dropdownListElement).then(function(items) {
        if(items.length > 0) {
            items.forEach(function(item) {
                if(item === itemToSelect) {
                    console.log(item);
                    item.click();
                    selectedItem = item;
                }
            });
        }
    });
}

Answer №29

To cater to our specific requirements, a personalized DropDown class can be crafted with the following method:

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

For confirmation on the currently selected value, we can implement:

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

Answer №30

Here is a straightforward answer explaining how Angular provides a special locator to select and index elements from a list.

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to ensure CSS affects icon inside main element?

Struggling to match the background color of Material-UI icons with the rest of the list items on hover. The CSS is not applying to both the icon and text despite styling the overall class (className= "dd-content-item"). Any assistance would be greatly appr ...

What is the process for displaying the save file dialog in Safari?

I'm struggling with generating a PDF and saving it as a file in Safari using an Angular app and DocRaptor. I've tried various methods from Stack Overflow, but none seem to trigger the save file dialog. Instead, they either open the file in the cu ...

Text being enveloped in a span tag

Currently, I have a table displaying a list of users with their corresponding roles. However, the roles column is sometimes wrapping before reaching the end of the line. The user list data looks like this: $scope.userList = [{ "id": 1, "name":"AB ...

Scrolling and hovering now triggers the fixed button to toggle class seamlessly

Currently, I am attempting to modify the class of a button on my website. The initial state of the button is wide, but as the user scrolls, it should shrink in size. When hovering over the shrunken button, it should expand back to its original width. Alt ...

Unable to access Form element in Firefox browser

I'm struggling with debugging unfamiliar problems. For instance, in my HTML there's a form: <form name="myForm" > <table> <tr> <td> <input type="radio" name="myType" value="val" onclick="someF ...

Steps to enable overflow: 'scroll' for components generated dynamically

When developing a React application, I encounter an issue with creating new components dynamically inside a container. The problem arises when the height of the container gets exceeded by the newly added items, and I aim to make the container scrollable in ...

Issue with October CMS: Radio button selection triggers an Ajax call, but clicking twice in quick succession causes the content

I am currently utilizing October CMS and materializecss to develop a form with options on one of my pages. The form functions correctly as it dynamically loads content when different options are clicked. However, I have identified a problem where clicking ...

Node.js is known for its unreliable promise returns

Currently, I have a function in place that establishes a connection with a sql database. After querying the database and formatting the results into an HTML table, the function returns the variable html: function getData() { return new Promise((resolv ...

The controller is referencing $rootScope which has not been properly defined

Here is my understanding of the controller concept. Whenever I launch the application, an error message appears saying "$rootScope is not defined." Can someone provide assistance in identifying the issue? var webadmin = angular.module('PcPortal' ...

Exploring the Functionality of Cookies in Nuxt 3 API Endpoints and Middlewares

Can cookies be utilized on the server side in Nuxt 3? For instance, I need to set a cookie in an API and then access its data in middleware: // ~/server/api/testApi.ts export default defineEventHandler(event => { /* setCookie('myCookie', ...

Using ReactJS to send formData to an Express API and retrieving a JSON response

Attempting to have the ReactJS frontend send a username and password from a form to my express API via a proxy, with the intention of having the API return a JSON file containing a user id. While the proxy connection is working as expected, the issue arise ...

When the Angular script is executed, the variable is not defined

One of my custom directives receives an object named 'vm' in its scope, which contains a property/value pair (ccirCategoryIncidentI : 3) that I need to access. When I try to log this value with console.log(scope.vm.ccirCategoryIncidentI), it init ...

The React page fails to load on Ubuntu, yet it works perfectly on the local WSL

It's puzzling. The code that performs flawlessly on my personal computer, smoothly running without any hiccups, fails to operate as expected on an ubuntu server. Upon executing npm start, my local environment exclaims "Compiled successfully!" while t ...

"Upon refreshing the browser, an Angular map loses its positioning and appears blank

I have implemented a LeafLet map in my Laravel 9 system, which is functioning properly with some exceptions. Here's how it looks like: https://i.stack.imgur.com/kcuVr.jpg The code in the controller (CompetitionsMapController.php) is as follows: ...

Creating Vue methods functions in separate JavaScript files

Hi there, I'm new to this so please forgive me if my question seems silly. I have a vue component called vuu /path_to_main/vue_file/app.js const vuu = new Vue({ el: '#vuu', data: { latitude: 'longi', long ...

Modifying HTML content through JSP file

I'm facing a challenge with implementing a specific functionality. My goal is to display the contents of a svn repository in a TreeView. I have a Java Class that connects to the repository and stores the contents in my Java DataModel. In my .jsp file ...

Automatically bypassing git conflicts in package.json: A step-by-step guide

We encounter frequent updates to shared npm packages in our app, resulting in multiple pull requests updating the same package version. Consequently, conflicts arise on GitHub when these pulls are merged into the master branch. Is there a way to automati ...

Tips for sorting items in Wordpress with JavaScript / on click?

I am currently utilizing a method similar to the one outlined in this resource from w3 schools for filtering elements within divs. However, I am facing challenges when attempting to integrate this script into my Aurora Wordpress site due to the removal of ...

Radio Buttons for Nested Question Toggling

My current setup involves using radio buttons and JavaScript/jQuery to handle nested questions. Based on the radio button clicked (Yes to show, No to hide), extra information is displayed or hidden. Here is an example of the HTML code: <div class="form ...

Accessing Form Data as an Array in a Single Page Application

I'm currently in the process of developing a single-page PHP application and I'm experimenting with submitting the form using ajax .post() instead of the traditional form submission that redirects to another page. However, I'm experiencing d ...