capybara 3.20.1 → 3.22.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/History.md +35 -0
  4. data/README.md +16 -11
  5. data/lib/capybara/driver/node.rb +6 -2
  6. data/lib/capybara/helpers.rb +1 -1
  7. data/lib/capybara/minitest/spec.rb +20 -7
  8. data/lib/capybara/minitest.rb +18 -5
  9. data/lib/capybara/node/actions.rb +36 -29
  10. data/lib/capybara/node/element.rb +123 -82
  11. data/lib/capybara/node/finders.rb +42 -53
  12. data/lib/capybara/node/matchers.rb +161 -72
  13. data/lib/capybara/queries/ancestor_query.rb +9 -7
  14. data/lib/capybara/queries/sibling_query.rb +11 -4
  15. data/lib/capybara/result.rb +2 -0
  16. data/lib/capybara/rspec/matchers/have_ancestor.rb +30 -0
  17. data/lib/capybara/rspec/matchers/have_sibling.rb +30 -0
  18. data/lib/capybara/rspec/matchers.rb +16 -1
  19. data/lib/capybara/selector/definition/checkbox.rb +8 -5
  20. data/lib/capybara/selector/definition/css.rb +4 -1
  21. data/lib/capybara/selector/definition/radio_button.rb +8 -5
  22. data/lib/capybara/selector/filter_set.rb +4 -2
  23. data/lib/capybara/selector/regexp_disassembler.rb +2 -2
  24. data/lib/capybara/selector.rb +153 -171
  25. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +35 -1
  26. data/lib/capybara/selenium/extensions/html5_drag.rb +63 -0
  27. data/lib/capybara/selenium/node.rb +4 -0
  28. data/lib/capybara/selenium/nodes/chrome_node.rb +4 -0
  29. data/lib/capybara/selenium/nodes/firefox_node.rb +4 -13
  30. data/lib/capybara/selenium/nodes/ie_node.rb +14 -3
  31. data/lib/capybara/selenium/nodes/safari_node.rb +0 -13
  32. data/lib/capybara/session/config.rb +1 -1
  33. data/lib/capybara/session.rb +74 -71
  34. data/lib/capybara/spec/public/test.js +29 -3
  35. data/lib/capybara/spec/session/attach_file_spec.rb +13 -5
  36. data/lib/capybara/spec/session/check_spec.rb +6 -0
  37. data/lib/capybara/spec/session/choose_spec.rb +6 -0
  38. data/lib/capybara/spec/session/has_ancestor_spec.rb +44 -0
  39. data/lib/capybara/spec/session/has_css_spec.rb +4 -3
  40. data/lib/capybara/spec/session/has_sibling_spec.rb +50 -0
  41. data/lib/capybara/spec/session/node_spec.rb +85 -0
  42. data/lib/capybara/spec/session/select_spec.rb +5 -5
  43. data/lib/capybara/spec/spec_helper.rb +4 -0
  44. data/lib/capybara/spec/views/form.erb +1 -1
  45. data/lib/capybara/version.rb +1 -1
  46. data/lib/capybara/window.rb +10 -10
  47. data/lib/capybara.rb +42 -36
  48. data/spec/minitest_spec.rb +11 -1
  49. data/spec/minitest_spec_spec.rb +11 -1
  50. data/spec/regexp_dissassembler_spec.rb +1 -1
  51. data/spec/selenium_spec_firefox.rb +2 -0
  52. data/spec/selenium_spec_ie.rb +13 -7
  53. data/spec/selenium_spec_safari.rb +2 -0
  54. data/spec/shared_selenium_session.rb +1 -51
  55. metadata +23 -18
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ Capybara::SpecHelper.spec '#have_sibling' do
4
+ before do
5
+ @session.visit('/with_html')
6
+ end
7
+
8
+ it 'should assert a prior sibling element using the given locator' do
9
+ el = @session.find(:css, '#mid_sibling')
10
+ expect(el).to have_sibling(:css, '#pre_sibling')
11
+ end
12
+
13
+ it 'should assert a following sibling element using the given locator' do
14
+ el = @session.find(:css, '#mid_sibling')
15
+ expect(el).to have_sibling(:css, '#post_sibling')
16
+ end
17
+
18
+ it 'should not raise an error if there are multiple matches' do
19
+ el = @session.find(:css, '#mid_sibling')
20
+ expect(el).to have_sibling(:css, 'div')
21
+ end
22
+
23
+ it 'should allow counts to be specified' do
24
+ el = @session.find(:css, '#mid_sibling')
25
+
26
+ expect(el).to have_sibling(:css, 'div').exactly(2).times
27
+ expect do
28
+ expect(el).to have_sibling(:css, 'div').once
29
+ end.to raise_error(RSpec::Expectations::ExpectationNotMetError)
30
+ end
31
+ end
32
+
33
+ Capybara::SpecHelper.spec '#have_no_sibling' do
34
+ before do
35
+ @session.visit('/with_html')
36
+ end
37
+
38
+ it 'should assert no matching sibling' do
39
+ el = @session.find(:css, '#mid_sibling')
40
+ expect(el).to have_no_sibling(:css, '#not_a_sibling')
41
+ expect(el).not_to have_sibling(:css, '#not_a_sibling')
42
+ end
43
+
44
+ it 'should raise if there are matching siblings' do
45
+ el = @session.find(:css, '#mid_sibling')
46
+ expect do
47
+ expect(el).to have_no_sibling(:css, '#pre_sibling')
48
+ end.to raise_error(RSpec::Expectations::ExpectationNotMetError)
49
+ end
50
+ end
@@ -242,6 +242,10 @@ Capybara::SpecHelper.spec 'node' do
242
242
  expect(@session.find('//div[@id="hidden_attr"]')).not_to be_visible
