Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 43 additions & 62 deletions java/client/src/org/openqa/selenium/support/ui/Select.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.stream.Collectors;

/**
* Models a SELECT tag, providing helper methods to select and deselect options.
Expand Down Expand Up @@ -59,45 +59,36 @@ public Select(WebElement element) {
* @return Whether this select element support selecting multiple options at the same time? This
* is done by checking the value of the "multiple" attribute.
*/
@Override
public boolean isMultiple() {
return isMulti;
}

/**
* @return All options belonging to this select tag
*/
@Override
public List<WebElement> getOptions() {
return element.findElements(By.tagName("option"));
}

/**
* @return All selected options belonging to this select tag
*/
@Override
public List<WebElement> getAllSelectedOptions() {
List<WebElement> toReturn = new ArrayList<>();

for (WebElement option : getOptions()) {
if (option.isSelected()) {
toReturn.add(option);
}
}

return toReturn;
return getOptions().stream().filter(WebElement::isSelected).collect(Collectors.toList());
}

/**
* @return The first selected option in this select tag (or the currently selected option in a
* normal select)
* @throws NoSuchElementException If no option is selected
*/
@Override
public WebElement getFirstSelectedOption() {
for (WebElement option : getOptions()) {
if (option.isSelected()) {
return option;
}
}

throw new NoSuchElementException("No options are selected");
return getOptions().stream().filter(WebElement::isSelected).findFirst()
.orElseThrow(() -> new NoSuchElementException("No options are selected"));
}

/**
Expand All @@ -115,16 +106,15 @@ public void selectByVisibleText(String text) {
List<WebElement> options =
element.findElements(By.xpath(".//option[normalize-space(.) = " + Quotes.escape(text) + "]"));

boolean matched = false;
for (WebElement option : options) {
setSelected(option, true);
if (!isMultiple()) {
return;
}
matched = true;
}

if (options.isEmpty() && text.contains(" ")) {
boolean matched = !options.isEmpty();
if (!matched && text.contains(" ")) {
String subStringWithoutSpace = getLongestSubstringWithoutSpace(text);
List<WebElement> candidates;
if ("".equals(subStringWithoutSpace)) {
Expand Down Expand Up @@ -171,16 +161,9 @@ private String getLongestSubstringWithoutSpace(String s) {
* @param index The option at this index will be selected
* @throws NoSuchElementException If no matching option elements are found
*/
@Override
public void selectByIndex(int index) {
String match = String.valueOf(index);

for (WebElement option : getOptions()) {
if (match.equals(option.getAttribute("index"))) {
setSelected(option, true);
return;
}
}
throw new NoSuchElementException("Cannot locate option with index: " + index);
setSelectedByIndex(index, true);
}

/**
Expand All @@ -192,21 +175,13 @@ public void selectByIndex(int index) {
* @param value The value to match against
* @throws NoSuchElementException If no matching option elements are found
*/
@Override
public void selectByValue(String value) {
List<WebElement> options = element.findElements(By.xpath(
".//option[@value = " + Quotes.escape(value) + "]"));

boolean matched = false;
for (WebElement option : options) {
for (WebElement option : findOptionsByValue(value)) {
setSelected(option, true);
if (!isMultiple()) {
return;
}
matched = true;
}

if (!matched) {
throw new NoSuchElementException("Cannot locate option with value: " + value);
}
}

Expand All @@ -215,6 +190,7 @@ public void selectByValue(String value) {
*
* @throws UnsupportedOperationException If the SELECT does not support multiple selections
*/
@Override
public void deselectAll() {
if (!isMultiple()) {
throw new UnsupportedOperationException(
Expand All @@ -236,21 +212,15 @@ public void deselectAll() {
* @throws NoSuchElementException If no matching option elements are found
* @throws UnsupportedOperationException If the SELECT does not support multiple selections
*/
@Override
public void deselectByValue(String value) {
if (!isMultiple()) {
throw new UnsupportedOperationException(
"You may only deselect options of a multi-select");
}

List<WebElement> options = element.findElements(By.xpath(
".//option[@value = " + Quotes.escape(value) + "]"));
boolean matched = false;
for (WebElement option : options) {
for (WebElement option : findOptionsByValue(value)) {
setSelected(option, false);
matched = true;
}
if (!matched) {
throw new NoSuchElementException("Cannot locate option with value: " + value);
}
}

Expand All @@ -262,21 +232,14 @@ public void deselectByValue(String value) {
* @throws NoSuchElementException If no matching option elements are found
* @throws UnsupportedOperationException If the SELECT does not support multiple selections
*/
@Override
public void deselectByIndex(int index) {
if (!isMultiple()) {
throw new UnsupportedOperationException(
"You may only deselect options of a multi-select");
}

String match = String.valueOf(index);

for (WebElement option : getOptions()) {
if (match.equals(option.getAttribute("index"))) {
setSelected(option, false);
return;
}
}
throw new NoSuchElementException("Cannot locate option with index: " + index);
setSelectedByIndex(index, false);
}

/**
Expand All @@ -289,6 +252,7 @@ public void deselectByIndex(int index) {
* @throws NoSuchElementException If no matching option elements are found
* @throws UnsupportedOperationException If the SELECT does not support multiple selections
*/
@Override
public void deselectByVisibleText(String text) {
if (!isMultiple()) {
throw new UnsupportedOperationException(
Expand All @@ -297,16 +261,34 @@ public void deselectByVisibleText(String text) {

List<WebElement> options = element.findElements(By.xpath(
".//option[normalize-space(.) = " + Quotes.escape(text) + "]"));
if (options.isEmpty()) {
throw new NoSuchElementException("Cannot locate element with text: " + text);
}

boolean matched = false;
for (WebElement option : options) {
setSelected(option, false);
matched = true;
}
}

if (!matched) {
throw new NoSuchElementException("Cannot locate element with text: " + text);
private List<WebElement> findOptionsByValue(String value) {
List<WebElement> options = element.findElements(By.xpath(
".//option[@value = " + Quotes.escape(value) + "]"));
if (options.isEmpty()) {
throw new NoSuchElementException("Cannot locate option with value: " + value);
}
return options;
}

private void setSelectedByIndex(int index, boolean select) {
String match = String.valueOf(index);

for (WebElement option : getOptions()) {
if (match.equals(option.getAttribute("index"))) {
setSelected(option, select);
return;
}
}
throw new NoSuchElementException("Cannot locate option with index: " + index);
}

/**
Expand All @@ -319,8 +301,7 @@ public void deselectByVisibleText(String text) {
* deselected (false)
*/
private void setSelected(WebElement option, boolean select) {
boolean isSelected=option.isSelected();
if ((!isSelected && select) || (isSelected && !select)) {
if (option.isSelected() != select) {
option.click();
}
}
Expand Down