capybara 3.13.2 → 3.40.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 (260) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/History.md +587 -16
  4. data/README.md +240 -90
  5. data/lib/capybara/config.rb +24 -11
  6. data/lib/capybara/cucumber.rb +1 -1
  7. data/lib/capybara/driver/base.rb +8 -0
  8. data/lib/capybara/driver/node.rb +20 -4
  9. data/lib/capybara/dsl.rb +5 -3
  10. data/lib/capybara/helpers.rb +25 -4
  11. data/lib/capybara/minitest/spec.rb +174 -90
  12. data/lib/capybara/minitest.rb +256 -142
  13. data/lib/capybara/node/actions.rb +123 -77
  14. data/lib/capybara/node/base.rb +20 -12
  15. data/lib/capybara/node/document.rb +2 -2
  16. data/lib/capybara/node/document_matchers.rb +3 -3
  17. data/lib/capybara/node/element.rb +223 -117
  18. data/lib/capybara/node/finders.rb +81 -71
  19. data/lib/capybara/node/matchers.rb +271 -134
  20. data/lib/capybara/node/simple.rb +18 -5
  21. data/lib/capybara/node/whitespace_normalizer.rb +81 -0
  22. data/lib/capybara/queries/active_element_query.rb +18 -0
  23. data/lib/capybara/queries/ancestor_query.rb +8 -9
  24. data/lib/capybara/queries/base_query.rb +3 -2
  25. data/lib/capybara/queries/current_path_query.rb +15 -5
  26. data/lib/capybara/queries/selector_query.rb +364 -54
  27. data/lib/capybara/queries/sibling_query.rb +8 -6
  28. data/lib/capybara/queries/style_query.rb +2 -2
  29. data/lib/capybara/queries/text_query.rb +13 -1
  30. data/lib/capybara/queries/title_query.rb +1 -1
  31. data/lib/capybara/rack_test/browser.rb +76 -11
  32. data/lib/capybara/rack_test/driver.rb +10 -5
  33. data/lib/capybara/rack_test/errors.rb +6 -0
  34. data/lib/capybara/rack_test/form.rb +31 -9
  35. data/lib/capybara/rack_test/node.rb +74 -23
  36. data/lib/capybara/registration_container.rb +41 -0
  37. data/lib/capybara/registrations/drivers.rb +42 -0
  38. data/lib/capybara/registrations/patches/puma_ssl.rb +29 -0
  39. data/lib/capybara/registrations/servers.rb +66 -0
  40. data/lib/capybara/result.rb +44 -20
  41. data/lib/capybara/rspec/matcher_proxies.rb +13 -11
  42. data/lib/capybara/rspec/matchers/base.rb +31 -16
  43. data/lib/capybara/rspec/matchers/compound.rb +1 -1
  44. data/lib/capybara/rspec/matchers/count_sugar.rb +37 -0
  45. data/lib/capybara/rspec/matchers/have_ancestor.rb +28 -0
  46. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  47. data/lib/capybara/rspec/matchers/have_selector.rb +21 -21
  48. data/lib/capybara/rspec/matchers/have_sibling.rb +27 -0
  49. data/lib/capybara/rspec/matchers/have_text.rb +4 -4
  50. data/lib/capybara/rspec/matchers/have_title.rb +2 -2
  51. data/lib/capybara/rspec/matchers/match_selector.rb +3 -3
  52. data/lib/capybara/rspec/matchers/match_style.rb +7 -2
  53. data/lib/capybara/rspec/matchers/spatial_sugar.rb +39 -0
  54. data/lib/capybara/rspec/matchers.rb +111 -68
  55. data/lib/capybara/rspec.rb +2 -0
  56. data/lib/capybara/selector/builders/css_builder.rb +11 -7
  57. data/lib/capybara/selector/builders/xpath_builder.rb +5 -3
  58. data/lib/capybara/selector/css.rb +11 -9
  59. data/lib/capybara/selector/definition/button.rb +68 -0
  60. data/lib/capybara/selector/definition/checkbox.rb +26 -0
  61. data/lib/capybara/selector/definition/css.rb +10 -0
  62. data/lib/capybara/selector/definition/datalist_input.rb +35 -0
  63. data/lib/capybara/selector/definition/datalist_option.rb +25 -0
  64. data/lib/capybara/selector/definition/element.rb +28 -0
  65. data/lib/capybara/selector/definition/field.rb +40 -0
  66. data/lib/capybara/selector/definition/fieldset.rb +14 -0
  67. data/lib/capybara/selector/definition/file_field.rb +13 -0
  68. data/lib/capybara/selector/definition/fillable_field.rb +33 -0
  69. data/lib/capybara/selector/definition/frame.rb +17 -0
  70. data/lib/capybara/selector/definition/id.rb +6 -0
  71. data/lib/capybara/selector/definition/label.rb +62 -0
  72. data/lib/capybara/selector/definition/link.rb +55 -0
  73. data/lib/capybara/selector/definition/link_or_button.rb +16 -0
  74. data/lib/capybara/selector/definition/option.rb +27 -0
  75. data/lib/capybara/selector/definition/radio_button.rb +27 -0
  76. data/lib/capybara/selector/definition/select.rb +81 -0
  77. data/lib/capybara/selector/definition/table.rb +109 -0
  78. data/lib/capybara/selector/definition/table_row.rb +21 -0
  79. data/lib/capybara/selector/definition/xpath.rb +5 -0
  80. data/lib/capybara/selector/definition.rb +280 -0
  81. data/lib/capybara/selector/filter_set.rb +19 -18
  82. data/lib/capybara/selector/filters/base.rb +11 -2
  83. data/lib/capybara/selector/filters/locator_filter.rb +13 -3
  84. data/lib/capybara/selector/regexp_disassembler.rb +11 -7
  85. data/lib/capybara/selector/selector.rb +50 -440
  86. data/lib/capybara/selector/xpath_extensions.rb +17 -0
  87. data/lib/capybara/selector.rb +473 -482
  88. data/lib/capybara/selenium/atoms/getAttribute.min.js +1 -0
  89. data/lib/capybara/selenium/atoms/isDisplayed.min.js +1 -0
  90. data/lib/capybara/selenium/atoms/src/getAttribute.js +161 -0
  91. data/lib/capybara/selenium/atoms/src/isDisplayed.js +454 -0
  92. data/lib/capybara/selenium/driver.rb +174 -62
  93. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +74 -18
  94. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +128 -0
  95. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +37 -3
  96. data/lib/capybara/selenium/driver_specializations/internet_explorer_driver.rb +14 -1
  97. data/lib/capybara/selenium/driver_specializations/safari_driver.rb +24 -0
  98. data/lib/capybara/selenium/extensions/file_input_click_emulation.rb +34 -0
  99. data/lib/capybara/selenium/extensions/find.rb +68 -45
  100. data/lib/capybara/selenium/extensions/html5_drag.rb +192 -22
  101. data/lib/capybara/selenium/extensions/modifier_keys_stack.rb +28 -0
  102. data/lib/capybara/selenium/extensions/scroll.rb +8 -10
  103. data/lib/capybara/selenium/node.rb +268 -72
  104. data/lib/capybara/selenium/nodes/chrome_node.rb +105 -9
  105. data/lib/capybara/selenium/nodes/edge_node.rb +110 -0
  106. data/lib/capybara/selenium/nodes/firefox_node.rb +51 -61
  107. data/lib/capybara/selenium/nodes/ie_node.rb +22 -0
  108. data/lib/capybara/selenium/nodes/safari_node.rb +118 -0
  109. data/lib/capybara/selenium/patches/atoms.rb +18 -0
  110. data/lib/capybara/selenium/patches/is_displayed.rb +16 -0
  111. data/lib/capybara/selenium/patches/logs.rb +45 -0
  112. data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -1
  113. data/lib/capybara/selenium/patches/persistent_client.rb +20 -0
  114. data/lib/capybara/server/animation_disabler.rb +43 -21
  115. data/lib/capybara/server/checker.rb +6 -2
  116. data/lib/capybara/server/middleware.rb +25 -13
  117. data/lib/capybara/server.rb +20 -4
  118. data/lib/capybara/session/config.rb +15 -11
  119. data/lib/capybara/session/matchers.rb +11 -11
  120. data/lib/capybara/session.rb +162 -131
  121. data/lib/capybara/spec/public/offset.js +6 -0
  122. data/lib/capybara/spec/public/test.js +105 -6
  123. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  124. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  125. data/lib/capybara/spec/session/all_spec.rb +89 -15
  126. data/lib/capybara/spec/session/ancestor_spec.rb +5 -0
  127. data/lib/capybara/spec/session/assert_current_path_spec.rb +5 -2
  128. data/lib/capybara/spec/session/assert_text_spec.rb +26 -22
  129. data/lib/capybara/spec/session/attach_file_spec.rb +64 -31
  130. data/lib/capybara/spec/session/check_spec.rb +26 -4
  131. data/lib/capybara/spec/session/choose_spec.rb +14 -2
  132. data/lib/capybara/spec/session/click_button_spec.rb +109 -61
  133. data/lib/capybara/spec/session/click_link_or_button_spec.rb +9 -0
  134. data/lib/capybara/spec/session/click_link_spec.rb +23 -1
  135. data/lib/capybara/spec/session/current_scope_spec.rb +1 -1
  136. data/lib/capybara/spec/session/current_url_spec.rb +11 -1
  137. data/lib/capybara/spec/session/element/matches_selector_spec.rb +40 -39
  138. data/lib/capybara/spec/session/evaluate_script_spec.rb +12 -0
  139. data/lib/capybara/spec/session/fill_in_spec.rb +46 -5
  140. data/lib/capybara/spec/session/find_link_spec.rb +10 -0
  141. data/lib/capybara/spec/session/find_spec.rb +80 -7
  142. data/lib/capybara/spec/session/first_spec.rb +2 -2
  143. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +14 -1
  144. data/lib/capybara/spec/session/frame/within_frame_spec.rb +14 -1
  145. data/lib/capybara/spec/session/has_all_selectors_spec.rb +5 -5
  146. data/lib/capybara/spec/session/has_ancestor_spec.rb +46 -0
  147. data/lib/capybara/spec/session/has_any_selectors_spec.rb +6 -2
  148. data/lib/capybara/spec/session/has_button_spec.rb +81 -0
  149. data/lib/capybara/spec/session/has_css_spec.rb +45 -8
  150. data/lib/capybara/spec/session/has_current_path_spec.rb +22 -7
  151. data/lib/capybara/spec/session/has_element_spec.rb +47 -0
  152. data/lib/capybara/spec/session/has_field_spec.rb +59 -1
  153. data/lib/capybara/spec/session/has_link_spec.rb +40 -0
  154. data/lib/capybara/spec/session/has_none_selectors_spec.rb +7 -7
  155. data/lib/capybara/spec/session/has_select_spec.rb +42 -8
  156. data/lib/capybara/spec/session/has_selector_spec.rb +19 -4
  157. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  158. data/lib/capybara/spec/session/has_table_spec.rb +177 -0
  159. data/lib/capybara/spec/session/has_text_spec.rb +31 -3
  160. data/lib/capybara/spec/session/html_spec.rb +1 -1
  161. data/lib/capybara/spec/session/matches_style_spec.rb +6 -4
  162. data/lib/capybara/spec/session/node_spec.rb +697 -23
  163. data/lib/capybara/spec/session/node_wrapper_spec.rb +1 -1
  164. data/lib/capybara/spec/session/refresh_spec.rb +2 -1
  165. data/lib/capybara/spec/session/reset_session_spec.rb +21 -7
  166. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -2
  167. data/lib/capybara/spec/session/save_page_spec.rb +4 -4
  168. data/lib/capybara/spec/session/save_screenshot_spec.rb +4 -4
  169. data/lib/capybara/spec/session/scroll_spec.rb +9 -7
  170. data/lib/capybara/spec/session/select_spec.rb +5 -10
  171. data/lib/capybara/spec/session/selectors_spec.rb +24 -3
  172. data/lib/capybara/spec/session/uncheck_spec.rb +3 -3
  173. data/lib/capybara/spec/session/unselect_spec.rb +1 -1
  174. data/lib/capybara/spec/session/visit_spec.rb +20 -0
  175. data/lib/capybara/spec/session/window/become_closed_spec.rb +20 -17
  176. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
  177. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
  178. data/lib/capybara/spec/session/window/window_spec.rb +54 -57
  179. data/lib/capybara/spec/session/window/windows_spec.rb +2 -2
  180. data/lib/capybara/spec/session/within_spec.rb +36 -0
  181. data/lib/capybara/spec/spec_helper.rb +30 -19
  182. data/lib/capybara/spec/test_app.rb +122 -34
  183. data/lib/capybara/spec/views/animated.erb +49 -0
  184. data/lib/capybara/spec/views/form.erb +86 -8
  185. data/lib/capybara/spec/views/frame_child.erb +3 -2
  186. data/lib/capybara/spec/views/frame_one.erb +2 -1
  187. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  188. data/lib/capybara/spec/views/frame_two.erb +1 -1
  189. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  190. data/lib/capybara/spec/views/layout.erb +10 -0
  191. data/lib/capybara/spec/views/obscured.erb +10 -10
  192. data/lib/capybara/spec/views/offset.erb +33 -0
  193. data/lib/capybara/spec/views/path.erb +2 -2
  194. data/lib/capybara/spec/views/popup_one.erb +1 -1
  195. data/lib/capybara/spec/views/popup_two.erb +1 -1
  196. data/lib/capybara/spec/views/react.erb +45 -0
  197. data/lib/capybara/spec/views/scroll.erb +2 -1
  198. data/lib/capybara/spec/views/spatial.erb +31 -0
  199. data/lib/capybara/spec/views/tables.erb +67 -0
  200. data/lib/capybara/spec/views/with_animation.erb +39 -4
  201. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  202. data/lib/capybara/spec/views/with_dragula.erb +24 -0
  203. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  204. data/lib/capybara/spec/views/with_hover.erb +3 -2
  205. data/lib/capybara/spec/views/with_hover1.erb +10 -0
  206. data/lib/capybara/spec/views/with_html.erb +34 -6
  207. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  208. data/lib/capybara/spec/views/with_js.erb +7 -4
  209. data/lib/capybara/spec/views/with_jstree.erb +26 -0
  210. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  211. data/lib/capybara/spec/views/with_scope.erb +2 -2
  212. data/lib/capybara/spec/views/with_scope_other.erb +6 -0
  213. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  214. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  215. data/lib/capybara/spec/views/with_sortable_js.erb +21 -0
  216. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  217. data/lib/capybara/spec/views/with_windows.erb +1 -1
  218. data/lib/capybara/spec/views/within_frames.erb +1 -1
  219. data/lib/capybara/version.rb +1 -1
  220. data/lib/capybara/window.rb +14 -18
  221. data/lib/capybara.rb +91 -126
  222. data/spec/basic_node_spec.rb +30 -16
  223. data/spec/capybara_spec.rb +40 -28
  224. data/spec/counter_spec.rb +35 -0
  225. data/spec/css_builder_spec.rb +3 -1
  226. data/spec/css_splitter_spec.rb +1 -1
  227. data/spec/dsl_spec.rb +33 -22
  228. data/spec/filter_set_spec.rb +5 -5
  229. data/spec/fixtures/selenium_driver_rspec_failure.rb +3 -3
  230. data/spec/fixtures/selenium_driver_rspec_success.rb +3 -3
  231. data/spec/minitest_spec.rb +24 -2
  232. data/spec/minitest_spec_spec.rb +60 -45
  233. data/spec/per_session_config_spec.rb +1 -1
  234. data/spec/rack_test_spec.rb +131 -98
  235. data/spec/regexp_dissassembler_spec.rb +53 -39
  236. data/spec/result_spec.rb +68 -66
  237. data/spec/rspec/features_spec.rb +9 -4
  238. data/spec/rspec/scenarios_spec.rb +6 -2
  239. data/spec/rspec/shared_spec_matchers.rb +137 -98
  240. data/spec/rspec_matchers_spec.rb +25 -0
  241. data/spec/rspec_spec.rb +23 -21
  242. data/spec/sauce_spec_chrome.rb +43 -0
  243. data/spec/selector_spec.rb +77 -21
  244. data/spec/selenium_spec_chrome.rb +141 -39
  245. data/spec/selenium_spec_chrome_remote.rb +32 -17
  246. data/spec/selenium_spec_edge.rb +36 -8
  247. data/spec/selenium_spec_firefox.rb +110 -68
  248. data/spec/selenium_spec_firefox_remote.rb +22 -15
  249. data/spec/selenium_spec_ie.rb +29 -22
  250. data/spec/selenium_spec_safari.rb +162 -0
  251. data/spec/server_spec.rb +153 -81
  252. data/spec/session_spec.rb +11 -4
  253. data/spec/shared_selenium_node.rb +79 -0
  254. data/spec/shared_selenium_session.rb +179 -74
  255. data/spec/spec_helper.rb +80 -5
  256. data/spec/whitespace_normalizer_spec.rb +54 -0
  257. data/spec/xpath_builder_spec.rb +3 -1
  258. metadata +218 -30
  259. data/lib/capybara/spec/session/source_spec.rb +0 -0
  260. data/lib/capybara/spec/views/with_title.erb +0 -5
