watir 1.4.1 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (422) hide show
  1. checksums.yaml +7 -0
  2. data/.document +4 -0
  3. data/.github/ISSUE_TEMPLATE.md +16 -0
  4. data/.github/workflows/chrome.yml +55 -0
  5. data/.github/workflows/edge.yml +44 -0
  6. data/.github/workflows/firefox.yml +55 -0
  7. data/.github/workflows/ie.yml +30 -0
  8. data/.github/workflows/safari.yml +38 -0
  9. data/.github/workflows/unit.yml +60 -0
  10. data/.gitignore +21 -0
  11. data/.rubocop.yml +114 -0
  12. data/.rubocop_todo.yml +17 -0
  13. data/CHANGES.md +2212 -0
  14. data/Gemfile +15 -0
  15. data/LICENSE +24 -0
  16. data/README.md +113 -0
  17. data/Rakefile +173 -0
  18. data/lib/watir/adjacent.rb +128 -0
  19. data/lib/watir/after_hooks.rb +135 -0
  20. data/lib/watir/alert.rb +113 -0
  21. data/lib/watir/aliases.rb +8 -0
  22. data/lib/watir/attribute_helper.rb +97 -0
  23. data/lib/watir/browser.rb +323 -0
  24. data/lib/watir/capabilities.rb +179 -0
  25. data/lib/watir/cell_container.rb +25 -0
  26. data/lib/watir/container.rb +33 -0
  27. data/lib/watir/cookies.rb +130 -0
  28. data/lib/watir/element_collection.rb +223 -0
  29. data/lib/watir/elements/button.rb +28 -0
  30. data/lib/watir/elements/cell.rb +18 -0
  31. data/lib/watir/elements/checkbox.rb +56 -0
  32. data/lib/watir/elements/date_field.rb +42 -0
  33. data/lib/watir/elements/date_time_field.rb +42 -0
  34. data/lib/watir/elements/dlist.rb +12 -0
  35. data/lib/watir/elements/element.rb +807 -0
  36. data/lib/watir/elements/file_field.rb +43 -0
  37. data/lib/watir/elements/font.rb +26 -0
  38. data/lib/watir/elements/form.rb +16 -0
  39. data/lib/watir/elements/hidden.rb +26 -0
  40. data/lib/watir/elements/html_elements.rb +1981 -0
  41. data/lib/watir/elements/iframe.rb +156 -0
  42. data/lib/watir/elements/image.rb +22 -0
  43. data/lib/watir/elements/input.rb +15 -0
  44. data/lib/watir/elements/link.rb +8 -0
  45. data/lib/watir/elements/list.rb +51 -0
  46. data/lib/watir/elements/option.rb +60 -0
  47. data/lib/watir/elements/radio.rb +65 -0
  48. data/lib/watir/elements/row.rb +18 -0
  49. data/lib/watir/elements/select.rb +214 -0
  50. data/lib/watir/elements/svg_elements.rb +497 -0
  51. data/lib/watir/elements/table.rb +77 -0
  52. data/lib/watir/elements/table_cell.rb +32 -0
  53. data/lib/watir/elements/table_row.rb +34 -0
  54. data/lib/watir/elements/table_section.rb +17 -0
  55. data/lib/watir/elements/text_area.rb +7 -0
  56. data/lib/watir/elements/text_field.rb +39 -0
  57. data/lib/watir/exception.rb +16 -0
  58. data/lib/watir/extensions/nokogiri.rb +14 -0
  59. data/lib/watir/generator/base/generator.rb +114 -0
  60. data/lib/watir/generator/base/idl_sorter.rb +51 -0
  61. data/lib/watir/generator/base/spec_extractor.rb +158 -0
  62. data/lib/watir/generator/base/util.rb +21 -0
  63. data/lib/watir/generator/base/visitor.rb +133 -0
  64. data/lib/watir/generator/base.rb +12 -0
  65. data/lib/watir/generator/html/generator.rb +36 -0
  66. data/lib/watir/generator/html/spec_extractor.rb +52 -0
  67. data/lib/watir/generator/html/visitor.rb +23 -0
  68. data/lib/watir/generator/html.rb +17 -0
  69. data/lib/watir/generator/svg/generator.rb +38 -0
  70. data/lib/watir/generator/svg/spec_extractor.rb +55 -0
  71. data/lib/watir/generator/svg/visitor.rb +23 -0
  72. data/lib/watir/generator/svg.rb +9 -0
  73. data/lib/watir/generator.rb +5 -0
  74. data/lib/watir/has_window.rb +72 -0
  75. data/lib/watir/http_client.rb +11 -0
  76. data/lib/watir/js_execution.rb +165 -0
  77. data/lib/watir/js_snippets/attributeValues.js +11 -0
  78. data/lib/watir/js_snippets/backgroundColor.js +7 -0
  79. data/lib/watir/js_snippets/elementObscured.js +14 -0
  80. data/lib/watir/js_snippets/fireEvent.js +31 -0
  81. data/lib/watir/js_snippets/focus.js +3 -0
  82. data/lib/watir/js_snippets/getElementTags.js +3 -0
  83. data/lib/watir/js_snippets/getInnerHtml.js +19 -0
  84. data/lib/watir/js_snippets/getInnerText.js +19 -0
  85. data/lib/watir/js_snippets/getOuterHtml.js +20 -0
  86. data/lib/watir/js_snippets/getTextContent.js +19 -0
  87. data/lib/watir/js_snippets/isElementInViewport.js +20 -0
  88. data/lib/watir/js_snippets/isImageLoaded.js +3 -0
  89. data/lib/watir/js_snippets/selectOptionsLabel.js +10 -0
  90. data/lib/watir/js_snippets/selectOptionsText.js +10 -0
  91. data/lib/watir/js_snippets/selectOptionsValue.js +10 -0
  92. data/lib/watir/js_snippets/selectText.js +64 -0
  93. data/lib/watir/js_snippets/selectedOptions.js +11 -0
  94. data/lib/watir/js_snippets/selectedText.js +17 -0
  95. data/lib/watir/js_snippets/setText.js +3 -0
  96. data/lib/watir/js_snippets/setValue.js +3 -0
  97. data/lib/watir/js_snippets.rb +18 -0
  98. data/lib/watir/locators/anchor/selector_builder.rb +43 -0
  99. data/lib/watir/locators/button/matcher.rb +19 -0
  100. data/lib/watir/locators/button/selector_builder/xpath.rb +69 -0
  101. data/lib/watir/locators/button/selector_builder.rb +10 -0
  102. data/lib/watir/locators/cell/selector_builder/xpath.rb +23 -0
  103. data/lib/watir/locators/cell/selector_builder.rb +13 -0
  104. data/lib/watir/locators/element/locator.rb +81 -0
  105. data/lib/watir/locators/element/matcher.rb +118 -0
  106. data/lib/watir/locators/element/selector_builder/regexp_disassembler.rb +69 -0
  107. data/lib/watir/locators/element/selector_builder/xpath.rb +268 -0
  108. data/lib/watir/locators/element/selector_builder/xpath_support.rb +29 -0
  109. data/lib/watir/locators/element/selector_builder.rb +164 -0
  110. data/lib/watir/locators/option/matcher.rb +26 -0
  111. data/lib/watir/locators/option/selector_builder/xpath.rb +39 -0
  112. data/lib/watir/locators/option/selector_builder.rb +10 -0
  113. data/lib/watir/locators/row/selector_builder/xpath.rb +53 -0
  114. data/lib/watir/locators/row/selector_builder.rb +18 -0
  115. data/lib/watir/locators/text_area/selector_builder/xpath.rb +21 -0
  116. data/lib/watir/locators/text_area/selector_builder.rb +10 -0
  117. data/lib/watir/locators/text_field/matcher.rb +37 -0
  118. data/lib/watir/locators/text_field/selector_builder/xpath.rb +50 -0
  119. data/lib/watir/locators/text_field/selector_builder.rb +10 -0
  120. data/lib/watir/locators.rb +77 -0
  121. data/lib/watir/logger.rb +30 -0
  122. data/lib/watir/navigation.rb +51 -0
  123. data/lib/watir/radio_set.rb +230 -0
  124. data/lib/watir/row_container.rb +36 -0
  125. data/lib/watir/screenshot.rb +51 -0
  126. data/lib/watir/scroll.rb +95 -0
  127. data/lib/watir/search_context.rb +96 -0
  128. data/lib/watir/shadow_root.rb +60 -0
  129. data/lib/watir/user_editable.rb +85 -0
  130. data/lib/watir/version.rb +5 -0
  131. data/lib/watir/wait/timer.rb +52 -0
  132. data/lib/watir/wait.rb +171 -0
  133. data/lib/watir/window.rb +276 -0
  134. data/lib/watir/window_collection.rb +82 -0
  135. data/lib/watir.rb +108 -0
  136. data/lib/watirspec/guards.rb +65 -0
  137. data/lib/watirspec/implementation.rb +56 -0
  138. data/lib/watirspec/rake_tasks.rb +118 -0
  139. data/lib/watirspec/remote_server.rb +39 -0
  140. data/lib/watirspec/runner.rb +64 -0
  141. data/lib/watirspec/server/app.rb +86 -0
  142. data/lib/watirspec/server.rb +104 -0
  143. data/lib/watirspec.rb +93 -0
  144. data/spec/locator_spec_helper.rb +88 -0
  145. data/spec/spec_helper.rb +24 -0
  146. data/spec/unit/capabilities_spec.rb +670 -0
  147. data/spec/unit/element_locator_spec.rb +97 -0
  148. data/spec/unit/match_elements/button_spec.rb +76 -0
  149. data/spec/unit/match_elements/element_spec.rb +424 -0
  150. data/spec/unit/match_elements/text_field_spec.rb +84 -0
  151. data/spec/unit/selector_builder/anchor_spec.rb +59 -0
  152. data/spec/unit/selector_builder/button_spec.rb +217 -0
  153. data/spec/unit/selector_builder/cell_spec.rb +71 -0
  154. data/spec/unit/selector_builder/element_spec.rb +804 -0
  155. data/spec/unit/selector_builder/row_spec.rb +128 -0
  156. data/spec/unit/selector_builder/text_field_spec.rb +203 -0
  157. data/spec/unit/selector_builder/textarea_spec.rb +35 -0
  158. data/spec/unit/unit_helper.rb +4 -0
  159. data/spec/unit/wait_spec.rb +99 -0
  160. data/spec/watirspec/adjacent_spec.rb +256 -0
  161. data/spec/watirspec/after_hooks_spec.rb +204 -0
  162. data/spec/watirspec/alert_spec.rb +89 -0
  163. data/spec/watirspec/browser_spec.rb +536 -0
  164. data/spec/watirspec/capabilities_spec.rb +556 -0
  165. data/spec/watirspec/cookies_spec.rb +196 -0
  166. data/spec/watirspec/drag_and_drop_spec.rb +38 -0
  167. data/spec/watirspec/element_hidden_spec.rb +86 -0
  168. data/spec/watirspec/elements/area_spec.rb +69 -0
  169. data/spec/watirspec/elements/areas_spec.rb +44 -0
  170. data/spec/watirspec/elements/button_spec.rb +265 -0
  171. data/spec/watirspec/elements/buttons_spec.rb +57 -0
  172. data/spec/watirspec/elements/checkbox_spec.rb +290 -0
  173. data/spec/watirspec/elements/checkboxes_spec.rb +46 -0
  174. data/spec/watirspec/elements/collections_spec.rb +132 -0
  175. data/spec/watirspec/elements/date_field_spec.rb +209 -0
  176. data/spec/watirspec/elements/date_fields_spec.rb +46 -0
  177. data/spec/watirspec/elements/date_time_field_spec.rb +223 -0
  178. data/spec/watirspec/elements/date_time_fields_spec.rb +47 -0
  179. data/spec/watirspec/elements/dd_spec.rb +108 -0
  180. data/spec/watirspec/elements/dds_spec.rb +44 -0
  181. data/spec/watirspec/elements/del_spec.rb +113 -0
  182. data/spec/watirspec/elements/dels_spec.rb +42 -0
  183. data/spec/watirspec/elements/div_spec.rb +232 -0
  184. data/spec/watirspec/elements/divs_spec.rb +56 -0
  185. data/spec/watirspec/elements/dl_spec.rb +117 -0
  186. data/spec/watirspec/elements/dls_spec.rb +45 -0
  187. data/spec/watirspec/elements/dt_spec.rb +107 -0
  188. data/spec/watirspec/elements/dts_spec.rb +44 -0
  189. data/spec/watirspec/elements/element_spec.rb +1069 -0
  190. data/spec/watirspec/elements/elements_spec.rb +60 -0
  191. data/spec/watirspec/elements/em_spec.rb +85 -0
  192. data/spec/watirspec/elements/ems_spec.rb +45 -0
  193. data/spec/watirspec/elements/filefield_spec.rb +135 -0
  194. data/spec/watirspec/elements/filefields_spec.rb +45 -0
  195. data/spec/watirspec/elements/font_spec.rb +31 -0
  196. data/spec/watirspec/elements/form_spec.rb +70 -0
  197. data/spec/watirspec/elements/forms_spec.rb +46 -0
  198. data/spec/watirspec/elements/frame_spec.rb +117 -0
  199. data/spec/watirspec/elements/frames_spec.rb +43 -0
  200. data/spec/watirspec/elements/hidden_spec.rb +106 -0
  201. data/spec/watirspec/elements/hiddens_spec.rb +45 -0
  202. data/spec/watirspec/elements/hn_spec.rb +80 -0
  203. data/spec/watirspec/elements/hns_spec.rb +42 -0
  204. data/spec/watirspec/elements/iframe_spec.rb +244 -0
  205. data/spec/watirspec/elements/iframes_spec.rb +49 -0
  206. data/spec/watirspec/elements/image_spec.rb +160 -0
  207. data/spec/watirspec/elements/images_spec.rb +42 -0
  208. data/spec/watirspec/elements/input_spec.rb +17 -0
  209. data/spec/watirspec/elements/ins_spec.rb +113 -0
  210. data/spec/watirspec/elements/inses_spec.rb +42 -0
  211. data/spec/watirspec/elements/label_spec.rb +77 -0
  212. data/spec/watirspec/elements/labels_spec.rb +42 -0
  213. data/spec/watirspec/elements/li_spec.rb +99 -0
  214. data/spec/watirspec/elements/link_spec.rb +180 -0
  215. data/spec/watirspec/elements/links_spec.rb +66 -0
  216. data/spec/watirspec/elements/lis_spec.rb +44 -0
  217. data/spec/watirspec/elements/list_spec.rb +50 -0
  218. data/spec/watirspec/elements/map_spec.rb +78 -0
  219. data/spec/watirspec/elements/maps_spec.rb +43 -0
  220. data/spec/watirspec/elements/meta_spec.rb +27 -0
  221. data/spec/watirspec/elements/metas_spec.rb +42 -0
  222. data/spec/watirspec/elements/ol_spec.rb +63 -0
  223. data/spec/watirspec/elements/ols_spec.rb +42 -0
  224. data/spec/watirspec/elements/option_spec.rb +113 -0
  225. data/spec/watirspec/elements/p_spec.rb +102 -0
  226. data/spec/watirspec/elements/pre_spec.rb +100 -0
  227. data/spec/watirspec/elements/pres_spec.rb +42 -0
  228. data/spec/watirspec/elements/ps_spec.rb +42 -0
  229. data/spec/watirspec/elements/radio_spec.rb +259 -0
  230. data/spec/watirspec/elements/radios_spec.rb +45 -0
  231. data/spec/watirspec/elements/select_list_spec.rb +701 -0
  232. data/spec/watirspec/elements/select_lists_spec.rb +49 -0
  233. data/spec/watirspec/elements/span_spec.rb +119 -0
  234. data/spec/watirspec/elements/spans_spec.rb +42 -0
  235. data/spec/watirspec/elements/strong_spec.rb +78 -0
  236. data/spec/watirspec/elements/strongs_spec.rb +45 -0
  237. data/spec/watirspec/elements/table_spec.rb +210 -0
  238. data/spec/watirspec/elements/tables_spec.rb +44 -0
  239. data/spec/watirspec/elements/tbody_spec.rb +94 -0
  240. data/spec/watirspec/elements/tbodys_spec.rb +64 -0
  241. data/spec/watirspec/elements/td_spec.rb +92 -0
  242. data/spec/watirspec/elements/tds_spec.rb +55 -0
  243. data/spec/watirspec/elements/text_field_spec.rb +223 -0
  244. data/spec/watirspec/elements/text_fields_spec.rb +47 -0
  245. data/spec/watirspec/elements/textarea_spec.rb +30 -0
  246. data/spec/watirspec/elements/textareas_spec.rb +28 -0
  247. data/spec/watirspec/elements/tfoot_spec.rb +89 -0
  248. data/spec/watirspec/elements/tfoots_spec.rb +72 -0
  249. data/spec/watirspec/elements/thead_spec.rb +88 -0
  250. data/spec/watirspec/elements/theads_spec.rb +72 -0
  251. data/spec/watirspec/elements/tr_spec.rb +69 -0
  252. data/spec/watirspec/elements/trs_spec.rb +63 -0
  253. data/spec/watirspec/elements/ul_spec.rb +63 -0
  254. data/spec/watirspec/elements/uls_spec.rb +42 -0
  255. data/spec/watirspec/html/alerts.html +12 -0
  256. data/spec/watirspec/html/aria_attributes.html +9 -0
  257. data/spec/watirspec/html/child_frame.html +29 -0
  258. data/spec/watirspec/html/class_locator.html +11 -0
  259. data/spec/watirspec/html/clicks.html +19 -0
  260. data/spec/watirspec/html/closeable.html +21 -0
  261. data/spec/watirspec/html/collections.html +15 -0
  262. data/spec/watirspec/html/css/jquery-ui-1.8.17.custom.css +287 -0
  263. data/spec/watirspec/html/data_attributes.html +10 -0
  264. data/spec/watirspec/html/definition_lists.html +48 -0
  265. data/spec/watirspec/html/drag_and_drop.html +106 -0
  266. data/spec/watirspec/html/font.html +10 -0
  267. data/spec/watirspec/html/forms_with_input_elements.html +194 -0
  268. data/spec/watirspec/html/frame_1.html +22 -0
  269. data/spec/watirspec/html/frame_2.html +16 -0
  270. data/spec/watirspec/html/frames.html +11 -0
  271. data/spec/watirspec/html/iframe_1.html +22 -0
  272. data/spec/watirspec/html/iframes.html +15 -0
  273. data/spec/watirspec/html/images/button.png +0 -0
  274. data/spec/watirspec/html/images/circle.png +0 -0
  275. data/spec/watirspec/html/images/map.gif +0 -0
  276. data/spec/watirspec/html/images/map2.gif +0 -0
  277. data/spec/watirspec/html/images/originaltriangle.png +0 -0
  278. data/spec/watirspec/html/images/square.png +0 -0
  279. data/spec/watirspec/html/images/triangle.png +0 -0
  280. data/spec/watirspec/html/images.html +28 -0
  281. data/spec/watirspec/html/inner_outer.html +5 -0
  282. data/spec/watirspec/html/javascript/angular.min.js +332 -0
  283. data/spec/watirspec/html/javascript/helpers.js +16 -0
  284. data/spec/watirspec/html/javascript/jquery-1.7.1.min.js +4 -0
  285. data/spec/watirspec/html/javascript/jquery-ui-1.8.17.custom.min.js +68 -0
  286. data/spec/watirspec/html/keylogger.html +15 -0
  287. data/spec/watirspec/html/modal_dialog.html +9 -0
  288. data/spec/watirspec/html/multiple_ids.html +15 -0
  289. data/spec/watirspec/html/nested_elements.html +44 -0
  290. data/spec/watirspec/html/nested_frame_1.html +1 -0
  291. data/spec/watirspec/html/nested_frame_2.html +9 -0
  292. data/spec/watirspec/html/nested_frame_3.html +14 -0
  293. data/spec/watirspec/html/nested_frames.html +10 -0
  294. data/spec/watirspec/html/nested_iframe_2.html +12 -0
  295. data/spec/watirspec/html/nested_iframes.html +13 -0
  296. data/spec/watirspec/html/nested_tables.html +203 -0
  297. data/spec/watirspec/html/non_control_elements.html +145 -0
  298. data/spec/watirspec/html/obscured.html +36 -0
  299. data/spec/watirspec/html/removed_element.html +24 -0
  300. data/spec/watirspec/html/right_click.html +23 -0
  301. data/spec/watirspec/html/scroll.html +15 -0
  302. data/spec/watirspec/html/scroll_nested.html +17 -0
  303. data/spec/watirspec/html/scroll_nested_offscreen.html +18 -0
  304. data/spec/watirspec/html/shadow_dom.html +28 -0
  305. data/spec/watirspec/html/special_chars.html +15 -0
  306. data/spec/watirspec/html/sticky_elements.html +10 -0
  307. data/spec/watirspec/html/tables.html +121 -0
  308. data/spec/watirspec/html/timeout_window_location.html +19 -0
  309. data/spec/watirspec/html/uneven_table.html +20 -0
  310. data/spec/watirspec/html/wait.html +99 -0
  311. data/spec/watirspec/html/watirspec.css +0 -0
  312. data/spec/watirspec/html/window_switching.html +22 -0
  313. data/spec/watirspec/radio_set_spec.rb +346 -0
  314. data/spec/watirspec/screenshot_spec.rb +33 -0
  315. data/spec/watirspec/scroll_spec.rb +208 -0
  316. data/spec/watirspec/shadow_root_spec.rb +108 -0
  317. data/spec/watirspec/support/rspec_matchers.rb +161 -0
  318. data/spec/watirspec/user_editable_spec.rb +207 -0
  319. data/spec/watirspec/wait_spec.rb +345 -0
  320. data/spec/watirspec/window_switching_spec.rb +580 -0
  321. data/spec/watirspec_helper.rb +163 -0
  322. data/support/doctest_helper.rb +101 -0
  323. data/support/version_differ.rb +60 -0
  324. data/watir.gemspec +50 -0
  325. metadata +652 -148
  326. data/readme.rb +0 -211
  327. data/unittests/WindowLogonExample.rb +0 -30
  328. data/unittests/WindowLogonExtra.rb +0 -7
  329. data/unittests/all_tests.rb +0 -10
  330. data/unittests/all_tests_concurrent.rb +0 -57
  331. data/unittests/attachToExistingWindow_test.rb +0 -40
  332. data/unittests/buttons_test.rb +0 -131
  333. data/unittests/checkbox_test.rb +0 -149
  334. data/unittests/core_tests.rb +0 -9
  335. data/unittests/css_test.rb +0 -60
  336. data/unittests/div_test.rb +0 -179
  337. data/unittests/errorchecker_test.rb +0 -29
  338. data/unittests/filefield_test.rb +0 -35
  339. data/unittests/form_test.rb +0 -279
  340. data/unittests/frame_test.rb +0 -141
  341. data/unittests/html/blankpage.html +0 -12
  342. data/unittests/html/buttons1.html +0 -40
  343. data/unittests/html/checkboxes1.html +0 -69
  344. data/unittests/html/complex_table.html +0 -36
  345. data/unittests/html/cssTest.html +0 -42
  346. data/unittests/html/div.html +0 -105
  347. data/unittests/html/fileupload.html +0 -45
  348. data/unittests/html/formTest1.html +0 -39
  349. data/unittests/html/forms2.html +0 -45
  350. data/unittests/html/forms3.html +0 -132
  351. data/unittests/html/forms4.html +0 -27
  352. data/unittests/html/frame_buttons.html +0 -4
  353. data/unittests/html/frame_links.html +0 -4
  354. data/unittests/html/frame_multi.html +0 -5
  355. data/unittests/html/iframeTest.html +0 -13
  356. data/unittests/html/iframeTest1.html +0 -7
  357. data/unittests/html/iframeTest2.html +0 -6
  358. data/unittests/html/images/button.jpg +0 -0
  359. data/unittests/html/images/circle.jpg +0 -0
  360. data/unittests/html/images/originaltriangle.jpg +0 -0
  361. data/unittests/html/images/square.jpg +0 -0
  362. data/unittests/html/images/triangle.jpg +0 -0
  363. data/unittests/html/images1.html +0 -52
  364. data/unittests/html/javascriptevents.html +0 -39
  365. data/unittests/html/link_pass.html +0 -11
  366. data/unittests/html/links1.html +0 -37
  367. data/unittests/html/links2.html +0 -11
  368. data/unittests/html/nestedFrames.html +0 -6
  369. data/unittests/html/pass.html +0 -10
  370. data/unittests/html/popups1.html +0 -60
  371. data/unittests/html/radioButtons1.html +0 -71
  372. data/unittests/html/select_tealeaf.html +0 -54
  373. data/unittests/html/selectboxes1.html +0 -55
  374. data/unittests/html/simple_table.html +0 -26
  375. data/unittests/html/simple_table_buttons.html +0 -104
  376. data/unittests/html/simple_table_columns.html +0 -76
  377. data/unittests/html/table1.html +0 -142
  378. data/unittests/html/textarea.html +0 -30
  379. data/unittests/html/textfields1.html +0 -87
  380. data/unittests/html/textsearch.html +0 -44
  381. data/unittests/ie_mock.rb +0 -93
  382. data/unittests/ie_test.rb +0 -50
  383. data/unittests/images_test.rb +0 -179
  384. data/unittests/iostring.rb +0 -30
  385. data/unittests/iostring_test.rb +0 -48
  386. data/unittests/js_events_test.rb +0 -77
  387. data/unittests/jscriptExtraAlert.rb +0 -6
  388. data/unittests/jscriptExtraConfirmCancel.rb +0 -7
  389. data/unittests/jscriptExtraConfirmOk.rb +0 -7
  390. data/unittests/jscriptPushButton.rb +0 -5
  391. data/unittests/jscript_test.rb +0 -57
  392. data/unittests/links_test.rb +0 -169
  393. data/unittests/minmax_test.rb +0 -31
  394. data/unittests/navigate_test.rb +0 -56
  395. data/unittests/non_core_tests.rb +0 -9
  396. data/unittests/pagecontainstext_test.rb +0 -49
  397. data/unittests/popups_test.rb +0 -44
  398. data/unittests/radios_test.rb +0 -164
  399. data/unittests/screen_capture_test.rb +0 -53
  400. data/unittests/selectbox_test.rb +0 -197
  401. data/unittests/send_keys_test.rb +0 -29
  402. data/unittests/setup.rb +0 -47
  403. data/unittests/table_test.rb +0 -306
  404. data/unittests/textAreafields_test.rb +0 -81
  405. data/unittests/textfields_test.rb +0 -239
  406. data/watir/AutoItX3.dll +0 -0
  407. data/watir/WindowHelper.rb +0 -47
  408. data/watir/camel_case.rb +0 -37
  409. data/watir/clickJSDialog.rb +0 -19
  410. data/watir/cookiemanager.rb +0 -53
  411. data/watir/exceptions.rb +0 -60
  412. data/watir/screen_capture.rb +0 -115
  413. data/watir/setFileDialog.rb +0 -16
  414. data/watir/testUnitAddons.rb +0 -47
  415. data/watir/watir_simple.rb +0 -475
  416. data/watir/winClicker.rb +0 -505
  417. data/watir.rb +0 -3744
  418. /data/{unittests → spec/watirspec}/html/images/1.gif +0 -0
  419. /data/{unittests/html/images/2.GIF → spec/watirspec/html/images/2.gif} +0 -0
  420. /data/{unittests/html/images/3.GIF → spec/watirspec/html/images/3.gif} +0 -0
  421. /data/{unittests/html/images/minus.GIF → spec/watirspec/html/images/minus.gif} +0 -0
  422. /data/{unittests → spec/watirspec}/html/images/plus.gif +0 -0