243
243
  expect(@session.find('//a[@id="hidden_attr_via_ancestor"]')).not_to be_visible
244
244
  expect(@session.find('//input[@id="hidden_input"]')).not_to be_visible
245
+ end
246
+
247
+ it 'template elements should not be visible' do
248
+ Capybara.ignore_hidden_elements = false
245
249
  expect(@session.find('//template')).not_to be_visible
246
250
  end
247
251
 
@@ -414,6 +418,87 @@ Capybara::SpecHelper.spec 'node' do
414
418
  link.drag_to target
415
419
  expect(@session).to have_xpath('//div[contains(., "Dropped!")]')
416
420
  end
421
+
422
+ context 'HTML5', requires: %i[js html5_drag] do
423
+ it 'should HTML5 drag and drop an object' do
424
+ @session.visit('/with_js')
425
+ element = @session.find('//div[@id="drag_html5"]')
426
+ target = @session.find('//div[@id="drop_html5"]')
427
+ element.drag_to(target)
428
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5")]')
429
+ end
430
+
431
+ it 'should set clientX/Y in dragover events' do
432
+ @session.visit('/with_js')
433
+ element = @session.find('//div[@id="drag_html5"]')
434
+ target = @session.find('//div[@id="drop_html5"]')
435
+ element.drag_to(target)
436
+ expect(@session).to have_css('div.log', text: /DragOver with client position: [1-9]\d*,[1-9]\d*/, count: 2)
437
+ end
438
+
439
+ it 'should not HTML5 drag and drop on a non HTML5 drop element' do
440
+ @session.visit('/with_js')
441
+ element = @session.find('//div[@id="drag_html5"]')
442
+ target = @session.find('//div[@id="drop_html5"]')
443
+ target.execute_script("$(this).removeClass('drop');")
444
+ element.drag_to(target)
445
+ sleep 1
446
+ expect(@session).not_to have_xpath('//div[contains(., "HTML5 Dropped")]')
447
+ end
448
+
449
+ it 'should HTML5 drag and drop when scrolling needed' do
450
+ @session.visit('/with_js')
451
+ element = @session.find('//div[@id="drag_html5_scroll"]')
452
+ target = @session.find('//div[@id="drop_html5_scroll"]')
453
+ element.drag_to(target)
454
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain drag_html5_scroll")]')
455
+ end
456
+
457
+ it 'should drag HTML5 default draggable elements' do
458
+ @session.visit('/with_js')
459
+ link = @session.find_link('drag_link_html5')
460
+ target = @session.find(:id, 'drop_html5')
461
+ link.drag_to target
462
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
463
+ end
464
+ end
465
+ end
466
+
467
+ describe 'Element#drop', requires: %i[js html5_drag] do
468
+ it 'can drop a file' do
469
+ @session.visit('/with_js')
470
+ target = @session.find('//div[@id="drop_html5"]')
471
+ target.drop(
472
+ with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__)))
473
+ )
474
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
475
+ end
476
+
477
+ it 'can drop multiple files' do
478
+ @session.visit('/with_js')
479
+ target = @session.find('//div[@id="drop_html5"]')
480
+ target.drop(
481
+ with_os_path_separators(File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__))),
482
+ with_os_path_separators(File.expand_path('../fixtures/test_file.txt', File.dirname(__FILE__)))
483
+ )
484
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: capybara.jpg")]')
485
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped file: test_file.txt")]')
486
+ end
487
+
488
+ it 'can drop strings' do
489
+ @session.visit('/with_js')
490
+ target = @session.find('//div[@id="drop_html5"]')
491
+ target.drop('text/plain' => 'Some dropped text')
492
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain Some dropped text")]')
493
+ end
494
+
495
+ it 'can drop multiple strings' do
496
+ @session.visit('/with_js')
497
+ target = @session.find('//div[@id="drop_html5"]')
498
+ target.drop('text/plain' => 'Some dropped text', 'text/url' => 'http://www.google.com')
499
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/plain Some dropped text")]')
500
+ expect(@session).to have_xpath('//div[contains(., "HTML5 Dropped string: text/url http://www.google.com")]')
501
+ end
417
502
  end