@@ -105,7 +105,7 @@ Capybara::SpecHelper.spec '#click_link' do
105
105
 
106
106
  it "should raise an error if no link's href matched the pattern" do
107
107
  expect { @session.click_link('labore', href: /invalid_pattern/) }.to raise_error(Capybara::ElementNotFound, %r{with href matching /invalid_pattern/})
108
- expect { @session.click_link('labore', href: /.+d+/) }.to raise_error(Capybara::ElementNotFound, /#{Regexp.quote "with href matching /.+d+/"}/)
108
+ expect { @session.click_link('labore', href: /.+d+/) }.to raise_error(Capybara::ElementNotFound, /#{Regexp.quote 'with href matching /.+d+/'}/)
109
109
  end
110
110
 
111
111
  context 'href: nil' do
@@ -118,6 +118,28 @@ Capybara::SpecHelper.spec '#click_link' do
118
118
  expect { @session.click_link('Normal Anchor', href: nil) }.to raise_error(Capybara::ElementNotFound, /with no href attribute/)
119
119
  end
120
120
  end
121
+
122
+ context 'href: false' do
123
+ it 'should not raise an error on links with no href attribute' do
124
+ expect { @session.click_link('No Href', href: false) }.not_to raise_error
125
+ end
126
+
127
+ it 'should not raise an error if href attribute exists' do
128
+ expect { @session.click_link('Blank Href', href: false) }.not_to raise_error
129
+ expect { @session.click_link('Normal Anchor', href: false) }.not_to raise_error
130
+ end
131
+ end
132
+ end
133
+
134
+ context 'with :target option given' do
135
+ it 'should find links with valid target' do
136
+ @session.click_link('labore', target: '_self')
137
+ expect(@session).to have_content('Bar')
138
+ end
139
+
140
+ it "should raise error if link wasn't found" do
141
+ expect { @session.click_link('labore', target: '_blank') }.to raise_error(Capybara::ElementNotFound, /Unable to find link "labore"/)
142
+ end
121
143
  end
122
144
 
123
145
  it 'should follow relative links' do
@@ -7,7 +7,7 @@ Capybara::SpecHelper.spec '#current_scope' do
7
7
 
8
8
  context 'when not in a #within block' do
9
9
  it 'should return the document' do
10
- expect(@session.current_scope).to be_kind_of Capybara::Node::Document
10
+ expect(@session.current_scope).to be_a Capybara::Node::Document
11
11
  end
12
12
  end
13
13
 
@@ -22,7 +22,7 @@ Capybara::SpecHelper.spec '#current_url, #current_path, #current_host' do
22
22
 
23
23
  expect(@session.current_url.chomp('?')).to eq("#{scheme}://#{s.host}:#{s.port}#{path}")
24
24
  expect(@session.current_host).to eq("#{scheme}://#{s.host}") # no port
25
- expect(@session.current_path).to eq(path)
25
+ expect(@session.current_path).to eq(path.split('#')[0])
26
26
  # Server should agree with us
27
27
  expect(@session).to have_content("Current host is #{scheme}://#{s.host}:#{s.port}") if path == '/host'
28
28
  end
@@ -84,6 +84,16 @@ Capybara::SpecHelper.spec '#current_url, #current_path, #current_host' do
84
84
  should_be_on 0, '/landed'
85
85
  end
86
86
 
87
+ it 'maintains fragment' do
88
+ @session.visit("#{bases[0]}/redirect#fragment")
89
+ should_be_on 0, '/landed#fragment'
90
+ end
91
+
92
+ it 'redirects to a fragment' do
93
+ @session.visit("#{bases[0]}/redirect_with_fragment")
94
+ should_be_on 0, '/landed#with_fragment'
95
+ end
96
+
87
97
  it 'is affected by pushState', requires: [:js] do
88
98
  @session.visit('/with_js')
89
99
  @session.execute_script("window.history.pushState({}, '', '/pushed')")
@@ -1,31 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Capybara::SpecHelper.spec '#match_selector?' do
4
+ let(:element) { @session.find(:xpath, '//span', text: '42') }
5
+
4
6
  before do
5
7
  @session.visit('/with_html')
6
- @element = @session.find('//span', text: '42')
7
8
  end
8
9
 
9
10
  it 'should be true if the element matches the given selector' do
10
- expect(@element).to match_selector(:xpath, '//span')
11
- expect(@element).to match_selector(:css, 'span.number')
12
- expect(@element.matches_selector?(:css, 'span.number')).to be true
11
+ expect(element).to match_selector(:xpath, '//span')
12
+ expect(element).to match_selector(:css, 'span.number')
13
+ expect(element.matches_selector?(:css, 'span.number')).to be true
13
14
  end
14
15
 
15
16
  it 'should be false if the element does not match the given selector' do
16
- expect(@element).not_to match_selector(:xpath, '//div')
17
- expect(@element).not_to match_selector(:css, 'span.not_a_number')
18
- expect(@element.matches_selector?(:css, 'span.not_a_number')).to be false
17
+ expect(element).not_to match_selector(:xpath, '//div')
18
+ expect(element).not_to match_selector(:css, 'span.not_a_number')
19
+ expect(element.matches_selector?(:css, 'span.not_a_number')).to be false
19
20
  end
20
21
 
21
22
  it 'should use default selector' do
22
23
  Capybara.default_selector = :css
23
- expect(@element).not_to match_selector('span.not_a_number')
24
- expect(@element).to match_selector('span.number')
24
+ expect(element).not_to match_selector('span.not_a_number')
25
+ expect(element).to match_selector('span.number')
25
26
  end
26
27
 
27
28
  it 'should work with elements located via a sibling selector' do
28
- sibling = @element.sibling(:css, 'span', text: 'Other span')
29
+ sibling = element.sibling(:css, 'span', text: 'Other span')
29
30
  expect(sibling).to match_selector(:xpath, '//span')
30
31
  expect(sibling).to match_selector(:css, 'span')
31
32
  end
@@ -37,23 +38,23 @@ Capybara::SpecHelper.spec '#match_selector?' do
37
38
 
38
39
  context 'with text' do
39
40
  it 'should discard all matches where the given string is not contained' do
40
- expect(@element).to match_selector('//span', text: '42')
41
- expect(@element).not_to match_selector('//span', text: 'Doesnotexist')
41
+ expect(element).to match_selector('//span', text: '42')
42
+ expect(element).not_to match_selector('//span', text: 'Doesnotexist')
42
43
  end
43
44
  end
44
45
 
45
46
  it 'should have css sugar' do
46
- expect(@element.matches_css?('span.number')).to be true
47
- expect(@element.matches_css?('span.not_a_number')).to be false
48
- expect(@element.matches_css?('span.number', text: '42')).to be true
49
- expect(@element.matches_css?('span.number', text: 'Nope')).to be false
47
+ expect(element.matches_css?('span.number')).to be true
48
+ expect(element.matches_css?('span.not_a_number')).to be false
49
+ expect(element.matches_css?('span.number', text: '42')).to be true
50
+ expect(element.matches_css?('span.number', text: 'Nope')).to be false
50
51
  end
51
52
 
52
53
  it 'should have xpath sugar' do
53
- expect(@element.matches_xpath?('//span')).to be true
54
- expect(@element.matches_xpath?('//div')).to be false
55
- expect(@element.matches_xpath?('//span', text: '42')).to be true
56
- expect(@element.matches_xpath?('//span', text: 'Nope')).to be false
54
+ expect(element.matches_xpath?('//span')).to be true
55
+ expect(element.matches_xpath?('//div')).to be false
56
+ expect(element.matches_xpath?('//span', text: '42')).to be true
57
+ expect(element.matches_xpath?('//span', text: 'Nope')).to be false
57
58
  end
58
59
 
59
60
  it 'should accept selector filters' do
@@ -73,47 +74,47 @@ Capybara::SpecHelper.spec '#match_selector?' do
73
74
  end
74
75
 
75
76
  Capybara::SpecHelper.spec '#not_matches_selector?' do
77
+ let(:element) { @session.find(:css, 'span', text: 42) }
76
78
  before do
77
79
  @session.visit('/with_html')
78
- @element = @session.find(:css, 'span', text: 42)
79
80
  end
80
81
 
81
82
  it 'should be false if the given selector matches the element' do
82
- expect(@element).not_to not_match_selector(:xpath, '//span')
83
- expect(@element).not_to not_match_selector(:css, 'span.number')
84
- expect(@element.not_matches_selector?(:css, 'span.number')).to be false
83
+ expect(element).not_to not_match_selector(:xpath, '//span')
84
+ expect(element).not_to not_match_selector(:css, 'span.number')
85
+ expect(element.not_matches_selector?(:css, 'span.number')).to be false
85
86
  end
86
87
 
87
88
  it 'should be true if the given selector does not match the element' do
88
- expect(@element).to not_match_selector(:xpath, '//abbr')
89
- expect(@element).to not_match_selector(:css, 'p a#doesnotexist')
90
- expect(@element.not_matches_selector?(:css, 'p a#doesnotexist')).to be true
89
+ expect(element).to not_match_selector(:xpath, '//abbr')
90
+ expect(element).to not_match_selector(:css, 'p a#doesnotexist')
91
+ expect(element.not_matches_selector?(:css, 'p a#doesnotexist')).to be true
91
92
  end
92
93
 
93
94
  it 'should use default selector' do
94
95
  Capybara.default_selector = :css
95
- expect(@element).to not_match_selector('p a#doesnotexist')
96
- expect(@element).not_to not_match_selector('span.number')
96
+ expect(element).to not_match_selector('p a#doesnotexist')
97
+ expect(element).not_to not_match_selector('span.number')
97
98
  end
98
99
 
99
100
  context 'with text' do
100
101
  it 'should discard all matches where the given string is contained' do
101
- expect(@element).not_to not_match_selector(:css, 'span.number', text: '42')
102
- expect(@element).to not_match_selector(:css, 'span.number', text: 'Doesnotexist')
102
+ expect(element).not_to not_match_selector(:css, 'span.number', text: '42')
103
+ expect(element).to not_match_selector(:css, 'span.number', text: 'Doesnotexist')
103
104
  end
104
105
  end
105
106
 
106
107
  it 'should have CSS sugar' do
107
- expect(@element.not_matches_css?('span.number')).to be false
108
- expect(@element.not_matches_css?('p a#doesnotexist')).to be true
109
- expect(@element.not_matches_css?('span.number', text: '42')).to be false
110
- expect(@element.not_matches_css?('span.number', text: 'Doesnotexist')).to be true
108
+ expect(element.not_matches_css?('span.number')).to be false
109
+ expect(element.not_matches_css?('p a#doesnotexist')).to be true
110
+ expect(element.not_matches_css?('span.number', text: '42')).to be false
111
+ expect(element.not_matches_css?('span.number', text: 'Doesnotexist')).to be true
111
112
  end
112
113
 
113
114
  it 'should have xpath sugar' do
114
- expect(@element.not_matches_xpath?('//span')).to be false
115
- expect(@element.not_matches_xpath?('//div')).to be true
116
- expect(@element.not_matches_xpath?('//span', text: '42')).to be false
117
- expect(@element.not_matches_xpath?('//span', text: 'Doesnotexist')).to be true
115
+ expect(element.not_matches_xpath?('//span')).to be false
116
+ expect(element.not_matches_xpath?('//div')).to be true
117
+ expect(element.not_matches_xpath?('//span', text: '42')).to be false
118
+ expect(element.not_matches_xpath?('//span', text: 'Doesnotexist')).to be true
118
119
  end
119
120
  end
@@ -34,4 +34,16 @@ Capybara::SpecHelper.spec '#evaluate_script', requires: [:js] do
34
34
  expect(el).to be_instance_of(Capybara::Node::Element)
35
35
  expect(el).to eq(@session.find(:css, '#change'))
36
36
  end
37
+
38
+ it 'should support multi statement via IIFE' do
39
+ @session.visit('/with_js')
40
+ @session.find(:css, '#change')
41
+ el = @session.evaluate_script(<<~JS)
42
+ (function(){
43
+ var el = document.getElementById('change');
44
+ return el;
45
+ })()
46
+ JS
47
+ expect(el).to eq(@session.find(:css, '#change'))
48
+ end
37
49
  end
@@ -47,6 +47,15 @@ Capybara::SpecHelper.spec '#fill_in' do
47
47
  expect(extract_results(@session)['description']).to eq('Texty text')
48
48
  end
49
49
 
50
+ it 'should fill in a textarea in a reasonable time by default' do
51
+ textarea = @session.find(:fillable_field, 'form[description]')
52
+ value = 'a' * 4000
53
+ start = Time.now
54
+ textarea.fill_in(with: value)
55
+ expect(Time.now.to_f).to be_within(0.25).of start.to_f
56
+ expect(textarea.value).to eq value
57
+ end
58
+
50
59
  it 'should fill in a password field by id' do
51
60
  @session.fill_in('form_password', with: 'supasikrit')
52
61
  @session.click_button('awesome')
@@ -89,6 +98,38 @@ Capybara::SpecHelper.spec '#fill_in' do
89
98
  expect(extract_results(@session)['description']).to eq("\r\nSome text\r\n")
90
99
  end
91
100
 
101
+ it 'should handle carriage returns with line feeds in a textarea correctly' do
102
+ @session.fill_in('form_description', with: "\r\nSome text\r\n")
103
+ @session.click_button('awesome')
104
+ expect(extract_results(@session)['description']).to eq("\r\nSome text\r\n")
105
+ end
106
+
107
+ it 'should fill in a color field' do
108
+ @session.fill_in('Html5 Color', with: '#112233')
109
+ @session.click_button('html5_submit')
110
+ expect(extract_results(@session)['html5_color']).to eq('#112233')
111
+ end
112
+
113
+ describe 'with input[type="range"]' do
114
+ it 'should set the range slider correctly' do
115
+ @session.fill_in('form_age', with: 51)
116
+ @session.click_button('awesome')
117
+ expect(extract_results(@session)['age'].to_f).to eq 51
118
+ end
119
+
120
+ it 'should set the range slider to valid values' do
121
+ @session.fill_in('form_age', with: '37.6')
122
+ @session.click_button('awesome')
123
+ expect(extract_results(@session)['age'].to_f).to eq 37.5
124
+ end
125
+
126
+ it 'should respect the range slider limits' do
127
+ @session.fill_in('form_age', with: '3')
128
+ @session.click_button('awesome')
129
+ expect(extract_results(@session)['age'].to_f).to eq 13
130
+ end
131
+ end
132
+
92
133
  it 'should fill in a field with a custom type' do
93
134
  @session.fill_in('Schmooo', with: 'Schmooo is the game')
94
135
  @session.click_button('awesome')
@@ -178,10 +219,10 @@ Capybara::SpecHelper.spec '#fill_in' do
178
219
  it 'should only trigger onchange once' do
179
220
  @session.visit('/with_js')
180
221
  # Click somewhere on the page to ensure focus is acquired. Without this FF won't generate change events for some reason???
181
- @session.find(:css, 'body').click
222
+ @session.find(:css, 'h1', text: 'FooBar').click
182
223
  @session.fill_in('with_change_event', with: 'some value')
183
224
  # click outside the field to trigger the change event
184
- @session.find(:css, 'body').click
225
+ @session.find(:css, 'h1', text: 'FooBar').click
185
226
  expect(@session.find(:css, '.change_event_triggered', match: :one)).to have_text 'some value'
186
227
  end
187
228
 
@@ -189,7 +230,7 @@ Capybara::SpecHelper.spec '#fill_in' do
189
230
  @session.visit('/with_js')
190
231
  @session.fill_in('with_change_event', with: '')
191
232
  # click outside the field to trigger the change event
192
- @session.find(:css, 'body').click
233
+ @session.find(:css, 'h1', text: 'FooBar').click
193
234
  expect(@session).to have_selector(:css, '.change_event_triggered', match: :one)
194
235
  end
195
236
  end
@@ -200,7 +241,7 @@ Capybara::SpecHelper.spec '#fill_in' do
200
241
  after { Capybara.ignore_hidden_elements = false }
201
242
 
202
243
  it 'should not find a hidden field' do
203
- msg = 'Unable to find visible field "Super Secret"'
244
+ msg = /Unable to find visible field "Super Secret"/
204
245
  expect do
205
246
  @session.fill_in('Super Secret', with: '777')
206
247
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -209,7 +250,7 @@ Capybara::SpecHelper.spec '#fill_in' do
209
250
 
210
251
  context "with a locator that doesn't exist" do
211
252
  it 'should raise an error' do
212
- msg = 'Unable to find field "does not exist"'
253
+ msg = /Unable to find field "does not exist"/
213
254
  expect do
214
255
  @session.fill_in('does not exist', with: 'Blah blah')
215
256
  end.to raise_error(Capybara::ElementNotFound, msg)
@@ -67,4 +67,14 @@ Capybara::SpecHelper.spec '#find_link' do
67
67
  expect { @session.find_link(download: 37) }.to raise_error ArgumentError
68
68
  end
69
69
  end
70
+
71
+ context 'with :target option' do
72
+ it 'should accept partial matches when false' do
73
+ expect(@session.find_link(target: '_self').text).to eq('labore')
74
+ end
75
+
76
+ it 'should not accept partial matches when true' do
77
+ expect { @session.find_link(target: '_blank') }.to raise_error Capybara::ElementNotFound
78
+ end
79
+ end
70
80
  end
@@ -107,8 +107,8 @@ Capybara::SpecHelper.spec '#find' do
107
107
  end
108
108
 
109
109
  it 'should warn if passed a non-valid locator type' do
110
- expect_any_instance_of(Kernel).to receive(:warn).with(/must respond to to_xpath or be an instance of String/)
111
- expect { @session.find(:xpath, 123) }.to raise_error # rubocop:disable RSpec/UnspecifiedException
110
+ expect { @session.find(:xpath, 123) }.to raise_error(Exception) # The exact error is not yet well defined
111
+ .and output(/must respond to to_xpath or be an instance of String/).to_stderr
112
112
  end
113
113
  end
114
114
 
@@ -233,10 +233,18 @@ Capybara::SpecHelper.spec '#find' do
233
233
  end.to raise_error(Capybara::ElementNotFound, 'Unable to find xpath "//div[@id=\\"nosuchthing\\"]"')
234
234
  end
235
235
 
236
+ context 'without locator' do
237
+ it 'should not output `nil` in the ElementNotFound message if nothing was found' do
238
+ expect do
239
+ @session.find(:label, text: 'no such thing').to be_nil
240
+ end.to raise_error(Capybara::ElementNotFound, 'Unable to find label')
241
+ end
242
+ end
243
+
236
244
  it 'should accept an XPath instance' do
237
245
  @session.visit('/form')
238
- @xpath = Capybara::Selector[:fillable_field].call('First Name')
239
- expect(@xpath).to be_a(::XPath::Union)
246
+ @xpath = Capybara::Selector.new(:fillable_field, config: {}, format: :xpath).call('First Name')
247
+ expect(@xpath).to be_a(XPath::Union)
240
248
  expect(@session.find(@xpath).value).to eq('John')
241
249
  end
242
250
 
@@ -263,9 +271,8 @@ Capybara::SpecHelper.spec '#find' do
263
271
  end
264
272
 
265
273
  it 'warns when the option has no effect' do
266
- expect_any_instance_of(Kernel).to receive(:warn)
267
- .with('The :exact option only has an effect on queries using the XPath#is method. Using it with the query "#test_field" has no effect.')
268
- @session.find(:css, '#test_field', exact: true)
274
+ expect { @session.find(:css, '#test_field', exact: true) }.to \
275
+ output(/^The :exact option only has an effect on queries using the XPath#is method. Using it with the query "#test_field" has no effect/).to_stderr
269
276
  end
270
277
  end
271
278
 
@@ -276,14 +283,17 @@ Capybara::SpecHelper.spec '#find' do
276
283
  @session.find(:css, '.multiple', match: :one)
277
284
  end.to raise_error(Capybara::Ambiguous)
278
285
  end
286
+
279
287
  it 'raises an error even if there the match is exact and the others are inexact' do
280
288
  expect do
281
289
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], exact: false, match: :one)
282
290
  end.to raise_error(Capybara::Ambiguous)
283
291
  end
292
+
284
293
  it 'returns the element if there is only one' do
285
294
  expect(@session.find(:css, '.singular', match: :one).text).to eq('singular')
286
295
  end
296
+
287
297
  it 'raises an error if there is no match' do
288
298
  expect do
289
299
  @session.find(:css, '.does-not-exist', match: :one)
@@ -295,6 +305,7 @@ Capybara::SpecHelper.spec '#find' do
295
305
  it 'returns the first matched element' do
296
306
  expect(@session.find(:css, '.multiple', match: :first).text).to eq('multiple one')
297
307
  end
308
+
298
309
  it 'raises an error if there is no match' do
299
310
  expect do
300
311
  @session.find(:css, '.does-not-exist', match: :first)
@@ -309,19 +320,23 @@ Capybara::SpecHelper.spec '#find' do
309
320
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :smart, exact: false)
310
321
  end.to raise_error(Capybara::Ambiguous)
