From 8ba67f74990de5738124771413926187f4549892 Mon Sep 17 00:00:00 2001 From: syber911911 Date: Fri, 23 Aug 2024 02:27:00 +0900 Subject: [PATCH 1/3] [java] feat: Add method to select options containing the provided text --- .../openqa/selenium/support/ui/ISelect.java | 15 +++++ .../openqa/selenium/support/ui/Select.java | 61 +++++++++++++++++++ .../support/ui/SelectElementTest.java | 17 ++++++ .../selenium/support/ui/SelectTest.java | 22 +++++++ 4 files changed, 115 insertions(+) diff --git a/java/src/org/openqa/selenium/support/ui/ISelect.java b/java/src/org/openqa/selenium/support/ui/ISelect.java index 510aa5a571ce1..446ea9534b72e 100644 --- a/java/src/org/openqa/selenium/support/ui/ISelect.java +++ b/java/src/org/openqa/selenium/support/ui/ISelect.java @@ -60,6 +60,21 @@ public interface ISelect { */ void selectByVisibleText(String text); + /** + * Select all options that display text matching or containing the argument. That is, when given "Bar" + * this would select an option like: + * + *

<option value="foo">Bar</option> + * + * Additionally, if no exact match is found, this will attempt to select options that contain the + * argument as a substring. For example, when given "1년", this would select an option like: + * + *

<option value="bar">1년납</option> + * + * @param text The visible text to match or partially match against + */ + void selectByContainsVisibleText(String text); + /** * Select the option at the given index. This is done by examining the "index" attribute of an * element, and not merely by counting. diff --git a/java/src/org/openqa/selenium/support/ui/Select.java b/java/src/org/openqa/selenium/support/ui/Select.java index e79a7d39ce0ee..f942fa7173626 100644 --- a/java/src/org/openqa/selenium/support/ui/Select.java +++ b/java/src/org/openqa/selenium/support/ui/Select.java @@ -154,6 +154,67 @@ public void selectByVisibleText(String text) { } } + /** + * Selects all options that display text matching or containing the provided argument. + * This method first attempts to find an exact match and, if not found, will then attempt + * to find options that contain the specified text as a substring. + * + * For example, when given "Bar", this would select an option like: + * + *

<option value="foo">Bar</option> + * + * And also select an option like: + * + *

<option value="baz">FooBar</option> or <option value="baz">1년납</option> when "1년" is provided. + * + * @param text The visible text to match against. It can be a full or partial match of the option text. + * @throws NoSuchElementException If no matching option elements are found + */ + @Override + public void selectByContainsVisibleText(String text) { + assertSelectIsEnabled(); + + // try to find the option via XPATH ... + List options = + element.findElements( + By.xpath(".//option[normalize-space(.) = " + Quotes.escape(text) + "]")); + + for (WebElement option : options) { + setSelected(option, true); + if (!isMultiple()) { + return; + } + } + + boolean matched = !options.isEmpty(); + if (!matched) { + String searchText = text.contains(" ") ? getLongestSubstringWithoutSpace(text) : text; + + List candidates; + if (searchText.isEmpty()) { + candidates = element.findElements(By.tagName("option")); + } else { + candidates = element.findElements( + By.xpath(".//option[contains(., " + Quotes.escape(searchText) + ")]")); + } + + String trimmed = text.trim(); + for (WebElement option : candidates) { + if (option.getText().contains(trimmed)) { + setSelected(option, true); + if (!isMultiple()) { + return; + } + matched = true; + } + } + } + + if (!matched) { + throw new NoSuchElementException("Cannot locate option with text: " + text); + } + } + private String getLongestSubstringWithoutSpace(String s) { String result = ""; StringTokenizer st = new StringTokenizer(s, " "); diff --git a/java/test/org/openqa/selenium/support/ui/SelectElementTest.java b/java/test/org/openqa/selenium/support/ui/SelectElementTest.java index c01fbdf792cee..e6d2ee9be2531 100644 --- a/java/test/org/openqa/selenium/support/ui/SelectElementTest.java +++ b/java/test/org/openqa/selenium/support/ui/SelectElementTest.java @@ -135,6 +135,23 @@ void shouldAllowOptionsToBeSelectedByVisibleText() { assertThat(firstSelected.getText()).isEqualTo("select_2"); } + @Test + void shouldAllowOptionsToBeSelectedByContainsVisibleText() { + WebElement selectElement = driver.findElement(By.name("select_empty_multiple")); + + Select select = new Select(selectElement); + select.selectByContainsVisibleText("select"); + WebElement firstSelected = select.getFirstSelectedOption(); + int selectedOptionCount = select.getAllSelectedOptions().size(); + + assertThat(firstSelected.getText()).isEqualTo("select_1"); + assertThat(selectedOptionCount).isEqualTo(4); + + select.deselectAll(); + assertThatExceptionOfType(NoSuchElementException.class) + .isThrownBy(() -> select.selectByContainsVisibleText("select_12")); + } + @Test @Ignore(ALL) public void shouldNotAllowInvisibleOptionsToBeSelectedByVisibleText() { diff --git a/java/test/org/openqa/selenium/support/ui/SelectTest.java b/java/test/org/openqa/selenium/support/ui/SelectTest.java index 64588cac5bb3c..74e6536740d47 100644 --- a/java/test/org/openqa/selenium/support/ui/SelectTest.java +++ b/java/test/org/openqa/selenium/support/ui/SelectTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -154,6 +155,24 @@ void shouldAllowOptionsToBeSelectedByVisibleText() { verify(firstOption).click(); } + @Test + void shouldAllowOptionsToBeSelectedByContainsVisibleText() { + String parameterText = "foo"; + + final WebElement firstOption = mockOption("first", false); + + final WebElement element = mockSelectWebElement("multiple"); + when(element.findElements(By.xpath(".//option[contains(., " + Quotes.escape(parameterText) + ")]"))) + .thenReturn(Collections.singletonList(firstOption)); + when(firstOption.getText()).thenReturn("foo bar"); + when(firstOption.isEnabled()).thenReturn(true); + + Select select = new Select(element); + select.selectByContainsVisibleText(parameterText); + + verify(firstOption).click(); + } + @Test void shouldNotAllowDisabledOptionsToBeSelected() { final WebElement firstOption = mockOption("first", false); @@ -302,5 +321,8 @@ void shouldThrowAnExceptionIfThereAreNoElementsToSelect() { assertThatExceptionOfType(NoSuchElementException.class) .isThrownBy(() -> select.selectByVisibleText("also not there")); + + assertThatExceptionOfType(NoSuchElementException.class) + .isThrownBy(() -> select.selectByContainsVisibleText("also not there")); } } From b2f82547e2045d37d0e1e6ed0da6dea543ece201 Mon Sep 17 00:00:00 2001 From: syber911911 Date: Sun, 15 Sep 2024 00:05:22 +0900 Subject: [PATCH 2/3] [java] feat: - Add method to deselect options containing the provided text - Add method for checking element visibility fix: - fix selectByContainsVisibleText method to check element visibility --- common/src/web/formPage.html | 6 ++ .../openqa/selenium/support/ui/ISelect.java | 2 + .../openqa/selenium/support/ui/Select.java | 50 ++++++++++++++- .../support/ui/SelectElementTest.java | 63 +++++++++++++++++++ .../selenium/support/ui/SelectTest.java | 17 +++++ 5 files changed, 135 insertions(+), 3 deletions(-) diff --git a/common/src/web/formPage.html b/common/src/web/formPage.html index 748e61bcc9d8a..70a31da55cae6 100644 --- a/common/src/web/formPage.html +++ b/common/src/web/formPage.html @@ -80,6 +80,12 @@ + +