418
503
 
419
504
  describe '#hover', requires: [:hover] do
@@ -42,13 +42,13 @@ Capybara::SpecHelper.spec '#select' do
42
42
  end
43
43
 
44
44
  it 'should select an option from a select box by id' do
45
- @session.select('Finish', from: 'form_locale')
45
+ @session.select('Finnish', from: 'form_locale')
46
46
  @session.click_button('awesome')
47
47
  expect(extract_results(@session)['locale']).to eq('fi')
48
48
  end
49
49
 
50
50
  it 'should select an option from a select box by label' do
51
- @session.select('Finish', from: 'Locale')
51
+ @session.select('Finnish', from: 'Locale')
52
52
  @session.click_button('awesome')
53
53
  expect(extract_results(@session)['locale']).to eq('fi')
54
54
  end
@@ -183,7 +183,7 @@ Capybara::SpecHelper.spec '#select' do
183
183
  context 'with :exact option' do
184
184
  context 'when `false`' do
185
185
  it 'can match select box approximately' do
186
- @session.select('Finish', from: 'Loc', exact: false)
186
+ @session.select('Finnish', from: 'Loc', exact: false)
187
187
  @session.click_button('awesome')
188
188
  expect(extract_results(@session)['locale']).to eq('fi')
189
189
  end
@@ -204,13 +204,13 @@ Capybara::SpecHelper.spec '#select' do
204
204
  context 'when `true`' do
205
205
  it 'can match select box approximately' do
206
206
  expect do
207
- @session.select('Finish', from: 'Loc', exact: true)
207
+ @session.select('Finnish', from: 'Loc', exact: true)
208
208
  end.to raise_error(Capybara::ElementNotFound)
209
209
  end
210
210
 
211
211
  it 'can match option approximately' do
212
212
  expect do
213
- @session.select('Fin', from: 'Locale', exact: true)
213
+ @session.select('Fin', from: 'Locale', exact: true)
214
214
  end.to raise_error(Capybara::ElementNotFound)
215
215
  end
216
216
 
@@ -124,6 +124,10 @@ module Capybara
124
124
  def be_an_invalid_element_error(session)
125
125
  satisfy { |error| session.driver.invalid_element_errors.any? { |e| error.is_a? e } }
126
126
  end