311
322
  end
323
+
312
324
  it 'finds a single exact match when there also are inexact matches' do
313
325
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], match: :smart, exact: false)
314
326
  expect(result.text).to eq('almost singular')
315
327
  end
328
+
316
329
  it 'raises an error when there are multiple inexact matches' do
317
330
  expect do
318
331
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :smart, exact: false)
319
332
  end.to raise_error(Capybara::Ambiguous)
320
333
  end
334
+
321
335
  it 'finds a single inexact match' do
322
336
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :smart, exact: false)
323
337
  expect(result.text).to eq('almost singular but not quite')
324
338
  end
339
+
325
340
  it 'raises an error if there is no match' do
326
341
  expect do
327
342
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :smart, exact: false)
@@ -335,20 +350,24 @@ Capybara::SpecHelper.spec '#find' do
335
350
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :smart, exact: true)
336
351
  end.to raise_error(Capybara::Ambiguous)
337
352
  end
353
+
338
354
  it 'finds a single exact match when there also are inexact matches' do
339
355
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], match: :smart, exact: true)
340
356
  expect(result.text).to eq('almost singular')
341
357
  end
358
+
342
359
  it 'raises an error when there are multiple inexact matches' do
343
360
  expect do
344
361
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :smart, exact: true)
345
362
  end.to raise_error(Capybara::ElementNotFound)