@@ -0,0 +1,804 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../unit_helper'
4
+
5
+ module Watir
6
+ module Locators
7
+ class Element
8
+ describe SelectorBuilder do
9
+ include LocatorSpecHelper
10
+
11
+ let(:selector_builder) { described_class.new(attributes, query_scope) }
12
+
13
+ describe '#build' do
14
+ it 'without any arguments' do
15
+ selector = {}
16
+ built = {xpath: './/*'}
17
+
18
+ expect(selector_builder.build(selector)).to eq built
19
+ end
20
+
21
+ context 'with xpath or css' do
22
+ it 'locates with xpath only' do
23
+ selector = {xpath: './/div'}
24
+ built = selector.dup
25
+
26
+ expect(selector_builder.build(selector)).to eq built
27
+ end
28
+
29
+ it 'locates with css only' do
30
+ selector = {css: 'div'}
31
+ built = selector.dup
32
+
33
+ expect(selector_builder.build(selector)).to eq built
34
+ end
35
+
36
+ it 'locates when attributes combined with xpath' do
37
+ selector = {xpath: './/div', random: 'foo'}
38
+ built = selector.dup
39
+
40
+ expect(selector_builder.build(selector)).to eq built
41
+ end
42
+
43
+ it 'locates when attributes combined with css' do
44
+ selector = {css: 'div', random: 'foo'}
45
+ built = selector.dup
46
+
47
+ expect(selector_builder.build(selector)).to eq built
48
+ end
49
+
50
+ it 'raises exception when using xpath & css' do
51
+ selector = {xpath: './/*', css: 'div'}
52
+ msg = 'Can not locate element with [:css, :xpath]'
53
+
54
+ expect { selector_builder.build(selector) }.to raise_exception Watir::Exception::LocatorException, msg
55
+ end
56
+
57
+ it 'raises exception when not a String' do
58
+ selector = {xpath: 7}
59
+ msg = /expected one of \[String\], got 7:Integer/
60
+
61
+ expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
62
+ end
63
+ end
64
+
65
+ context 'with tag_name' do
66
+ it 'with String equals' do
67
+ selector = {tag_name: 'div'}
68
+ built = {xpath: ".//*[local-name()='div']"}
69
+
70
+ expect(selector_builder.build(selector)).to eq built
71
+ end
72
+
73
+ it 'with simple Regexp contains' do
74
+ selector = {tag_name: /div/}
75
+ built = {xpath: './/*[contains(local-name(), "div")]'}
76
+
77
+ expect(selector_builder.build(selector)).to eq built
78
+ end
79
+
80
+ it 'with Symbol' do
81
+ selector = {tag_name: :div}
82
+ built = {xpath: ".//*[local-name()='div']"}
83
+
84
+ expect(selector_builder.build(selector)).to eq built
85
+ end
86
+
87
+ it 'raises exception when not a String or Regexp' do
88
+ selector = {tag_name: 7}
89
+ msg = /expected one of \[String, Regexp, Symbol\], got 7:Integer/
90
+
91
+ expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
92
+ end
93
+ end
94
+
95
+ context 'with class names' do
96
+ it 'class_name is converted to class' do
97
+ selector = {class_name: 'user'}
98
+ built = {xpath: ".//*[contains(concat(' ', normalize-space(@class), ' '), ' user ')]"}
99
+
100
+ expect(selector_builder.build(selector)).to eq built
101
+ end
102
+
103
+ it 'single String concatenates' do
104
+ selector = {class: 'user'}
105
+ built = {xpath: ".//*[contains(concat(' ', normalize-space(@class), ' '), ' user ')]"}
106
+
107
+ expect(selector_builder.build(selector)).to eq built
108
+ end
109
+
110
+ it 'Array of String concatenates with and' do
111
+ selector = {class: %w[multiple here]}
112
+ built = {xpath: ".//*[contains(concat(' ', normalize-space(@class), ' '), ' multiple ') and " \
113
+ "contains(concat(' ', normalize-space(@class), ' '), ' here ')]"}
114
+
115
+ expect(selector_builder.build(selector)).to eq built
116
+ end
117
+
118
+ it 'merges values when class and class_name are both used' do
119
+ selector = {class: 'foo', class_name: 'bar'}
120
+ built = {xpath: ".//*[contains(concat(' ', normalize-space(@class), ' '), ' foo ') and " \
121
+ "contains(concat(' ', normalize-space(@class), ' '), ' bar ')]"}
122
+
123
+ expect(selector_builder.build(selector)).to eq built
124
+ end
125
+
126
+ it 'simple Regexp contains' do
127
+ selector = {class_name: /use/}
128
+ built = {xpath: './/*[contains(@class, "use")]'}
129
+
130
+ expect(selector_builder.build(selector)).to eq built
131
+ end
132
+
133
+ it 'Array of Regexp contains with and' do
134
+ selector = {class: [/mult/, /her/]}
135
+ built = {xpath: './/*[contains(@class, "mult") and contains(@class, "her")]'}
136
+
137
+ expect(selector_builder.build(selector)).to eq built
138
+ end
139
+
140
+ it 'single negated String concatenates with not' do
141
+ selector = {class: '!multiple'}
142
+ built = {xpath: ".//*[not(contains(concat(' ', normalize-space(@class), ' '), ' multiple '))]"}
143
+
144
+ expect(selector_builder.build(selector)).to eq built
145
+ end
146
+
147
+ it 'single Boolean true provides the at' do
148
+ selector = {class: true}
149
+ built = {xpath: './/*[@class]'}
150
+
151
+ expect(selector_builder.build(selector)).to eq built
152
+ end
153
+
154
+ it 'single Boolean false provides the not atat' do
155
+ selector = {class: false}
156
+ built = {xpath: './/*[not(@class)]'}
157
+
158
+ expect(selector_builder.build(selector)).to eq built
159
+ end
160
+
161
+ it 'Array of mixed String, Regexp and Boolean contains and concatenates with and and not' do
162
+ selector = {class: [/mult/, 'classes', '!here']}
163
+ built = {xpath: './/*[contains(@class, "mult") ' \
164
+ "and contains(concat(' ', normalize-space(@class), ' '), ' classes ') " \
165
+ "and not(contains(concat(' ', normalize-space(@class), ' '), ' here '))]"}
166
+
167
+ expect(selector_builder.build(selector)).to eq built
168
+ end
169
+
170
+ it 'empty string finds elements without class' do
171
+ selector = {class_name: ''}
172
+ built = {xpath: './/*[not(@class)]'}
173
+
174
+ expect(selector_builder.build(selector)).to eq built
175
+ end
176
+
177
+ it 'empty Array finds elements without class' do
178
+ selector = {class_name: []}
179
+ built = {xpath: './/*[not(@class)]'}
180
+
181
+ expect(selector_builder.build(selector)).to eq built
182
+ end
183
+
184
+ it 'raises exception when not a String or Regexp or Array' do
185
+ selector = {class: 7}
186
+ msg = /expected one of \[String, Regexp, TrueClass, FalseClass\], got 7:Integer/
187
+
188
+ expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
189
+ end
190
+
191
+ it 'raises exception when Array values are not a String or Regexp' do
192
+ selector = {class: [7]}
193
+ msg = /expected one of \[String, Regexp, TrueClass, FalseClass\], got 7:Integer/
194
+
195
+ expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
196
+ end
197
+ end
198
+
199
+ context 'with attributes as predicates' do
200
+ it 'with href attribute' do
201
+ selector = {href: 'watirspec.css'}
202
+ built = {xpath: ".//*[normalize-space(@href)='watirspec.css']"}
203
+
204
+ expect(selector_builder.build(selector)).to eq built
205
+ end
206
+
207
+ it 'with String attribute key' do
208
+ selector = {'id' => 'user_new'}
209
+ built = {xpath: ".//*[@id='user_new']"}
210
+
211
+ expect(selector_builder.build(selector)).to eq built
212
+ end
213
+
214
+ it 'with String equals' do
215
+ selector = {id: 'user_new'}
216
+ built = {xpath: ".//*[@id='user_new']"}
217
+
218
+ expect(selector_builder.build(selector)).to eq built
219
+ end
220
+
221
+ it 'with TrueClass no equals' do
222
+ selector = {tag_name: 'input', id: true}
223
+ built = {xpath: ".//*[local-name()='input'][@id]"}
224
+
225
+ expect(selector_builder.build(selector)).to eq built
226
+ end
227
+
228
+ it 'with FalseClass not with no equals' do
229
+ selector = {tag_name: 'input', name: false}
230
+ built = {xpath: ".//*[local-name()='input'][not(@name)]"}
231
+
232
+ expect(selector_builder.build(selector)).to eq built
233
+ end
234
+
235
+ it 'with multiple attributes: no equals and not with no equals and equals' do
236
+ selector = {readonly: true, foo: false, id: 'good_luck'}
237
+ built = {xpath: ".//*[@readonly and not(@foo) and @id='good_luck']"}
238
+
239
+ expect(selector_builder.build(selector)).to eq built
240
+ end
241
+
242
+ it 'raises exception when attribute value is not a Boolean, String or Regexp' do
243
+ selector = {foo: 7}
244
+ msg = /expected one of \[String, Regexp, TrueClass, FalseClass\], got 7:Integer/
245
+
246
+ expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
247
+ end
248
+
249
+ it 'raises exception when attribute key is not a String or Regexp' do
250
+ selector = {7 => 'foo'}
251
+ msg = /Unable to build XPath using 7:Integer/
252
+
253
+ expect { selector_builder.build(selector) }.to raise_exception Watir::Exception::LocatorException, msg
254
+ end
255
+ end
256
+
257
+ context 'with attributes as partials' do
258
+ it 'with Regexp' do
259
+ selector = {name: /user/}
260
+ built = {xpath: './/*[contains(@name, "user")]'}
261
+
262
+ expect(selector_builder.build(selector)).to eq built
263
+ end
264
+
265
+ it 'with multiple Regexp attributes separated by and' do
266
+ selector = {readonly: /read/, id: /good/}
267
+ built = {xpath: './/*[contains(@readonly, "read") and contains(@id, "good")]'}
268
+
269
+ expect(selector_builder.build(selector)).to eq built
270
+ end
271
+ end
272
+
273
+ context 'with text' do
274
+ it 'String uses normalize space equals' do
275
+ selector = {text: 'Add user'}
276
+ built = {xpath: ".//*[normalize-space()='Add user']"}
277
+
278
+ expect(selector_builder.build(selector)).to eq built
279
+ end
280
+
281
+ it 'Regexp uses contains normalize space' do
282
+ selector = {text: /Add/}
283
+ built = {xpath: './/*[contains(normalize-space(), "Add")]'}
284
+
285
+ expect(selector_builder.build(selector)).to eq built
286
+ end
287
+
288
+ it 'raises exception when text is not a String or Regexp' do
289
+ selector = {text: 7}
290
+ msg = /expected one of \[String, Regexp\], got 7:Integer/
291
+
292
+ expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
293
+ end
294
+ end
295
+
296
+ context 'with index' do
297
+ it 'positive' do
298
+ selector = {tag_name: 'div', index: 7}
299
+ built = {xpath: "(.//*[local-name()='div'])[8]"}
300
+
301
+ expect(selector_builder.build(selector)).to eq built
302
+ end
303
+
304
+ it 'negative' do
305
+ selector = {tag_name: 'div', index: -7}
306
+ built = {xpath: "(.//*[local-name()='div'])[last()-6]"}
307
+
308
+ expect(selector_builder.build(selector)).to eq built
309
+ end
310
+
311
+ it 'last' do
312
+ selector = {tag_name: 'div', index: -1}
313
+ built = {xpath: "(.//*[local-name()='div'])[last()]"}
314
+
315
+ expect(selector_builder.build(selector)).to eq built
316
+ end
317
+
318
+ it 'does not return index if it is zero' do
319
+ selector = {tag_name: 'div', index: 0}
320
+ built = {xpath: ".//*[local-name()='div']"}
321
+
322
+ expect(selector_builder.build(selector)).to eq built
323
+ end
324
+
325
+ it 'raises exception when index is not an Integer' do
326
+ selector = {index: 'foo'}
327
+ msg = /expected one of \[(Integer|Fixnum)\], got "foo":String/
328
+
329
+ expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
330
+ end
331
+ end
332
+
333
+ context 'with labels' do
334
+ it 'locates the element associated with the label element located by the text of the provided label key' do
335
+ selector = {label: 'Cars'}
336
+ built = {xpath: ".//*[@id=//label[normalize-space()='Cars']/@for " \
337
+ "or parent::label[normalize-space()='Cars']]"}
338
+
339
+ expect(selector_builder.build(selector)).to eq built
340
+ end
341
+
342
+ it 'returns a label_element if complex' do
343
+ selector = {label: /Ca|rs/}
344
+ xpath = './/*[@id=//label[normalize-space()]/@for or parent::label[normalize-space()]]'
345
+ built = {xpath: xpath, label_element: /Ca|rs/}
346
+
347
+ expect(selector_builder.build(selector)).to eq built
348
+ end
349
+
350
+ it 'returns a visible_label_element if complex' do
351
+ selector = {visible_label: /Ca|rs/}
352
+ built = {xpath: './/*', visible_label_element: /Ca|rs/}
353
+
354
+ expect(selector_builder.build(selector)).to eq built
355
+ end
356
+
357
+ it 'does not use the label element when label is a valid attribute' do
358
+ @attributes ||= Watir::Option.attribute_list
359
+
360
+ selector = {tag_name: 'option', label: 'Germany'}
361
+ built = {xpath: ".//*[local-name()='option'][@label='Germany']"}
362
+
363
+ expect(selector_builder.build(selector)).to eq built
364
+ end
365
+ end
366
+
367
+ context 'with adjacent locators' do
368
+ it 'raises exception when not a Symbol' do
369
+ selector = {adjacent: 'foo', index: 0}
370
+ msg = 'expected one of [Symbol], got "foo":String'
371
+
372
+ expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
373
+ end
374
+
375
+ it 'raises exception when not a valid value' do
376
+ selector = {adjacent: :foo, index: 0}
377
+ msg = 'Unable to process adjacent locator with foo'
378
+
379
+ expect { selector_builder.build(selector) }.to raise_exception Watir::Exception::LocatorException, msg
380
+ end
381
+
382
+ describe '#parent' do
383
+ it 'with no other arguments' do
384
+ selector = {adjacent: :ancestor, index: 0}
385
+ built = {xpath: './ancestor::*[1]'}
386
+
387
+ expect(selector_builder.build(selector)).to eq built
388
+ end
389
+
390
+ it 'with index' do
391
+ selector = {adjacent: :ancestor, index: 2}
392
+ built = {xpath: './ancestor::*[3]'}
393
+
394
+ expect(selector_builder.build(selector)).to eq built
395
+ end
396
+
397
+ it 'with multiple locators' do
398
+ selector = {adjacent: :ancestor, id: true, tag_name: 'div', class: 'ancestor', index: 1}
399
+ built = {xpath: "./ancestor::*[local-name()='div']" \
400
+ "[contains(concat(' ', normalize-space(@class), ' '), ' ancestor ')][@id][2]"}
401
+
402
+ expect(selector_builder.build(selector)).to eq built
403
+ end
404
+
405
+ it 'raises an exception if text locator is used' do
406
+ selector = {adjacent: :ancestor, index: 0, text: 'Foo'}
407
+ msg = 'Can not find parent element with text locator'
408
+ expect { selector_builder.build(selector) }
409
+ .to raise_exception Watir::Exception::LocatorException, msg
410
+ end
411
+ end
412
+
413
+ describe '#following_sibling' do
414
+ it 'with no other arguments' do
415
+ selector = {adjacent: :following, index: 0}
416
+ built = {xpath: './following-sibling::*[1]'}
417
+
418
+ expect(selector_builder.build(selector)).to eq built
419
+ end
420
+
421
+ it 'with index' do
422
+ selector = {adjacent: :following, index: 2}
423
+ built = {xpath: './following-sibling::*[3]'}
424
+
425
+ expect(selector_builder.build(selector)).to eq built
426
+ end
427
+
428
+ it 'with multiple locators' do
429
+ selector = {adjacent: :following, tag_name: 'div', class: 'b', index: 0, id: true}
430
+ built = {xpath: "./following-sibling::*[local-name()='div']" \
431
+ "[contains(concat(' ', normalize-space(@class), ' '), ' b ')][@id][1]"}
432
+
433
+ expect(selector_builder.build(selector)).to eq built
434
+ end
435
+
436
+ it 'with text' do
437
+ selector = {adjacent: :following, text: 'Third', index: 0}
438
+ built = {xpath: "./following-sibling::*[normalize-space()='Third'][1]"}
439
+
440
+ expect(selector_builder.build(selector)).to eq built
441
+ end
442
+ end
443
+
444
+ describe '#previous_sibling' do
445
+ it 'with no other arguments' do
446
+ selector = {adjacent: :preceding, index: 0}
447
+ built = {xpath: './preceding-sibling::*[1]'}
448
+
449
+ expect(selector_builder.build(selector)).to eq built
450
+ end
451
+
452
+ it 'with index' do
453
+ selector = {adjacent: :preceding, index: 2}
454
+ built = {xpath: './preceding-sibling::*[3]'}
455
+
456
+ expect(selector_builder.build(selector)).to eq built
457
+ end
458
+
459
+ it 'with multiple locators' do
460
+ selector = {adjacent: :preceding, tag_name: 'div', class: 'b', id: true, index: 0}
461
+ built = {xpath: "./preceding-sibling::*[local-name()='div']" \
462
+ "[contains(concat(' ', normalize-space(@class), ' '), ' b ')][@id][1]"}
463
+
464
+ expect(selector_builder.build(selector)).to eq built
465
+ end
466
+
467
+ it 'with text' do
468
+ selector = {adjacent: :preceding, text: 'Second', index: 0}
469
+ built = {xpath: "./preceding-sibling::*[normalize-space()='Second'][1]"}
470
+
471
+ expect(selector_builder.build(selector)).to eq built
472
+ end
473
+ end
474
+
475
+ describe '#child' do
476
+ it 'with no other arguments' do
477
+ selector = {adjacent: :child, index: 0}
478
+ built = {xpath: './child::*[1]'}
479
+
480
+ expect(selector_builder.build(selector)).to eq built
481
+ end
482
+
483
+ it 'with index' do
484
+ selector = {adjacent: :child, index: 2}
485
+ built = {xpath: './child::*[3]'}
486
+
487
+ expect(selector_builder.build(selector)).to eq built
488
+ end
489
+
490
+ it 'with multiple locators' do
491
+ selector = {adjacent: :child, tag_name: 'div', class: 'b', id: true, index: 0}
492
+ built = {xpath: "./child::*[local-name()='div']" \
493
+ "[contains(concat(' ', normalize-space(@class), ' '), ' b ')][@id][1]"}
494
+
495
+ expect(selector_builder.build(selector)).to eq built
496
+ end
497
+
498
+ it 'with text' do
499
+ selector = {adjacent: :child, text: 'Second', index: 0}
500
+ built = {xpath: "./child::*[normalize-space()='Second'][1]"}
501
+
502
+ expect(selector_builder.build(selector)).to eq built
503
+ end
504
+ end
505
+ end
506
+
507
+ context 'with multiple locators' do
508
+ it 'locates using tag name, class, attributes and text' do
509
+ selector = {tag_name: 'div', class: 'content', contenteditable: 'true', text: 'Foo'}
510
+ built = {xpath: ".//*[local-name()='div']" \
511
+ "[contains(concat(' ', normalize-space(@class), ' '), ' content ')]" \
512
+ "[normalize-space()='Foo'][@contenteditable='true']"}
513
+
514
+ expect(selector_builder.build(selector)).to eq built
515
+ end
516
+ end
517
+
518
+ context 'with simple Regexp' do
519
+ it 'handles spaces' do
520
+ selector = {title: /od Lu/}
521
+ built = {xpath: './/*[contains(@title, "od Lu")]'}
522
+
523
+ expect(selector_builder.build(selector)).to eq built
524
+ end
525
+
526
+ it 'handles escaped characters' do
527
+ selector = {src: %r{ages/but}}
528
+ built = {xpath: './/*[contains(@src, "ages/but")]'}
529
+
530
+ expect(selector_builder.build(selector)).to eq built
531
+ end
532
+ end
533
+
534
+ context 'with complex Regexp' do
535
+ it 'handles wildcards' do
536
+ selector = {src: /ages.*but/}
537
+ built = {xpath: './/*[contains(@src, "ages") and contains(@src, "but")]', src: /ages.*but/}
538
+
539
+ expect(selector_builder.build(selector)).to eq built
540
+ end
541
+
542
+ it 'handles optional characters' do
543
+ selector = {src: /ages ?but/}
544
+ built = {xpath: './/*[contains(@src, "ages") and contains(@src, "but")]', src: /ages ?but/}
545
+
546
+ expect(selector_builder.build(selector)).to eq built
547
+ end
548
+
549
+ it 'handles anchors' do
550
+ selector = {name: /^new_user_image$/}
551
+ built = {xpath: './/*[contains(@name, "new_user_image")]', name: /^new_user_image$/}
552
+
553
+ expect(selector_builder.build(selector)).to eq built
554
+ end
555
+
556
+ it 'handles beginning anchor' do
557
+ selector = {src: /^i/}
558
+ built = {xpath: ".//*[starts-with(@src, 'i')]"}
559
+
560
+ expect(selector_builder.build(selector)).to eq built
561
+ end
562
+
563
+ it 'does not use starts-with if visible locator used' do
564
+ selector = {id: /^vis/, visible_text: 'shown div'}
565
+ built = {xpath: './/*[contains(@id, "vis")]', id: /^vis/, visible_text: 'shown div'}
566
+
567
+ expect(selector_builder.build(selector)).to eq built
568
+ end
569
+
570
+ it 'handles case insensitive' do
571
+ selector = {action: /ME/i}
572
+ built = {xpath: './/*[contains(translate(@action,' \
573
+ "'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'," \
574
+ "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'), " \
575
+ 'translate("me",' \
576
+ "'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'," \
577
+ "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'))]"}
578
+
579
+ expect(selector_builder.build(selector)).to eq built
580
+ end
581
+ end
582
+
583
+ context 'with special cased selectors' do
584
+ it 'handles data-* attributes with String' do
585
+ selector = {data_foo: 'user_new'}
586
+ built = {xpath: ".//*[@data-foo='user_new']"}
587
+
588
+ expect(selector_builder.build(selector)).to eq built
589
+ end
590
+
591
+ it 'handles aria-* attributes' do
592
+ selector = {aria_foo: 'user_new'}
593
+ built = {xpath: ".//*[@aria-foo='user_new']"}
594
+
595
+ expect(selector_builder.build(selector)).to eq built
596
+ end
597
+
598
+ it "doesn't modify attribute name when the attribute key is a string" do
599
+ selector = {'_underscore-dash' => 'user_new'}
600
+ built = {xpath: ".//*[@_underscore-dash='user_new']"}
601
+
602
+ expect(selector_builder.build(selector)).to eq built
603
+ end
604
+
605
+ it 'translates ruby attribute names to content attribute names' do
606
+ selector = {http_equiv: 'foo'}
607
+ built = {xpath: ".//*[@http-equiv='foo']"}
608
+
609
+ expect(selector_builder.build(selector)).to eq built
610
+ end
611
+ end
612
+
613
+ context 'when can not be directly translated' do
614
+ it 'returns locator from attribute with complicated Regexp at end' do
615
+ selector = {action: /me$/}
616
+ built = {xpath: './/*[contains(@action, "me")]', action: /me$/}
617
+
618
+ expect(selector_builder.build(selector)).to eq built
619
+ end
620
+
621
+ it 'returns locator from class with complicated Regexp' do
622
+ selector = {class: /he?r/}
623
+ built = {xpath: './/*[contains(@class, "h") and contains(@class, "r")]', class: [/he?r/]}
624
+
625
+ expect(selector_builder.build(selector)).to eq built
626
+ end
627
+
628
+ it 'returns locator from visible' do
629
+ selector = {tag_name: 'div', visible: true}
630
+ built = {xpath: ".//*[local-name()='div']", visible: true}
631
+
632
+ expect(selector_builder.build(selector)).to eq built
633
+ end
634
+
635
+ it 'returns locator from not visible' do
636
+ selector = {tag_name: 'span', visible: false}
637
+ built = {xpath: ".//*[local-name()='span']", visible: false}
638
+
639
+ expect(selector_builder.build(selector)).to eq built
640
+ end
641
+
642
+ it 'returns locator from visible text' do
643
+ selector = {tag_name: 'span', visible_text: 'foo'}
644
+ built = {xpath: ".//*[local-name()='span']", visible_text: 'foo'}
645
+
646
+ expect(selector_builder.build(selector)).to eq built
647
+ end
648
+
649
+ it 'raises exception when visible is not boolean' do
650
+ selector = {visible: 'foo'}
651
+ msg = 'expected one of [TrueClass, FalseClass], got "foo":String'
652
+
653
+ expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
654
+ end
655
+
656
+ it 'raises exception when visible text is not a String or Regexp' do
657
+ selector = {visible_text: 7}
658
+ msg = /expected one of \[String, Regexp\], got 7:Integer/
659
+
660
+ expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
661
+ end
662
+ end
663
+
664
+ context 'with generic element scope' do
665
+ let(:query_scope) { instance_double Watir::HTMLElement }
666
+ let(:scope_built) { {xpath: ".//*[local-name()='div'][@id='table-rows-test']"} }
667
+
668
+ before do
669
+ allow(query_scope).to receive_messages(selector_builder: selector_builder, browser: browser)
670
+ allow(selector_builder).to receive(:built).and_return(scope_built)
671
+ end
672
+
673
+ it 'uses scope' do
674
+ selector = {tag_name: 'div'}
675
+ built = {xpath: "(#{scope_built[:xpath]})[1]//*[local-name()='div']"}
676
+
677
+ expect(selector_builder.build(selector)).to eq built
678
+ end
679
+
680
+ it 'does not use scope if selector is a CSS' do
681
+ selector = {css: 'div'}
682
+
683
+ build_selector = selector_builder.build(selector)
684
+ expect(build_selector.delete(:scope)).not_to be_nil
685
+ expect(build_selector).to eq selector
686
+ end
687
+
688
+ it 'does not use scope if selector is a XPath' do
689
+ selector = {xpath: './/*'}
690
+
691
+ build_selector = selector_builder.build(selector)
692
+ expect(build_selector.delete(:scope)).not_to be_nil
693
+ expect(build_selector).to eq selector
694
+ end
695
+
696
+ it 'does not use scope if selector has :adjacent' do
697
+ selector = {adjacent: :ancestor, index: 0}
698
+ built = {xpath: './ancestor::*[1]'}
699
+
700
+ build_selector = selector_builder.build(selector)
701
+ expect(build_selector.delete(:scope)).not_to be_nil
702
+ expect(build_selector).to eq built
703
+ end
704
+ end
705
+
706
+ context 'with invalid query scopes' do
707
+ let(:query_scope) { instance_double Watir::HTMLElement }
708
+
709
+ it 'does not use scope if query_scope built has multiple keys' do
710
+ scope_built = {xpath: ".//*[local-name()='div']", visible: true}
711
+ allow(selector_builder).to receive(:built).and_return(scope_built)
712
+ allow(query_scope).to receive(:selector_builder).and_return(selector_builder)
713
+
714
+ selector = {tag_name: 'div'}
715
+ built = {xpath: ".//*[local-name()='div']"}
716
+
717
+ build_selector = selector_builder.build(selector)
718
+ expect(build_selector.delete(:scope)).not_to be_nil
719
+ expect(build_selector).to eq built
720
+ end
721
+
722
+ it 'does not use scope if query_scope uses different Selenium Locator' do
723
+ scope_built = {css: '#foo'}
724
+ allow(selector_builder).to receive(:built).and_return(scope_built)
725
+ allow(query_scope).to receive(:selector_builder).and_return(selector_builder)
726
+
727
+ selector = {tag_name: 'div'}
728
+ built = {xpath: ".//*[local-name()='div']"}
729
+
730
+ build_selector = selector_builder.build(selector)
731
+ expect(build_selector.delete(:scope)).not_to be_nil
732
+ expect(build_selector).to eq built
733
+ end
734
+ end
735
+
736
+ context 'with specific element scope' do
737
+ let(:scope_built) { {xpath: ".//*[local-name()='iframe'][@id='one']"} }
738
+
739
+ it 'does not use scope if query scope is an IFrame' do
740
+ query_scope = instance_double Watir::IFrame
741
+ selector_builder = described_class.new(attributes, query_scope)
742
+
743
+ allow(selector_builder).to receive(:built).and_return(scope_built)
744
+ allow(query_scope).to receive_messages(selector_builder: selector_builder, browser: browser)
745
+ allow(query_scope).to receive(:is_a?).with(Watir::Browser).and_return(false)
746
+ allow(query_scope).to receive(:is_a?).with(Watir::ShadowRoot).and_return(false)
747
+ allow(query_scope).to receive(:is_a?).with(Watir::IFrame).and_return(true)
748
+
749
+ selector = {tag_name: 'div'}
750
+ built = {xpath: ".//*[local-name()='div']"}
751
+
752
+ build_selector = selector_builder.build(selector)
753
+ expect(build_selector.delete(:scope)).not_to be_nil
754
+ expect(build_selector).to eq built
755
+ end
756
+ end
757
+
758
+ context 'with case-insensitive attributes' do
759
+ let(:upper) { "'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'" }
760
+ let(:lower) { "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'" }
761
+
762
+ it 'respects case when locating uknown element with uknown attribute' do
763
+ expect(selector_builder.build(hreflang: 'en')).to eq(xpath: ".//*[@hreflang='en']")
764
+ expect(selector_builder.build(hreflang: /en/)).to eq(xpath: './/*[contains(@hreflang, "en")]')
765
+ end
766
+
767
+ it 'ignores case when locating uknown element with defined attribute' do
768
+ lhs = "translate(@lang,#{upper},#{lower})"
769
+ rhs = "translate('en',#{upper},#{lower})"
770
+ rhs_regex = "translate(\"en\",#{upper},#{lower})"
771
+ expect(selector_builder.build(lang: 'en')).to eq(xpath: ".//*[#{lhs}=#{rhs}]")
772
+ expect(selector_builder.build(lang: /en/)).to eq(xpath: ".//*[contains(#{lhs}, #{rhs_regex})]")
773
+ expect(selector_builder.build(tag_name: /a/, lang: 'en'))
774
+ .to eq(xpath: ".//*[contains(local-name(), \"a\")][#{lhs}=#{rhs}]")
775
+ expect(selector_builder.build(tag_name: /a/, lang: /en/))
776
+ .to eq(xpath: ".//*[contains(local-name(), \"a\")][contains(#{lhs}, #{rhs_regex})]")
777
+ end
778
+
779
+ it 'ignores case when attribute is defined for element' do
780
+ lhs = "translate(@hreflang,#{upper},#{lower})"
781
+ rhs = "translate('en',#{upper},#{lower})"
782
+ rhs_regex = "translate(\"en\",#{upper},#{lower})"
783
+ expect(selector_builder.build(tag_name: 'a', hreflang: 'en'))
784
+ .to eq(xpath: ".//*[local-name()='a'][#{lhs}=#{rhs}]")
785
+ expect(selector_builder.build(tag_name: 'a', hreflang: /en/))
786
+ .to eq(xpath: ".//*[local-name()='a'][contains(#{lhs}, #{rhs_regex})]")
787
+ end
788
+
789
+ it 'respects case when attribute is not defined for element' do
790
+ expect(selector_builder.build(tag_name: 'table', hreflang: 'en'))
791
+ .to eq(xpath: ".//*[local-name()='table'][@hreflang='en']")
792
+ expect(selector_builder.build(tag_name: 'table', hreflang: /en/))
793
+ .to eq(xpath: ".//*[local-name()='table'][contains(@hreflang, \"en\")]")
794
+ expect(selector_builder.build(tag_name: /a/, hreflang: 'en'))
795
+ .to eq(xpath: ".//*[contains(local-name(), \"a\")][@hreflang='en']")
796
+ expect(selector_builder.build(tag_name: /a/, hreflang: /en/))
797
+ .to eq(xpath: './/*[contains(local-name(), "a")][contains(@hreflang, "en")]')
798
+ end
799
+ end
800
+ end
801
+ end
802
+ end
803
+ end
804
+ end