127
+
128
+ def with_os_path_separators(path)
129
+ Gem.win_platform? ? path.to_s.tr('/', '\\') : path.to_s
130
+ end
127
131
  end
128
132
  end
129
133
 
@@ -108,7 +108,7 @@
108
108
  <select name="form[locale]" id="form_locale">
109
109
  <option value="sv">Swedish</option>
110
110
  <option selected="selected" value="en">English</option>
111
- <option value="fi">Finish</option>
111
+ <option value="fi">Finnish</option>
112
112
  <option value="no">Norwegian</option>
113
113
  <option value="jo">John's made-up language</option>
114
114
  <option value="jbo"> Lojban </option>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Capybara
4
- VERSION = '3.20.1'
4
+ VERSION = '3.22.0'
5
5
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Capybara
4
4
  ##
5
- # The Window class represents a browser window.
5
+ # The {Window} class represents a browser window.
6
6
  #
7
7
  # You can get an instance of the class by calling either of:
8
8
  #
@@ -12,12 +12,12 @@ module Capybara
12
12
  # * {Capybara::Session#switch_to_window}
13
13
  #
14
14
  # Note that some drivers (e.g. Selenium) support getting size of/resizing/closing only
15
- # current window. So if you invoke such method for:
15
+ # current window. So if you invoke such method for:
16
16
  #
17
- # * window that is current, Capybara will make 2 Selenium method invocations
18
- # (get handle of current window + get size/resize/close).
19
- # * window that is not current, Capybara will make 4 Selenium method invocations
20
- # (get handle of current window + switch to given handle + get size/resize/close + switch to original handle)
17
+ # * window that is current, Capybara will make 2 Selenium method invocations
18
+ # (get handle of current window + get size/resize/close).
19
+ # * window that is not current, Capybara will make 4 Selenium method invocations
20
+ # (get handle of current window + switch to given handle + get size/resize/close + switch to original handle)
21
21
  #
22
22
  class Window
23
23
  # @return [String] a string that uniquely identifies window within session
@@ -57,12 +57,12 @@ module Capybara
57
57
  # Close window.
58
58
  #
59
59
  # If this method was called for window that is current, then after calling this method
60
- # future invocations of other Capybara methods should raise
61
- # `session.driver.no_such_window_error` until another window will be switched to.
60
+ # future invocations of other Capybara methods should raise
61
+ # {Capybara::Driver::Base#no_such_window_error session.driver.no_such_window_error} until another window will be switched to.
62
62
  #
63
63
  # @!macro about_current
64
64
  # If this method was called for window that is not current, then after calling this method
65
- # current window shouldn remain the same as it was before calling this method.
65
+ # current window should remain the same as it was before calling this method.
66
66
  #
67
67
  def close
68
68
  @driver.close_window(handle)
@@ -93,7 +93,7 @@ module Capybara
93
93
  # Maximize window.
94
94
  #
95
95
  # If a particular driver (e.g. headless driver) doesn't have concept of maximizing it
96
- # may not support this method.
96
+ # may not support this method.
97
97
  #
98
98
  # @macro about_current
99
99
  #
data/lib/capybara.rb CHANGED
@@ -66,36 +66,44 @@ module Capybara
66
66
  # config.app_host = 'http://www.google.com'
67
67
  # end
68
68
  #