346
363
  end
364
+
347
365
  it 'raises an error when there is a single inexact matches' do
348
366
  expect do
349
367
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :smart, exact: true)
350
368
  end.to raise_error(Capybara::ElementNotFound)
351
369
  end
370
+
352
371
  it 'raises an error if there is no match' do
353
372
  expect do
354
373
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :smart, exact: true)
@@ -363,18 +382,22 @@ Capybara::SpecHelper.spec '#find' do
363
382
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :prefer_exact, exact: false)
364
383
  expect(result.text).to eq('multiple one')
365
384
  end
385
+
366
386
  it 'finds a single exact match when there also are inexact matches' do
367
387
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], match: :prefer_exact, exact: false)
368
388
  expect(result.text).to eq('almost singular')
369
389
  end
390
+
370
391
  it 'picks the first one when there are multiple inexact matches' do
371
392
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :prefer_exact, exact: false)
372
393
  expect(result.text).to eq('almost singular but not quite')
373
394
  end
395
+
374
396
  it 'finds a single inexact match' do
375
397
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :prefer_exact, exact: false)
376
398
  expect(result.text).to eq('almost singular but not quite')
377
399
  end
400
+
378
401
  it 'raises an error if there is no match' do
379
402
  expect do
380
403
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :prefer_exact, exact: false)
@@ -387,20 +410,24 @@ Capybara::SpecHelper.spec '#find' do
387
410
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('multiple')], match: :prefer_exact, exact: true)
388
411
  expect(result.text).to eq('multiple one')
