You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ComboBoxElement.java 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.testbench.elements;
  17. import java.util.ArrayList;
  18. import java.util.Collections;
  19. import java.util.List;
  20. import org.openqa.selenium.JavascriptExecutor;
  21. import org.openqa.selenium.Keys;
  22. import org.openqa.selenium.WebDriverException;
  23. import org.openqa.selenium.WebElement;
  24. import com.vaadin.testbench.By;
  25. import com.vaadin.testbench.elementsbase.ServerClass;
  26. @ServerClass("com.vaadin.ui.ComboBox")
  27. public class ComboBoxElement extends AbstractSelectElement {
  28. private static org.openqa.selenium.By bySuggestionPopup = By
  29. .vaadin("#popup");
  30. private static org.openqa.selenium.By byNextPage = By
  31. .className("v-filterselect-nextpage");
  32. private static org.openqa.selenium.By byPrevPage = By
  33. .className("v-filterselect-prevpage");
  34. /**
  35. * Selects the first option in the ComboBox which matches the given text.
  36. *
  37. * @param text
  38. * the text of the option to select
  39. */
  40. public void selectByText(String text) {
  41. if (isReadOnly()) {
  42. throw new ReadOnlyException();
  43. }
  44. if (!isTextInputAllowed()) {
  45. selectByTextFromPopup(text);
  46. return;
  47. }
  48. getInputField().clear();
  49. sendInputFieldKeys(text);
  50. selectSuggestion(text);
  51. }
  52. /**
  53. * Selects, without filtering, the first option in the ComboBox which
  54. * matches the given text.
  55. *
  56. * @param text
  57. * the text of the option to select
  58. */
  59. private void selectByTextFromPopup(String text) {
  60. // This method assumes there is no need to touch the filter string
  61. // 1. Find first page
  62. // 2. Select first matching text if found
  63. // 3. Iterate towards end
  64. while (openPrevPage()) {
  65. // Scroll until beginning
  66. }
  67. do {
  68. if (selectSuggestion(text)) {
  69. return;
  70. }
  71. } while (openNextPage());
  72. }
  73. private boolean selectSuggestion(String text) {
  74. for (WebElement suggestion : getPopupSuggestionElements()) {
  75. if (text.equals(suggestion.getText())) {
  76. suggestion.click();
  77. return true;
  78. }
  79. }
  80. return false;
  81. }
  82. private boolean isReadOnly(WebElement elem) {
  83. JavascriptExecutor js = (JavascriptExecutor) getDriver();
  84. return (Boolean) js.executeScript("return arguments[0].readOnly", elem);
  85. }
  86. /**
  87. * Checks if text input is allowed for the combo box.
  88. *
  89. * @return <code>true</code> if text input is allowed, <code>false</code>
  90. * otherwise
  91. */
  92. public boolean isTextInputAllowed() {
  93. return !isReadOnly(getInputField());
  94. }
  95. /*
  96. * Workaround selenium's bug: sendKeys() will not send left parentheses
  97. * properly. See #14048.
  98. */
  99. private void sendInputFieldKeys(String text) {
  100. WebElement textBox = getInputField();
  101. if (!text.contains("(")) {
  102. textBox.sendKeys(text);
  103. return;
  104. }
  105. String OPEN_PARENTHESES = "_OPEN_PARENT#H#ESES_";
  106. String tamperedText = text.replaceAll("\\(", OPEN_PARENTHESES);
  107. textBox.sendKeys(tamperedText);
  108. JavascriptExecutor js = getCommandExecutor();
  109. String jsScript = String.format(
  110. "arguments[0].value = arguments[0].value.replace(/%s/g, '(')",
  111. OPEN_PARENTHESES);
  112. js.executeScript(jsScript, textBox);
  113. // refresh suggestions popupBox
  114. textBox.sendKeys("a" + Keys.BACK_SPACE);
  115. }
  116. /**
  117. * Open the suggestion popup
  118. */
  119. public void openPopup() {
  120. findElement(By.vaadin("#button")).click();
  121. }
  122. /**
  123. * Gets the text representation of all suggestions on the current page
  124. *
  125. * @return List of suggestion texts
  126. */
  127. public List<String> getPopupSuggestions() {
  128. List<String> suggestionsTexts = new ArrayList<String>();
  129. List<WebElement> suggestions = getPopupSuggestionElements();
  130. for (WebElement suggestion : suggestions) {
  131. String text = suggestion.getText();
  132. if (!text.isEmpty()) {
  133. suggestionsTexts.add(text);
  134. }
  135. }
  136. return suggestionsTexts;
  137. }
  138. /**
  139. * Gets the elements of all suggestions on the current page.
  140. * <p>
  141. * Opens the popup if not already open.
  142. *
  143. * @return a list of elements for the suggestions on the current page
  144. */
  145. public List<WebElement> getPopupSuggestionElements() {
  146. List<WebElement> tables = getSuggestionPopup()
  147. .findElements(By.tagName("table"));
  148. if (tables == null || tables.isEmpty()) {
  149. return Collections.emptyList();
  150. }
  151. WebElement table = tables.get(0);
  152. return table.findElements(By.tagName("td"));
  153. }
  154. /**
  155. * Opens next popup page.
  156. *
  157. * @return True if next page opened. false if doesn't have next page
  158. */
  159. public boolean openNextPage() {
  160. try {
  161. getSuggestionPopup().findElement(byNextPage).click();
  162. return true;
  163. } catch (WebDriverException e) {
  164. // PhantomJS driver can throw WDE instead of the more specific
  165. // NoSuchElementException
  166. return false;
  167. }
  168. }
  169. /**
  170. * Open previous popup page.
  171. *
  172. * @return True if previous page opened. False if doesn't have previous page
  173. */
  174. public boolean openPrevPage() {
  175. try {
  176. getSuggestionPopup().findElement(byPrevPage).click();
  177. return true;
  178. } catch (WebDriverException e) {
  179. // PhantomJS driver can throw WDE instead of the more specific
  180. // NoSuchElementException
  181. return false;
  182. }
  183. }
  184. /**
  185. * Returns the suggestion popup element
  186. */
  187. public WebElement getSuggestionPopup() {
  188. ensurePopupOpen();
  189. return findElement(bySuggestionPopup);
  190. }
  191. /**
  192. * Return value of the combo box element
  193. *
  194. * @return value of the combo box element
  195. */
  196. public String getValue() {
  197. return getInputField().getAttribute("value");
  198. }
  199. /**
  200. * Returns the text input field element, used for entering text into the
  201. * combo box.
  202. *
  203. * @return the input field element
  204. */
  205. public WebElement getInputField() {
  206. return findElement(By.vaadin("#textbox"));
  207. }
  208. private void ensurePopupOpen() {
  209. if (!isElementPresent(bySuggestionPopup)) {
  210. openPopup();
  211. }
  212. }
  213. @Override
  214. public String getText() {
  215. return getInputField().getAttribute("value");
  216. }
  217. @Override
  218. public void clear() {
  219. getInputField().clear();
  220. }
  221. @Override
  222. public void sendKeys(CharSequence... keysToSend) {
  223. sendKeys(50, keysToSend);
  224. }
  225. /**
  226. * Use this method to simulate typing into an element, which may set its
  227. * value.
  228. *
  229. * @param delay
  230. * delay after sending each individual key (mainly needed for
  231. * PhantomJS)
  232. * @param keysToSend
  233. * keys to type into the element
  234. */
  235. public void sendKeys(int delay, CharSequence... keysToSend) {
  236. WebElement input = getInputField();
  237. for (CharSequence key : keysToSend) {
  238. input.sendKeys(key);
  239. try {
  240. Thread.sleep(delay);
  241. } catch (InterruptedException e) {
  242. }
  243. }
  244. }
  245. }