69
- # === Configurable options
70
- #
71
- # [app_host = String/nil] The default host to use when giving a relative URL to visit, must be a valid URL e.g. http://www.example.com
72
- # [always_include_port = Boolean] Whether the Rack server's port should automatically be inserted into every visited URL unless another port is explicitly specified (Default: false)
73
- # [asset_host = String] Where dynamic assets are hosted - will be prepended to relative asset locations if present (Default: nil)
74
- # [run_server = Boolean] Whether to start a Rack server for the given Rack app (Default: true)
75
- # [raise_server_errors = Boolean] Should errors raised in the server be raised in the tests? (Default: true)
76
- # [server_errors = Array\<Class\>] Error classes that should be raised in the tests if they are raised in the server and Capybara.raise_server_errors is true (Default: [Exception])
77
- # [default_selector = :css/:xpath] Methods which take a selector use the given type by default (Default: :css)
78
- # [default_max_wait_time = Numeric] The maximum number of seconds to wait for asynchronous processes to finish (Default: 2)
79
- # [ignore_hidden_elements = Boolean] Whether to ignore hidden elements on the page (Default: true)
80
- # [automatic_reload = Boolean] Whether to automatically reload elements as Capybara is waiting (Default: true)
81
- # [save_path = String] Where to put pages saved through save_(page|screenshot), save_and_open_(page|screenshot) (Default: Dir.pwd)
82
- # [automatic_label_click = Boolean] Whether Node#choose, Node#check, Node#uncheck will attempt to click the associated label element if the checkbox/radio button are non-visible (Default: false)
83
- # [enable_aria_label = Boolean] Whether fields, links, and buttons will match against aria-label attribute (Default: false)
84
- # [reuse_server = Boolean] Reuse the server thread between multiple sessions using the same app object (Default: true)
85
- # [threadsafe = Boolean] Whether sessions can be configured individually (Default: false)
86
- # [server = Symbol] The name of the registered server to use when running the app under test (Default: :webrick)
87
- # [default_set_options = Hash] The default options passed to Node::set (Default: {})
88
- # [test_id = Symbol/String/nil] Optional attribute to match locator aginst with builtin selectors along with id (Default: nil)
89
- # [predicates_wait = Boolean] Whether Capybaras predicate matchers use waiting behavior by default (Default: true)
90
- # [default_normalize_ws = Boolean] Whether text predicates and matchers use normalize whitespace behaviour (Default: false)
91
- # [allow_gumbo = Boolean] When `nokogumbo` is available, whether it will be used to parse HTML strings (Default: false)
92
- #
93
- # === DSL Options
94
- #
95
- # when using capybara/dsl, the following options are also available:
96
- #
97
- # [default_driver = Symbol] The name of the driver to use by default. (Default: :rack_test)
98
- # [javascript_driver = Symbol] The name of a driver to use for JavaScript enabled tests. (Default: :selenium)
69
+ # #### Configurable options
70
+ #
71
+ # - **allow_gumbo** (Boolean = `false`) - When `nokogumbo` is available, whether it will be used to parse HTML strings.
72
+ # - **always_include_port** (Boolean = `false`) - Whether the Rack server's port should automatically be inserted into every visited URL
73
+ # unless another port is explicitly specified.
74
+ # - **app_host** (String, `nil`) - The default host to use when giving a relative URL to visit, must be a valid URL e.g. `http://www.example.com`.
75
+ # - **asset_host** (String = `nil`) - Where dynamic assets are hosted - will be prepended to relative asset locations if present.
76
+ # - **automatic_label_click** (Boolean = `false`) - Whether {Capybara::Node::Element#choose Element#choose}, {Capybara::Node::Element#check Element#check},
77
+ # {Capybara::Node::Element#uncheck Element#uncheck} will attempt to click the associated `<label>` element if the checkbox/radio button are non-visible.
78
+ # - **automatic_reload** (Boolean = `true`) - Whether to automatically reload elements as Capybara is waiting.
79
+ # - **default_max_wait_time** (Numeric = `2`) - The maximum number of seconds to wait for asynchronous processes to finish.
80
+ # - **default_normalize_ws** (Boolean = `false`) - Whether text predicates and matchers use normalize whitespace behavior.
81
+ # - **default_selector** (`:css`, `:xpath` = `:css`) - Methods which take a selector use the given type by default. See also {Capybara::Selector}.
82
+ # - **default_set_options** (Hash = `{}`) - The default options passed to {Capybara::Node::Element#set Element#set}.
83
+ # - **enable_aria_label** (Boolean = `false`) - Whether fields, links, and buttons will match against `aria-label` attribute.
84
+ # - **exact** (Boolean = `false`) - Whether locators are matched exactly or with substrings. Only affects selector conditions
85
+ # written using the `XPath#is` method.
86
+ # - **exact_text** (Boolean = `false`) - Whether the text matchers and `:text` filter match exactly or on substrings.
87
+ # - **ignore_hidden_elements** (Boolean = `true`) - Whether to ignore hidden elements on the page.
88
+ # - **match** (`:one`, `:first`, `:prefer_exact`, `:smart` = `:smart`) - The matching strategy to find nodes.
89
+ # - **predicates_wait** (Boolean = `true`) - Whether Capybara's predicate matchers use waiting behavior by default.
90
+ # - **raise_server_errors** (Boolean = `true`) - Should errors raised in the server be raised in the tests?
91
+ # - **reuse_server** (Boolean = `true`) - Whether to reuse the server thread between multiple sessions using the same app object.
92
+ # - **run_server** (Boolean = `true`) - Whether to start a Rack server for the given Rack app.
93
+ # - **save_path** (String = `Dir.pwd`) - Where to put pages saved through {Capybara::Session#save_page save_page}, {Capybara::Session#save_screenshot save_screenshot},
94
+ # {Capybara::Session#save_and_open_page save_and_open_page}, or {Capybara::Session#save_and_open_screenshot save_and_open_screenshot}.
95
+ # - **server** (Symbol = `:default` (which uses puma)) - The name of the registered server to use when running the app under test.
96
+ # - **server_errors** (Array\<Class> = `[Exception]`) - Error classes that should be raised in the tests if they are raised in the server
97
+ # and {configure raise_server_errors} is `true`.
98
+ # - **test_id** (`Symbol`, `String`, `nil` = `nil`) - Optional attribute to match locator against with built-in selectors along with id.
99
+ # - **threadsafe** (Boolean = `false`) - Whether sessions can be configured individually.
100
+ #
101
+ # #### DSL Options
102
+ #
103
+ # When using `capybara/dsl`, the following options are also available:
104
+ #
105
+ # - **default_driver** (Symbol = `:rack_test`) - The name of the driver to use by default.
106
+ # - **javascript_driver** (Symbol = `:selenium`) - The name of a driver to use for JavaScript enabled tests.
99
107
  #
