skip to content

In Selenium, what do Select's getOptions and getAllSelectedOptions return, and what does each call cost?

level: seniorimportance: should knowfreq 44%

answer

  1. Every read starts from the same find
  2. The list is a snapshot, not live
  3. One round trip per option's selectedness
  4. Nothing selected is a throw, not null

basics

~20 s

getOptions runs a fresh search for the select's option elements and returns a snapshot list, not a live collection. getAllSelectedOptions filters that list by asking each option whether it is selected, so it costs one find plus one command per option.

solid answer

~40 s

`getOptions()` is a search for `option` descendants of the wrapped `<select>`, re-executed on every call and returned as an ordinary list of element references — a snapshot, so options the page adds later are not in a list you already hold. It includes options nested in `<optgroup>` groups, in document order. `getAllSelectedOptions()` builds on it by asking each option whether it is selected, and each of those is its own remote command: on a 200-entry zone list one call is one find plus 200 reads. `getFirstSelectedOption()` walks the same sequence and stops at the first hit, but throws `NoSuchElementException("No options are selected")` rather than returning null when nothing is chosen.

code

java · 23 lines
java
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.Select;

public class PermitZoneReader {
  public static void main(String[] args) {
    WebDriver driver = new ChromeDriver();
    try {
      driver.get("https://permits.example.gov/renew");
      Select zones = new Select(driver.findElement(By.id("permit-zone")));

      List<WebElement> options = zones.getOptions();
      System.out.println(options.size());
      System.out.println(options.get(0).getText());
      System.out.println(zones.getFirstSelectedOption().getDomAttribute("value"));
    } finally {
      driver.quit();
    }
  }
}

go deeper

for a junior

Recall which method answers which question: all the options, the selected ones, or the first selected one. Remember that the last of those raises rather than returning null when nothing is chosen.

for a middle

Explain that getOptions is a fresh find returning a snapshot list and that getAllSelectedOptions asks each option separately, so the cost grows with the number of options rather than staying constant.

for a senior

Show you can spot the round-trip cost in real code: a loop that re-finds the options or re-reads attributes per option turns one command into hundreds, and that is a measurable share of a slow suite.

for a principal

Own the guidance for the wider suite about how much a screen-driven check may read back from the browser, and where the team accepts the cost of exhaustive list verification.

## The three read methods | Method | Returns | When nothing is selected | |---|---|---| | `getOptions()` | every `<option>` under the wrapped select | the full list, unchanged | | `getAllSelectedOptions()` | the subset whose selectedness is true | an empty list | | `getFirstSelectedOption()` | the first option whose selectedness is true | throws `NoSuchElementException` | All three start from the same place: `getOptions()` is exactly a search for `option` descendants of the wrapped `<select>`, and the other two are built on top of it. ## getOptions is a fresh find on every call `getOptions()` issues **one remote find command each time you call it** and returns an ordinary `java.util.List` of element references. Two properties follow: - The list is a **snapshot**, not a live collection. Options the page adds afterwards do not appear in a list you already hold; you have to call `getOptions()` again. - The search covers descendants, so options nested inside `<optgroup>` groups are included, in document order. The order matches the `index` property that `selectByIndex` compares against. On a parking-permit renewal form whose zone dropdown is filled from a lookup service, that means a list captured before the lookup finishes stays short forever, no matter how many zones eventually render. ## What getAllSelectedOptions costs `getAllSelectedOptions()` filters `getOptions()` by asking each option whether it is selected, and **each of those questions is its own remote command**. For a 200-entry zone list a single call is: 1. one find command, returning 200 element references; 2. 200 separate selectedness reads, one per option; 3. a filtered list assembled on the client from the 200 answers. `getFirstSelectedOption()` walks the same sequence but stops at the first option that answers yes, so it is much cheaper when the chosen zone is near the top of the list and no cheaper at all when it is the last entry. Neither method is a single round trip, and neither is cached: calling `getAllSelectedOptions()` twice does all of that work twice. ## Keeping the round trips down - Call `getOptions()` once and reuse the returned list rather than calling it again inside a loop over its own result — that is the shape that turns one find into hundreds. - On a single-selection permit-type dropdown, prefer `getFirstSelectedOption()`: it stops at the first hit, while `getAllSelectedOptions()` reads every option before it can return. - Read what you need from an option you already hold rather than re-finding it: `getText()` for the label the applicant sees, `getDomAttribute("value")` for the code the form posts. - If you only need the number of choices offered, `getOptions().size()` is a single find; there is no cheaper count. - Remember that the wrapper caches nothing between calls. Two consecutive `getAllSelectedOptions()` calls do the whole find-and-read sequence twice, so hold the result if you need it more than once in the same step. ## When getFirstSelectedOption throws It throws `NoSuchElementException` with the message "No options are selected" — it does **not** return null, so a null check will never fire and a `NullPointerException` is not the failure you should expect. - On a single-selection dropdown the throw is rare, because a browser keeps one option of an ordinary `<select>` selected; if it happens, look at whether you are really on the control you think you are. - On a `<select multiple>` it is the ordinary way to observe "the applicant has chosen nothing yet", and code that reads a multi-selection vehicle-class list has to expect it. - `getAllSelectedOptions()` is the non-throwing counterpart for that case: it returns an empty list and lets you decide what an empty selection means. ## What the returned elements are The list holds element references bound to the option nodes that existed when the find ran. They are ordinary `WebElement` handles, so everything you can ask an element you can ask an option — its text, its attributes, whether it is enabled. What they are not is a snapshot of the option's **data**: every property you read from one of them is another round trip to the browser, which is why a loop that reads three attributes from each of 200 options costs 600 commands and takes noticeably longer than the single find that produced the list. The distinction that catches people is between the list and the elements in it. The list itself is fixed at the moment of the find and will never grow. The elements in it are live handles onto the page, so what they report can change between two reads if the renewal form updates the zone list underneath you.

  • Why is getFirstSelectedOption usually cheaper than getAllSelectedOptions?
    Both start with the same find, but `getAllSelectedOptions()` asks every option whether it is selected before it can return a complete list, while `getFirstSelectedOption()` stops at the first option that answers yes. On a single-selection dropdown whose choice sits near the top that is a handful of commands instead of hundreds. If the chosen option is last, the two cost the same.
  • Does a list from getOptions update when the page adds more options?
    No. The call issues one find and returns a plain list of element references captured at that moment; it is not a live collection. If a zone lookup adds entries afterwards, they appear only when you call `getOptions()` again. The corollary is that a list captured before an asynchronous load finishes stays short no matter how long you hold it.

saying these in an interview costs you the question

  • Believes getOptions returns a live collection that updates itself
  • Assumes getAllSelectedOptions is a single remote command
  • Expects getFirstSelectedOption to return null when nothing is selected
  • Thinks getOptions skips options nested inside optgroup elements
  • Calls getOptions again inside a loop over its own result