389
412
  end
413
+
390
414
  it 'finds a single exact match when there also are inexact matches' do
391
415
  result = @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular')], match: :prefer_exact, exact: true)
392
416
  expect(result.text).to eq('almost singular')
393
417
  end
418
+
394
419
  it 'raises an error if there are multiple inexact matches' do
395
420
  expect do
396
421
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singul')], match: :prefer_exact, exact: true)
397
422
  end.to raise_error(Capybara::ElementNotFound)
398
423
  end
424
+
399
425
  it 'raises an error if there is a single inexact match' do
400
426
  expect do
401
427
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('almost_singular but')], match: :prefer_exact, exact: true)
402
428
  end.to raise_error(Capybara::ElementNotFound)
403
429
  end
430
+
404
431
  it 'raises an error if there is no match' do
405
432
  expect do
406
433
  @session.find(:xpath, XPath.descendant[XPath.attr(:class).is('does-not-exist')], match: :prefer_exact, exact: true)
@@ -429,6 +456,41 @@ Capybara::SpecHelper.spec '#find' do
429
456
  expect(@session.find(:css, 'input', &:disabled?)[:name]).to eq('disabled_text')
430
457
  end
431
458
 
459
+ context 'with spatial filters', requires: [:spatial] do
460
+ before do
461
+ @session.visit('/spatial')
462
+ end
463
+
464
+ let :center do
465
+ @session.find(:css, 'div.center')
466
+ end
467
+
468
+ it 'should find an element above another element' do
469
+ expect(@session.find(:css, 'div:not(.corner)', above: center).text).to eq('2')
470
+ end
471
+
472
+ it 'should find an element below another element' do
473
+ expect(@session.find(:css, 'div:not(.corner):not(.footer)', below: center).text).to eq('8')
474
+ end
475
+
476
+ it 'should find an element left of another element' do
477
+ expect(@session.find(:css, 'div:not(.corner)', left_of: center).text).to eq('4')
478
+ end
479
+
480
+ it 'should find an element right of another element' do
481
+ expect(@session.find(:css, 'div:not(.corner)', right_of: center).text).to eq('6')
482
+ end
483
+
484
+ it 'should combine spatial filters' do
485
+ expect(@session.find(:css, 'div', left_of: center, above: center).text).to eq('1')
486
+ expect(@session.find(:css, 'div', right_of: center, below: center).text).to eq('9')
487
+ end
488
+
489
+ it 'should find an element "near" another element' do
490
+ expect(@session.find(:css, 'div.distance', near: center).text).to eq('2')
491
+ end
492
+ end
493
+
432
494
  context 'within a scope' do