100
108
  def configure
101
109
  yield config
@@ -201,15 +209,13 @@ module Capybara
201
209
  # any string containing HTML in the exact same way you would query the current document in a Capybara
202
210
  # session.
203
211
  #
204
- # Example: A single element
205
- #
212
+ # @example A single element
206
213
  # node = Capybara.string('<a href="foo">bar</a>')
207
214
  # anchor = node.first('a')
208
215
  # anchor[:href] #=> 'foo'
209
216
  # anchor.text #=> 'bar'
210
217
  #
211
- # Example: Multiple elements
212
- #
218
+ # @example Multiple elements
213
219
  # node = Capybara.string <<-HTML
214
220
  # <ul>
215
221
  # <li id="home">Home</li>
@@ -297,7 +303,7 @@ module Capybara
297
303
 
298
304
  ##
299
305
  #
300
- # The current Capybara::Session based on what is set as Capybara.app and Capybara.current_driver
306
+ # The current {Capybara::Session} based on what is set as {app} and {current_driver}.
301
307
  #
302
308
  # @return [Capybara::Session] The currently used session
303
309
  #
@@ -340,7 +346,7 @@ module Capybara
340
346
 
341
347
  ##
342
348
  #
343
- # Yield a block using a specific session name or Capybara::Session instance.
349
+ # Yield a block using a specific session name or {Capybara::Session} instance.
344
350
  #
345
351
  def using_session(name_or_session)
