WebDriverSelect.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <?php
  2. // Copyright 2004-present Facebook. All Rights Reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of 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,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. namespace Facebook\WebDriver;
  16. use Facebook\WebDriver\Exception\NoSuchElementException;
  17. use Facebook\WebDriver\Exception\UnexpectedTagNameException;
  18. use Facebook\WebDriver\Exception\UnsupportedOperationException;
  19. use Facebook\WebDriver\Support\XPathEscaper;
  20. /**
  21. * Models a default HTML <select> tag, providing helper methods to select and deselect options.
  22. */
  23. class WebDriverSelect implements WebDriverSelectInterface
  24. {
  25. /** @var WebDriverElement */
  26. private $element;
  27. /** @var bool */
  28. private $isMulti;
  29. public function __construct(WebDriverElement $element)
  30. {
  31. $tag_name = $element->getTagName();
  32. if ($tag_name !== 'select') {
  33. throw new UnexpectedTagNameException('select', $tag_name);
  34. }
  35. $this->element = $element;
  36. $value = $element->getAttribute('multiple');
  37. $this->isMulti = ($value === 'true');
  38. }
  39. public function isMultiple()
  40. {
  41. return $this->isMulti;
  42. }
  43. public function getOptions()
  44. {
  45. return $this->element->findElements(WebDriverBy::tagName('option'));
  46. }
  47. public function getAllSelectedOptions()
  48. {
  49. $selected_options = [];
  50. foreach ($this->getOptions() as $option) {
  51. if ($option->isSelected()) {
  52. $selected_options[] = $option;
  53. if (!$this->isMultiple()) {
  54. return $selected_options;
  55. }
  56. }
  57. }
  58. return $selected_options;
  59. }
  60. public function getFirstSelectedOption()
  61. {
  62. foreach ($this->getOptions() as $option) {
  63. if ($option->isSelected()) {
  64. return $option;
  65. }
  66. }
  67. throw new NoSuchElementException('No options are selected');
  68. }
  69. public function selectByIndex($index)
  70. {
  71. foreach ($this->getOptions() as $option) {
  72. if ($option->getAttribute('index') === (string) $index) {
  73. $this->selectOption($option);
  74. return;
  75. }
  76. }
  77. throw new NoSuchElementException(sprintf('Cannot locate option with index: %d', $index));
  78. }
  79. public function selectByValue($value)
  80. {
  81. $matched = false;
  82. $xpath = './/option[@value = ' . XPathEscaper::escapeQuotes($value) . ']';
  83. $options = $this->element->findElements(WebDriverBy::xpath($xpath));
  84. foreach ($options as $option) {
  85. $this->selectOption($option);
  86. if (!$this->isMultiple()) {
  87. return;
  88. }
  89. $matched = true;
  90. }
  91. if (!$matched) {
  92. throw new NoSuchElementException(
  93. sprintf('Cannot locate option with value: %s', $value)
  94. );
  95. }
  96. }
  97. public function selectByVisibleText($text)
  98. {
  99. $matched = false;
  100. $xpath = './/option[normalize-space(.) = ' . XPathEscaper::escapeQuotes($text) . ']';
  101. $options = $this->element->findElements(WebDriverBy::xpath($xpath));
  102. foreach ($options as $option) {
  103. $this->selectOption($option);
  104. if (!$this->isMultiple()) {
  105. return;
  106. }
  107. $matched = true;
  108. }
  109. // Since the mechanism of getting the text in xpath is not the same as
  110. // webdriver, use the expensive getText() to check if nothing is matched.
  111. if (!$matched) {
  112. foreach ($this->getOptions() as $option) {
  113. if ($option->getText() === $text) {
  114. $this->selectOption($option);
  115. if (!$this->isMultiple()) {
  116. return;
  117. }
  118. $matched = true;
  119. }
  120. }
  121. }
  122. if (!$matched) {
  123. throw new NoSuchElementException(
  124. sprintf('Cannot locate option with text: %s', $text)
  125. );
  126. }
  127. }
  128. public function selectByVisiblePartialText($text)
  129. {
  130. $matched = false;
  131. $xpath = './/option[contains(normalize-space(.), ' . XPathEscaper::escapeQuotes($text) . ')]';
  132. $options = $this->element->findElements(WebDriverBy::xpath($xpath));
  133. foreach ($options as $option) {
  134. $this->selectOption($option);
  135. if (!$this->isMultiple()) {
  136. return;
  137. }
  138. $matched = true;
  139. }
  140. if (!$matched) {
  141. throw new NoSuchElementException(
  142. sprintf('Cannot locate option with text: %s', $text)
  143. );
  144. }
  145. }
  146. public function deselectAll()
  147. {
  148. if (!$this->isMultiple()) {
  149. throw new UnsupportedOperationException('You may only deselect all options of a multi-select');
  150. }
  151. foreach ($this->getOptions() as $option) {
  152. $this->deselectOption($option);
  153. }
  154. }
  155. public function deselectByIndex($index)
  156. {
  157. if (!$this->isMultiple()) {
  158. throw new UnsupportedOperationException('You may only deselect options of a multi-select');
  159. }
  160. foreach ($this->getOptions() as $option) {
  161. if ($option->getAttribute('index') === (string) $index) {
  162. $this->deselectOption($option);
  163. return;
  164. }
  165. }
  166. }
  167. public function deselectByValue($value)
  168. {
  169. if (!$this->isMultiple()) {
  170. throw new UnsupportedOperationException('You may only deselect options of a multi-select');
  171. }
  172. $xpath = './/option[@value = ' . XPathEscaper::escapeQuotes($value) . ']';
  173. $options = $this->element->findElements(WebDriverBy::xpath($xpath));
  174. foreach ($options as $option) {
  175. $this->deselectOption($option);
  176. }
  177. }
  178. public function deselectByVisibleText($text)
  179. {
  180. if (!$this->isMultiple()) {
  181. throw new UnsupportedOperationException('You may only deselect options of a multi-select');
  182. }
  183. $xpath = './/option[normalize-space(.) = ' . XPathEscaper::escapeQuotes($text) . ']';
  184. $options = $this->element->findElements(WebDriverBy::xpath($xpath));
  185. foreach ($options as $option) {
  186. $this->deselectOption($option);
  187. }
  188. }
  189. public function deselectByVisiblePartialText($text)
  190. {
  191. if (!$this->isMultiple()) {
  192. throw new UnsupportedOperationException('You may only deselect options of a multi-select');
  193. }
  194. $xpath = './/option[contains(normalize-space(.), ' . XPathEscaper::escapeQuotes($text) . ')]';
  195. $options = $this->element->findElements(WebDriverBy::xpath($xpath));
  196. foreach ($options as $option) {
  197. $this->deselectOption($option);
  198. }
  199. }
  200. /**
  201. * Mark option selected
  202. * @param WebDriverElement $option
  203. */
  204. protected function selectOption(WebDriverElement $option)
  205. {
  206. if (!$option->isSelected()) {
  207. $option->click();
  208. }
  209. }
  210. /**
  211. * Mark option not selected
  212. * @param WebDriverElement $option
  213. */
  214. protected function deselectOption(WebDriverElement $option)
  215. {
  216. if ($option->isSelected()) {
  217. $option->click();
  218. }
  219. }
  220. }