433
495
  before do
434
496
  @session.visit('/with_scope')
@@ -468,5 +530,16 @@ Capybara::SpecHelper.spec '#find' do
468
530
  Capybara.test_id = 'data-other-test-id'
469
531
  expect(@session.find(:field, 'test_id')[:id]).to eq 'normal'
470
532
  end
533
+
534
+ it 'should find a link with the test_id' do
535
+ Capybara.test_id = 'data-test-id'
536
+ expect(@session.find(:link, 'test-foo')[:id]).to eq 'foo'
537
+ end
538
+ end
539
+
540
+ it 'should warn if passed count options' do
541
+ allow(Capybara::Helpers).to receive(:warn)
542
+ @session.find('//h1', count: 44)
543
+ expect(Capybara::Helpers).to have_received(:warn).with(/'find' does not support count options/)
471
544
  end
472
545
  end
@@ -24,8 +24,8 @@ Capybara::SpecHelper.spec '#first' do
24
24
 
25
25
  it 'should accept an XPath instance' do
26
26
  @session.visit('/form')
27
- @xpath = Capybara::Selector[:fillable_field].call('First Name')
28
- expect(@xpath).to be_a(::XPath::Union)
27
+ @xpath = Capybara::Selector.new(:fillable_field, config: {}, format: :xpath).call('First Name')
28
+ expect(@xpath).to be_a(XPath::Union)
29
29
  expect(@session.first(@xpath).value).to eq('John')