346
352
  previous_session_info = {
@@ -130,6 +130,16 @@ class MinitestTest < Minitest::Test
130
130
  visit('/with_html')
131
131
  assert_matches_style(find(:css, '#second'), display: 'inline')
132
132
  end
133
+
134
+ def test_assert_ancestor
135
+ option = find(:option, 'Finnish')
136
+ assert_ancestor(option, :css, '#form_locale')
137
+ end
138
+
139
+ def test_assert_sibling
140
+ option = find(:css, '#form_title').find(:option, 'Mrs')
141
+ assert_sibling(option, :option, 'Mr')
142
+ end
133
143
  end
134
144
 
135
145
  RSpec.describe 'capybara/minitest' do
@@ -148,6 +158,6 @@ RSpec.describe 'capybara/minitest' do
148
158
  reporter.start
149
159
  MinitestTest.run reporter, {}
150
160
  reporter.report
151
- expect(output.string).to include('20 runs, 50 assertions, 0 failures, 0 errors, 1 skips')
161
+ expect(output.string).to include('22 runs, 52 assertions, 0 failures, 0 errors, 1 skips')
152
162
  end
153
163
  end
@@ -127,6 +127,16 @@ class MinitestSpecTest < Minitest::Spec
127
127
  find(:css, '#second').must_have_style('display' => 'inline') # deprecated
128
128
  find(:css, '#second').must_match_style('display' => 'inline')
129
129
  end
130
+
131
+ it 'supports ancestor expectations' do
132
+ option = find(:option, 'Finnish')
133
+ option.must_have_ancestor(:css, '#form_locale')
134
+ end
135
+
136
+ it 'supports sibling expectations' do
137
+ option = find(:css, '#form_title').find(:option, 'Mrs')
138
+ option.must_have_sibling(:option, 'Mr')
139
+ end
130
140
  end
131
141
 
132
142
  RSpec.describe 'capybara/minitest/spec' do
@@ -145,7 +155,7 @@ RSpec.describe 'capybara/minitest/spec' do
145
155
  reporter.start
146
156
  MinitestSpecTest.run reporter, {}
147
157
  reporter.report
148
- expect(output.string).to include('20 runs, 42 assertions, 1 failures, 0 errors, 1 skips')
158
+ expect(output.string).to include('22 runs, 44 assertions, 1 failures, 0 errors, 1 skips')
149
159
  # Make sure error messages are displayed
150
160
  expect(output.string).to match(/expected to find select box "non_existing_form_title" .*but there were no matches/)
151
161
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- RSpec.describe Capybara::Selector::RegexpDisassembler do
5
+ RSpec.describe Capybara::Selector::RegexpDisassembler, :aggregate_failures do
6
6
  it 'handles strings' do
7
7
  verify_strings(
8
8
  /abcdef/ => %w[abcdef],
@@ -64,6 +64,8 @@ Capybara::SpecHelper.run_specs TestSessions::SeleniumFirefox, 'selenium', capyba
64
64
  pending "Geckodriver doesn't provide a way to remove cookies outside the current domain"
65
65
  when 'Capybara::Session selenium #attach_file with a block can upload by clicking the file input'
66
66
  pending "Geckodriver doesn't allow clicking on file inputs"
67
+ when /drag_to.*HTML5/
68
+ pending "Firefox < 62 doesn't support a DataTransfer constuctor" if firefox_lt?(62.0, @session)
67
69
  end
68
70
  end
69
71
 
@@ -6,13 +6,13 @@ require 'shared_selenium_session'
6
6
  require 'shared_selenium_node'
7
7
  require 'rspec/shared_spec_matchers'
8
8
 
9
- if ENV['CI']
10
- if ::Selenium::WebDriver::Service.respond_to? :driver_path=
11
- ::Selenium::WebDriver::IE::Service
12
- else
13
- ::Selenium::WebDriver::IE
14
- end.driver_path = 'C:\Tools\WebDriver\IEDriverServer.exe'
15
- end
9
+ # if ENV['CI']
10
+ # if ::Selenium::WebDriver::Service.respond_to? :driver_path=
11
+ # ::Selenium::WebDriver::IE::Service
12
+ # else
13
+ # ::Selenium::WebDriver::IE
14
+ # end.driver_path = 'C:\Tools\WebDriver\IEDriverServer.exe'
15
+ # end
16
16
 
17
17
  def selenium_host
18
18
  ENV.fetch('SELENIUM_HOST', '192.168.56.102')
@@ -110,6 +110,12 @@ Capybara::SpecHelper.run_specs TestSessions::SeleniumIE, 'selenium', capybara_sk
110
110
  pending 'IE treats blank href as a parent request (against HTML spec)'
111
111
  when /#attach_file with a block/
112
112
  skip 'Hangs IE testing for unknown reason'
113
+ when /drag_to.*HTML5/
114
+ pending "IE doesn't support a DataTransfer constuctor"
115
+ when /template elements should not be visible/
116
+ skip "IE doesn't support template elements"
117
+ when /Element#drop/
118
+ pending "IE doesn't support DataTransfer constructor"
113
119
  end
114
120
  end
115
121
 
@@ -73,6 +73,8 @@ Capybara::SpecHelper.run_specs TestSessions::Safari, SAFARI_DRIVER.to_s, capybar
73
73
  when 'Capybara::Session selenium_safari #go_back should fetch a response from the driver from the previous page',
74
74
  'Capybara::Session selenium_safari #go_forward should fetch a response from the driver from the previous page'
75
75
  skip 'safaridriver loses the ability to find elements in the document after `go_back`'
76
+ when /drag_to.*HTML5/
77
+ pending "Safari doesn't support"
76
78
  end
77
79
  end
78
80
 
@@ -303,57 +303,6 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
303
303
  end
304
304
  end
305
305
 
306
- describe 'Element#drag_to' do
307
- before do
308
- skip "Firefox < 62 doesn't support a DataTransfer constuctor" if firefox_lt?(62.0, session)
309
- skip "IE doesn't support a DataTransfer constuctor" if ie?(session)
310
- skip "Safari doesn't support" if safari?(session)
311
- end
312
-
313
- it 'should HTML5 drag and drop an object' do
314
- session.visit('/with_js')
315
- element = session.find('//div[@id="drag_html5"]')
316
- target = session.find('//div[@id="drop_html5"]')
317
- element.drag_to(target)
318
- expect(session).to have_xpath('//div[contains(., "HTML5 Dropped drag_html5")]')
319
- end
320
-
321
- it 'should set clientX/Y in dragover events' do
322
- session.visit('/with_js')
323
- element = session.find('//div[@id="drag_html5"]')
324
- target = session.find('//div[@id="drop_html5"]')
325
- element.drag_to(target)
326
- session.all(:css, 'div.log').each { |el| puts el.text }
327
- expect(session).to have_css('div.log', text: /DragOver with client position: [1-9]\d*,[1-9]\d*/, count: 2)
328
- end
329
-
330
- it 'should not HTML5 drag and drop on a non HTML5 drop element' do
331
- session.visit('/with_js')
332
- element = session.find('//div[@id="drag_html5"]')
333
- target = session.find('//div[@id="drop_html5"]')
334
- target.execute_script("$(this).removeClass('drop');")
335
- element.drag_to(target)
336
- sleep 1
337
- expect(session).not_to have_xpath('//div[contains(., "HTML5 Dropped drag_html5")]')
338
- end
339
-
340
- it 'should HTML5 drag and drop when scrolling needed' do
341
- session.visit('/with_js')
342
- element = session.find('//div[@id="drag_html5_scroll"]')
343
- target = session.find('//div[@id="drop_html5_scroll"]')
344
- element.drag_to(target)
345
- expect(session).to have_xpath('//div[contains(., "HTML5 Dropped drag_html5_scroll")]')
346
- end
347
-
348
- it 'should drag HTML5 default draggable elements' do
349
- session.visit('/with_js')
350
- link = session.find_link('drag_link_html5')
351
- target = session.find(:id, 'drop_html5')
352
- link.drag_to target
353
- expect(session).to have_xpath('//div[contains(., "HTML5 Dropped")]')
354
- end
355
- end
356
-
357
306
  describe 'Capybara#Node#attach_file' do
358
307
  it 'can attach a directory' do
359
308
  pending "Geckodriver doesn't support uploading a directory" if firefox?(session)
@@ -472,6 +421,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
472
421
  describe 'with react' do
473
422
  context 'controlled components' do
474
423
  it 'can set and clear a text field' do
424
+ skip "This test doesn't support older browsers" if ie?(session)
475
425
  # session.visit 'https://reactjs.org/docs/forms.html'
476
426
  # session.all(:css, 'h2#controlled-components ~ p a', text: 'Try it on CodePen')[0].click
477
427
  # copied into local view