Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selenium Select Object selectByIndex method examines index attribute instead of counting. Why?

Disclaimer: I'm new to StackOverflow, at least in terms of asking my own questions, so if there's anything wrong or 'bad practice' about this one please give me some pointers.

Recently at work I've had cause to use Selenium and, being new to the tool, there have been a few times when I've wound up scratching my head over why something is done a certain way. Usually the reason becomes apparent later, but not in this case.

Currently I'm writing some browser automation which involves indexing search combinations and noting how many results appear for that combination on various sites related to the company I'm working for.

For most of these sites, the searches will usually be defined via keywords and drop-down menus which I'm handling via Selenium's Select object. Specifically I've been using the selectByIndex method to iterate through the various combinations.

One thing that I noticed was that, using this method, the further down the list of options I got the longer the method took. When I opened up the declaration the code I found was as follows:

  /**
   * Select the option at the given index. This is done by examing the "index" attribute of an
   * element, and not merely by counting.
   * 
   * @param index The option at this index will be selected
   */
  public void selectByIndex(int index) {
    String match = String.valueOf(index);

    boolean matched = false;
    for (WebElement option : getOptions()) {
      if (match.equals(option.getAttribute("index"))) {
        setSelected(option);
        if (!isMultiple()) {
          return;
        }
        matched = true;
      }
    }
    if (!matched) {
      throw new NoSuchElementException("Cannot locate option with index: " + index);
    }
  }

What I'm confused about is why this code is written so that it examines the 'index' attribute. As far as I can tell the getOptions() method returns a list of the options available to the selector based on tag so it should be accurate, and considering that I've been listing the indexed search combinations using the same method and those have been accurate I'm fairly sure it is.

So, right now I've extended the class and overloaded the method to just direct it straight to the corresponding index as I do have a non-trivial number of search combinations to check and any increase in speed is valuable. There don't appear to be any issues cropping up with the overloaded code and everything seems to be accurate so I'm wondering why this method is written in this way? Could anyone enlighten me?

like image 449
Reid Palmquist Avatar asked Nov 10 '22 10:11

Reid Palmquist


1 Answers

Select the option at the given index. This is done by examing the "index" attribute of an element, and not merely by counting.

I believe this is done to overcome the possibility of Nested Options or OPTGROUP in the Select Dropdown tag. Consider the below Select tag:

<SELECT name="ComOS">
  <OPTION selected label="none" value="none">None</OPTION>
  <OPTGROUP label="PortMaster 3">
    <OPTION label="3.7.1" value="pm3_3.7.1">PortMaster 3 with ComOS 3.7.1</OPTION>
    <OPTION label="3.7" value="pm3_3.7">PortMaster 3 with ComOS 3.7</OPTION>
    <OPTION label="3.5" value="pm3_3.5">PortMaster 3 with ComOS 3.5</OPTION>
  </OPTGROUP>
  <OPTGROUP label="PortMaster 2">
    <OPTION label="3.7" value="pm2_3.7">PortMaster 2 with ComOS 3.7</OPTION>
    <OPTION label="3.5" value="pm2_3.5">PortMaster 2 with ComOS 3.5</OPTION>
  </OPTGROUP>
  <OPTGROUP label="IRX">
    <OPTION label="3.7R" value="IRX_3.7R">IRX with ComOS 3.7R</OPTION>
    <OPTION label="3.5R" value="IRX_3.5R">IRX with ComOS 3.5R</OPTION>
  </OPTGROUP>
</SELECT>

In this Select tag, merely counting the index and find the element is not enough as it may return multiple indexes and give error/exceptions.

Moreover, if multiple option tags are found it should be notified also. Hence, 'probably' this may be the reason for examining the "index" attribute before actually returning the element.

In your case, it is better to overload the method and go by indexes as selectByIndex is bound to get slow for huge amount of options tags.

Edit:

Editing after reading the comments. The statement for (WebElement option : getOptions()) is actually slowing the code(Question mostly focus on increasing the speed). So, it really do not matter if the solutions is done by examining the index attribute or other way as that is not the reason for slow speed.

Also, examining the index attribute is helpful for nested options as it indexes the options as the child of Select, and not only as immediate child of Select.

like image 176
Manu Avatar answered Nov 14 '22 21:11

Manu