30
30
  end
31
31
 
@@ -53,7 +53,20 @@ Capybara::SpecHelper.spec '#switch_to_frame', requires: [:frames] do
53
53
  @session.switch_to_frame frame
54
54
  frame = @session.find(:frame, 'childFrame')
55
55
  @session.switch_to_frame frame
56
- @session.click_link 'Close Window'
56
+ @session.click_link 'Close Window Now'
57
+ @session.switch_to_frame :parent # Go back to parentFrame
58
+ expect(@session).to have_selector(:css, 'body#parentBody')
59
+ expect(@session).not_to have_selector(:css, '#childFrame')
60
+ @session.switch_to_frame :parent # Go back to top
61
+ end
62
+
63
+ it 'works if the frame is closed with a slight delay', requires: %i[frames js] do
64
+ frame = @session.find(:frame, 'parentFrame')
65
+ @session.switch_to_frame frame
66
+ frame = @session.find(:frame, 'childFrame')
67
+ @session.switch_to_frame frame
68
+ @session.click_link 'Close Window Soon'
69
+ sleep 1
57
70
  @session.switch_to_frame :parent # Go back to parentFrame
58
71
  expect(@session).to have_selector(:css, 'body#parentBody')
59
72
  expect(@session).not_to have_selector(:css, '#childFrame')
@@ -64,7 +64,9 @@ Capybara::SpecHelper.spec '#within_frame', requires: [:frames] do
64
64
  end
65
65
  expect do
66
66
  # Multiple frames in scope here
67
+ # rubocop:disable Style/Semicolon
67
68
  @session.within_frame { ; }
69
+ # rubocop:enable Style/Semicolon
68
70
  end.to raise_error Capybara::Ambiguous
69
71
  end
70
72
 
@@ -92,7 +94,18 @@ Capybara::SpecHelper.spec '#within_frame', requires: [:frames] do
92
94
  it 'works if the frame is closed', requires: %i[frames js] do
93
95
  @session.within_frame 'parentFrame' do
94
96
  @session.within_frame 'childFrame' do
95
- @session.click_link 'Close Window'
97
+ @session.click_link 'Close Window Now'
98
+ end
99
+ expect(@session).to have_selector(:css, 'body#parentBody')
100
+ expect(@session).not_to have_selector(:css, '#childFrame')
101
+ end
102
+ end
103
+
104
+ it 'works if the frame is closed with a slight delay', requires: %i[frames js] do
105
+ @session.within_frame 'parentFrame' do
106
+ @session.within_frame 'childFrame' do
107
+ @session.click_link 'Close Window Soon'
108
+ sleep 1
96
109
  end
97
110
  expect(@session).to have_selector(:css, 'body#parentBody')
98
111
  expect(@session).not_to have_selector(:css, '#childFrame')