capybara 2.16.1 → 2.17.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94085614fef28d8c100eac0e0e11e213f0bb89ab487bb538a864da3b2ec21951
4
- data.tar.gz: b61bc9c51db0e61c730bd14e3d593ff9885e45178403dd5200a368f3e67fc8e2
3
+ metadata.gz: 5f913df68a0c00ede749cba87a0b229ff28e9e6b8f8f45bbbbd07577729f1c6a
4
+ data.tar.gz: 37a3fdfec9dc3cab859eae2300819d4691c1f20ccb05acf98807e7e287796c98
5
5
  SHA512:
6
- metadata.gz: 465a59847ac6f986ab374e6a84c678078c8804a60341c9ecd52625cf86e1041d98629806a4e4dc08531337e9db8190dfdbea3e64e40387ad3f16bb5a1d42cf09
7
- data.tar.gz: 43a4b4aaead1b7a66058269e5f8ea3f09782a2c7766c0bb7cd4c3e7f56abe7b852fe28859d3ef746135798e73b86c8c72dde7fdabce57f2765b58639c232b1e8
6
+ metadata.gz: 1edbf3df7b7357bbb96937c10eecffa5afa6ead2c119b0607bae820973702197de1536ec540968100d00355d07227c1f531f793156d645124d9f1a0250802996
7
+ data.tar.gz: e5a51fbceb1d26ddf7a101712bb407bc835ab701038b6e103c9f25c7677308fbda93ec515701862b297810b962dffac3b0e3ed35032296a6cf1f78c4adb4b79e
data/History.md CHANGED
@@ -1,5 +1,18 @@
1
+ # Version 2.17.0
2
+ Release date: 2018-01-02
3
+
4
+ ### Added
5
+
6
+ * `have_all_of_selectors`, `have_none_of_selectors` RSpec matchers for parity with minitest assertions [Thomas Walpole]
7
+
8
+ ### Fixed
9
+
10
+ * Allow xpath 3.x gem [Thomas Walpole]
11
+ * Issue when drivers returned nil for `current_path` and a matcher was used with a Regexp [Thomas Walpole]
12
+ * Error message when visible element not found, but non-visible was [Andy Klimczak]
13
+
1
14
  # Version 2.16.1
2
- Release data: 2017-11-20
15
+ Release date: 2017-11-20
3
16
 
4
17
  ### Fixed
5
18
 
@@ -81,7 +81,9 @@ module Capybara
81
81
  # @!method assert_xpath
82
82
  # see {Capybara::Node::Matchers#assert_not_matches_selector}
83
83
 
84
- %w(assert_selector assert_no_selector assert_matches_selector assert_not_matches_selector).each do |assertion_name|
84
+ %w(assert_selector assert_no_selector
85
+ assert_all_of_selectors assert_none_of_selectors
86
+ assert_matches_selector assert_not_matches_selector).each do |assertion_name|
85
87
  self.class_eval <<-EOM, __FILE__, __LINE__ + 1
86
88
  def #{assertion_name} *args, &optional_filter_block
87
89
  self.assertions +=1
@@ -11,7 +11,9 @@ module Capybara
11
11
  (%w(selector xpath css link button field select table checked_field unchecked_field).flat_map do |assertion|
12
12
  [["assert_#{assertion}", "must_have_#{assertion}"],
13
13
  ["refute_#{assertion}", "wont_have_#{assertion}"]]
14
- end + %w(selector xpath css).flat_map do |assertion|
14
+ end + [["assert_all_of_selectors", "must_have_all_of_selectors"],
15
+ ["assert_none_of_selectors", "must_have_none_of_selectors"]] +
16
+ %w(selector xpath css).flat_map do |assertion|
15
17
  [["assert_matches_#{assertion}", "must_match_#{assertion}"],
16
18
  ["refute_matches_#{assertion}", "wont_match_#{assertion}"]]
17
19
  end).each do |(meth, new_name)|
@@ -31,7 +31,7 @@ module Capybara
31
31
  end
32
32
 
33
33
  if @expected_path.is_a? Regexp
34
- @actual_path.match(@expected_path)
34
+ @actual_path.to_s.match(@expected_path)
35
35
  else
36
36
  ::Addressable::URI.parse(@expected_path) == ::Addressable::URI.parse(@actual_path)
37
37
  end
@@ -70,7 +70,7 @@ module Capybara
70
70
  invisible_text = text(@node, :all)
71
71
  invisible_count = invisible_text.scan(@search_regexp).size
72
72
  if invisible_count != @count
73
- details_message << ". it was found #{invisible_count} #{Capybara::Helpers.declension("time", "times", invisible_count)} including non-visible text"
73
+ details_message << "it was found #{invisible_count} #{Capybara::Helpers.declension("time", "times", invisible_count)} including non-visible text"
74
74
  end
75
75
  rescue
76
76
  # An error getting the non-visible text (if element goes out of scope) should not affect the response
@@ -59,7 +59,6 @@ module Capybara
59
59
  end
60
60
 
61
61
  class HaveSelector < Matcher
62
-
63
62
  def initialize(*args, &filter_block)
64
63
  @args = args
65
64
  @filter_block = filter_block
@@ -82,6 +81,44 @@ module Capybara
82
81
  end
83
82
  end
84
83
 
84
+ class HaveAllSelectors < Matcher
85
+ def initialize(*args, &filter_block)
86
+ @args = args
87
+ @filter_block = filter_block
88
+ end
89
+
90
+ def matches?(actual)
91
+ wrap_matches?(actual){ |el| el.assert_all_of_selectors(*@args, &@filter_block) }
92
+ end
93
+
94
+ def does_not_match?(actual)
95
+ raise ArgumentError, "The have_all_selectors matcher does not support use with not_to/should_not"
96
+ end
97
+
98
+ def description
99
+ "have all selectors"
100
+ end
101
+ end
102
+
103
+ class HaveNoSelectors < Matcher
104
+ def initialize(*args, &filter_block)
105
+ @args = args
106
+ @filter_block = filter_block
107
+ end
108
+
109
+ def matches?(actual)
110
+ wrap_matches?(actual){ |el| el.assert_none_of_selectors(*@args, &@filter_block) }
111
+ end
112
+
113
+ def does_not_match?(actual)
114
+ raise ArgumentError, "The have_none_of_selectors matcher does not support use with not_to/should_not"
115
+ end
116
+
117
+ def description
118
+ "have no selectors"
119
+ end
120
+ end
121
+
85
122
  class MatchSelector < HaveSelector
86
123
  def matches?(actual)
87
124
  wrap_matches?(actual) { |el| el.assert_matches_selector(*@args, &@filter_block) }
@@ -211,6 +248,18 @@ module Capybara
211
248
  HaveSelector.new(*args, &optional_filter_block)
212
249
  end
213
250
 
251
+ # RSpec matcher for whether the element(s) matching a group of selectors exist
252
+ # See {Capybara::Node::Matcher#assert_all_of_selectors}
253
+ def have_all_of_selectors(*args, &optional_filter_block)
254
+ HaveAllSelectors.new(*args, &optional_filter_block)
255
+ end
256
+
257
+ # RSpec matcher for whether no element(s) matching a group of selectors exist
258
+ # See {Capybara::Node::Matcher#assert_none_of_selectors}
259
+ def have_none_of_selectors(*args, &optional_filter_block)
260
+ HaveNoSelectors.new(*args, &optional_filter_block)
261
+ end
262
+
214
263
  # RSpec matcher for whether the current element matches a given selector
215
264
  # See {Capybara::Node::Matchers#assert_matches_selector}
216
265
  def match_selector(*args, &optional_filter_block)
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  class Capybara::Selenium::Node < Capybara::Driver::Node
3
+
3
4
  def visible_text
4
5
  # Selenium doesn't normalize Unicode whitespace.
5
6
  Capybara::Helpers.normalize_whitespace(native.text)
@@ -112,11 +113,15 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
112
113
  end
113
114
 
114
115
  def right_click
115
- driver.browser.action.context_click(native).perform
116
+ scroll_if_needed do
117
+ driver.browser.action.context_click(native).perform
118
+ end
116
119
  end
117
120
 
118
121
  def double_click
119
- driver.browser.action.double_click(native).perform
122
+ scroll_if_needed do
123
+ driver.browser.action.double_click(native).perform
124
+ end
120
125
  end
121
126
 
122
127
  def send_keys(*args)
@@ -124,11 +129,15 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
124
129
  end
125
130
 
126
131
  def hover
127
- driver.browser.action.move_to(native).perform
132
+ scroll_if_needed do
133
+ driver.browser.action.move_to(native).perform
134
+ end
128
135
  end
129
136
 
130
137
  def drag_to(element)
131
- driver.browser.action.drag_and_drop(native, element.native).perform
138
+ scroll_if_needed do
139
+ driver.browser.action.drag_and_drop(native, element.native).perform
140
+ end
132
141
  end
133
142
 
134
143
  def tag_name
@@ -238,4 +247,18 @@ private
238
247
  end
239
248
  end
240
249
  end
250
+
251
+ def scroll_if_needed(&block)
252
+ block.call
253
+ rescue ::Selenium::WebDriver::Error::MoveTargetOutOfBoundsError
254
+ script = <<-JS
255
+ try {
256
+ arguments[0].scrollIntoView({behavior: 'instant', block: 'center', inline: 'center'});
257
+ } catch(e) {
258
+ arguments[0].scrollIntoView(true);
259
+ }
260
+ JS
261
+ driver.execute_script(script, self)
262
+ block.call
263
+ end
241
264
  end
@@ -261,10 +261,8 @@ module Capybara
261
261
 
262
262
  visit_uri_parts = visit_uri.to_hash.delete_if { |k,v| v.nil? }
263
263
 
264
- # TODO - this is only for compatability with previous 2.x behavior that concatenated
265
- # Capybara.app_host and a "relative" path - Consider removing in 3.0
266
- # @abotalov brought up a good point about this behavior potentially being useful to people
267
- # deploying to a subdirectory and/or single page apps where only the url fragment changes
264
+ # Useful to people deploying to a subdirectory
265
+ # and/or single page apps where only the url fragment changes
268
266
  visit_uri_parts[:path] = uri_base.path + visit_uri.path
269
267
 
270
268
  visit_uri = uri_base.merge(visit_uri_parts)
@@ -488,7 +486,7 @@ module Capybara
488
486
  # @raise [Capybara::WindowError] if no window matches given block
489
487
  # @overload switch_to_window(window)
490
488
  # @param window [Capybara::Window] window that should be switched to
491
- # @raise [Capybara::Driver::Base#no_such_window_error] if non-existent (e.g. closed) window was passed
489
+ # @raise [Capybara::Driver::Base#no_such_window_error] if nonexistent (e.g. closed) window was passed
492
490
  #
493
491
  # @return [Capybara::Window] window that has been switched to
494
492
  # @raise [Capybara::ScopeError] if this method is invoked inside `within` or
@@ -521,7 +519,7 @@ module Capybara
521
519
  # @overload within_window(window) { do_something }
522
520
  # @param window [Capybara::Window] instance of `Capybara::Window` class
523
521
  # that will be switched to
524
- # @raise [driver#no_such_window_error] if unexistent (e.g. closed) window was passed
522
+ # @raise [driver#no_such_window_error] if nonexistent (e.g. closed) window was passed
525
523
  # @overload within_window(proc_or_lambda) { do_something }
526
524
  # @param lambda [Proc] lambda. First window for which lambda
527
525
  # returns a value other than false or nil will be switched to.
@@ -39,6 +39,7 @@ module Capybara
39
39
  # See {Capybara.configure}
40
40
  #@!method save_path
41
41
  # See {Capybara.configure}
42
+ #@deprecated
42
43
  #@!method exact_options
43
44
  # See {Capybara.configure}
44
45
  #@!method asset_host
@@ -90,6 +91,13 @@ module Capybara
90
91
  @save_and_open_page_path = path
91
92
  end
92
93
 
94
+ remove_method :exact_options=
95
+ def exact_options=(opt)
96
+ @exact_options = opt
97
+ warn "DEPRECATED: #exact_options is deprecated, please scope your findes/actions and use the `:exact` "\
98
+ "option if similar functionality is needed."
99
+ end
100
+
93
101
  def initialize_copy(other)
94
102
  super
95
103
  @server_errors = @server_errors.dup
@@ -1,8 +1,8 @@
1
1
  var activeRequests = 0;
2
2
  $(function() {
3
3
  $('#change').text('I changed it');
4
- $('#drag').draggable();
5
- $('#drop').droppable({
4
+ $('#drag, #drag_scroll').draggable();
5
+ $('#drop, #drop_scroll').droppable({
6
6
  drop: function(event, ui) {
7
7
  ui.draggable.remove();
8
8
  $(this).html('Dropped!');
@@ -52,6 +52,14 @@ Capybara::SpecHelper.spec '#assert_text' do
52
52
  end.to raise_error(Capybara::ExpectationNotMet, /it was found 1 time using a case insensitive search/)
53
53
  end
54
54
 
55
+ it "should raise error with helpful message if requested text is present but invisible and with incorrect case", requires: [:js] do
56
+ @session.visit('/with_html')
57
+ el = @session.find(:css, '#uppercase')
58
+ expect do
59
+ el.assert_text('text here')
60
+ end.to raise_error(Capybara::ExpectationNotMet, /it was found 1 time using a case insensitive search and it was found 1 time including non-visible text/)
61
+ end
62
+
55
63
  it "should raise the correct error if requested text is missing but contains regex special characters" do
56
64
  @session.visit('/with_html')
57
65
  expect do
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+ Capybara::SpecHelper.spec '#have_all_selectors' do
3
+ before do
4
+ @session.visit('/with_html')
5
+ end
6
+
7
+ it "should be true if the given selectors are on the page" do
8
+ expect(@session).to have_all_of_selectors(:css, "p a#foo", "h2#h2one", "h2#h2two" )
9
+ end
10
+
11
+ it "should be false if any of the given selectors are not on the page" do
12
+ expect {
13
+ expect(@session).to have_all_of_selectors(:css, "p a#foo", "h2#h2three", "h2#h2one")
14
+ }.to raise_error ::RSpec::Expectations::ExpectationNotMetError
15
+ end
16
+
17
+ it "should use default selector" do
18
+ Capybara.default_selector = :css
19
+ expect(@session).to have_all_of_selectors("p a#foo", "h2#h2two", "h2#h2one" )
20
+ expect {
21
+ expect(@session).to have_all_of_selectors("p a#foo", "h2#h2three", "h2#h2one")
22
+ }.to raise_error ::RSpec::Expectations::ExpectationNotMetError
23
+ end
24
+
25
+ context "should respect scopes" do
26
+ it "when used with `within`" do
27
+ @session.within "//p[@id='first']" do
28
+ expect(@session).to have_all_of_selectors(".//a[@id='foo']")
29
+ expect {
30
+ expect(@session).to have_all_of_selectors(".//a[@id='red']")
31
+ }.to raise_error ::RSpec::Expectations::ExpectationNotMetError
32
+ end
33
+ end
34
+
35
+ it "when called on elements" do
36
+ el = @session.find "//p[@id='first']"
37
+ expect(el).to have_all_of_selectors(".//a[@id='foo']")
38
+ expect {
39
+ expect(el).to have_all_of_selectors(".//a[@id='red']")
40
+ }.to raise_error ::RSpec::Expectations::ExpectationNotMetError
41
+ end
42
+ end
43
+
44
+ context "with options" do
45
+ it "should apply options to all locators" do
46
+ expect(@session).to have_all_of_selectors(:field, 'normal', 'additional_newline', type: :textarea)
47
+ expect {
48
+ expect(@session).to have_all_of_selectors(:field, 'normal', 'test_field', 'additional_newline', type: :textarea)
49
+ }.to raise_error ::RSpec::Expectations::ExpectationNotMetError
50
+ end
51
+ end
52
+
53
+ context "with wait", requires: [:js] do
54
+ it "should not raise error if all the elements appear before given wait duration" do
55
+ Capybara.using_wait_time(0.1) do
56
+ @session.visit('/with_js')
57
+ @session.click_link('Click me')
58
+ expect(@session).to have_all_of_selectors(:css, "a#clickable", "a#has-been-clicked", '#drag', wait: 0.9)
59
+ end
60
+ end
61
+ end
62
+
63
+ it "cannot be negated" do
64
+ expect {
65
+ expect(@session).not_to have_all_of_selectors(:css, "p a#foo", "h2#h2one", "h2#h2two")
66
+ }.to raise_error ArgumentError
67
+ end
68
+ end
69
+
@@ -13,6 +13,12 @@ Capybara::SpecHelper.spec '#has_current_path?' do
13
13
  expect(@session).not_to have_current_path(/monkey/)
14
14
  end
15
15
 
16
+ it "should not raise an error when non-http" do
17
+ @session.reset_session!
18
+ expect(@session.has_current_path?(/monkey/)).to eq false
19
+ expect(@session.has_current_path?("/with_js")).to eq false
20
+ end
21
+
16
22
  it "should handle non-escaped query options" do
17
23
  @session.click_link("Non-escaped query options")
18
24
  expect(@session).to have_current_path("/with_html?options[]=things")
@@ -14,8 +14,8 @@ Capybara::SpecHelper.spec '#has_link?' do
14
14
 
15
15
  it "should be false if the given link is not on the page" do
16
16
  expect(@session).not_to have_link('monkey')
17
- expect(@session).not_to have_link('A link', href: '/non-existant-href')
18
- expect(@session).not_to have_link('A link', href: /non-existant/)
17
+ expect(@session).not_to have_link('A link', href: '/nonexistent-href')
18
+ expect(@session).not_to have_link('A link', href: /nonexistent/)
19
19
  end
20
20
  end
21
21
 
@@ -32,7 +32,7 @@ Capybara::SpecHelper.spec '#has_no_link?' do
32
32
 
33
33
  it "should be true if the given link is not on the page" do
34
34
  expect(@session).to have_no_link('monkey')
35
- expect(@session).to have_no_link('A link', href: '/non-existant-href')
36
- expect(@session).to have_no_link('A link', href: /\/non-existant-href/)
35
+ expect(@session).to have_no_link('A link', href: '/nonexistent-href')
36
+ expect(@session).to have_no_link('A link', href: /\/nonexistent-href/)
37
37
  end
38
38
  end
@@ -0,0 +1,76 @@
1
+ Capybara::SpecHelper.spec '#have_none_of_selectors' do
2
+ before do
3
+ @session.visit('/with_html')
4
+ end
5
+
6
+ it "should be false if any of the given locators are on the page" do
7
+ expect {
8
+ expect(@session).to have_none_of_selectors(:xpath, "//p", "//a")
9
+ }.to raise_error ::RSpec::Expectations::ExpectationNotMetError
10
+ expect {
11
+ expect(@session).to have_none_of_selectors(:css, "p a#foo")
12
+ }.to raise_error ::RSpec::Expectations::ExpectationNotMetError
13
+ end
14
+
15
+ it "should be true if none of the given locators are on the page" do
16
+ expect(@session).to have_none_of_selectors(:xpath, "//abbr", "//td" )
17
+ expect(@session).to have_none_of_selectors(:css, "p a#doesnotexist", "abbr")
18
+ end
19
+
20
+ it "should use default selector" do
21
+ Capybara.default_selector = :css
22
+ expect(@session).to have_none_of_selectors("p a#doesnotexist", "abbr")
23
+ expect {
24
+ expect(@session).to have_none_of_selectors("abbr", "p a#foo")
25
+ }.to raise_error ::RSpec::Expectations::ExpectationNotMetError
26
+ end
27
+
28
+ context "should respect scopes" do
29
+ it "when used with `within`" do
30
+ @session.within "//p[@id='first']" do
31
+ expect {
32
+ expect(@session).to have_none_of_selectors(".//a[@id='foo']")
33
+ }.to raise_error ::RSpec::Expectations::ExpectationNotMetError
34
+ expect(@session).to have_none_of_selectors(".//a[@id='red']")
35
+ end
36
+ end
37
+
38
+ it "when called on an element" do
39
+ el = @session.find "//p[@id='first']"
40
+ expect {
41
+ expect(el).to have_none_of_selectors(".//a[@id='foo']")
42
+ }.to raise_error ::RSpec::Expectations::ExpectationNotMetError
43
+ expect(el).to have_none_of_selectors(".//a[@id='red']")
44
+ end
45
+ end
46
+
47
+ context "with options" do
48
+ it "should apply the options to all locators" do
49
+ expect {
50
+ expect(@session).to have_none_of_selectors("//p//a", text: "Redirect")
51
+ }.to raise_error ::RSpec::Expectations::ExpectationNotMetError
52
+ expect(@session).to have_none_of_selectors("//p", text: "Doesnotexist")
53
+ end
54
+
55
+ it "should discard all matches where the given regexp is matched" do
56
+ expect {
57
+ expect(@session).to have_none_of_selectors("//p//a", text: /re[dab]i/i, count: 1)
58
+ }.to raise_error ::RSpec::Expectations::ExpectationNotMetError
59
+ expect(@session).to have_none_of_selectors("//p//a", text: /Red$/)
60
+ end
61
+ end
62
+
63
+ context "with wait", requires: [:js] do
64
+ it "should not find elements if they appear after given wait duration" do
65
+ @session.visit('/with_js')
66
+ @session.click_link('Click me')
67
+ expect(@session).to have_none_of_selectors(:css, "#new_field", "a#has-been-clicked", wait: 0.1)
68
+ end
69
+ end
70
+
71
+ it "cannot be negated" do
72
+ expect {
73
+ expect(@session).not_to have_none_of_selectors(:css, "p a#foo", "h2#h2one", "h2#h2two")
74
+ }.to raise_error ArgumentError
75
+ end
76
+ end
@@ -27,7 +27,7 @@ Capybara::SpecHelper.spec '#has_select?' do
27
27
  expect(@session).not_to have_select('Does not exist', selected: 'John')
28
28
  expect(@session).not_to have_select('City', selected: 'Not there')
29
29
  expect(@session).not_to have_select('Underwear', selected: [
30
- 'Boxerbriefs', 'Briefs', 'Commando', "Frenchman's Pantalons", 'Long Johns', 'Nonexistant'
30
+ 'Boxerbriefs', 'Briefs', 'Commando', "Frenchman's Pantalons", 'Long Johns', 'Nonexistent'
31
31
  ])
32
32
  expect(@session).not_to have_select('Underwear', selected: [
33
33
  'Boxerbriefs', 'Briefs', 'Boxers', 'Commando', "Frenchman's Pantalons", 'Long Johns'
@@ -185,7 +185,7 @@ Capybara::SpecHelper.spec '#has_no_select?' do
185
185
  expect(@session).to have_no_select('Does not exist', selected: 'John')
186
186
  expect(@session).to have_no_select('City', selected: 'Not there')
187
187
  expect(@session).to have_no_select('Underwear', selected: [
188
- 'Boxerbriefs', 'Briefs', 'Commando', "Frenchman's Pantalons", 'Long Johns', 'Nonexistant'
188
+ 'Boxerbriefs', 'Briefs', 'Commando', "Frenchman's Pantalons", 'Long Johns', 'Nonexistent'
189
189
  ])
190
190
  expect(@session).to have_no_select('Underwear', selected: [
191
191
  'Boxerbriefs', 'Briefs', 'Boxers', 'Commando', "Frenchman's Pantalons", 'Long Johns'
@@ -297,14 +297,29 @@ Capybara::SpecHelper.spec "node" do
297
297
  element.drag_to(target)
298
298
  expect(@session.find('//div[contains(., "Dropped!")]')).not_to be_nil
299
299
  end
300
+
301
+ it "should drag and drop if scrolling is needed" do
302
+ @session.visit('/with_js')
303
+ element = @session.find('//div[@id="drag_scroll"]')
304
+ target = @session.find('//div[@id="drop_scroll"]')
305
+ element.drag_to(target)
306
+ expect(@session.find('//div[contains(., "Dropped!")]')).not_to be_nil
307
+ end
300
308
  end
301
309
 
302
310
  describe '#hover', requires: [:hover] do
303
311
  it "should allow hovering on an element" do
304
312
  @session.visit('/with_hover')
305
- expect(@session.find(:css,'.hidden_until_hover', visible: false)).not_to be_visible
306
- @session.find(:css,'.wrapper').hover
307
- expect(@session.find(:css, '.hidden_until_hover', visible: false)).to be_visible
313
+ expect(@session.find(:css, '.wrapper:not(.scroll_needed) .hidden_until_hover', visible: false)).not_to be_visible
314
+ @session.find(:css,'.wrapper:not(.scroll_needed)').hover
315
+ expect(@session.find(:css, '.wrapper:not(.scroll_needed) .hidden_until_hover', visible: false)).to be_visible
316
+ end
317
+
318
+ it "should allow hovering on an element that needs to be scrolled into view" do
319
+ @session.visit('/with_hover')
320
+ expect(@session.find(:css, '.wrapper.scroll_needed .hidden_until_hover', visible: false)).not_to be_visible
321
+ @session.find(:css,'.wrapper.scroll_needed').hover
322
+ expect(@session.find(:css, '.wrapper.scroll_needed .hidden_until_hover', visible: false)).to be_visible
308
323
  end
309
324
  end
310
325
 
@@ -347,7 +362,7 @@ Capybara::SpecHelper.spec "node" do
347
362
 
348
363
  describe '#double_click', requires: [:js] do
349
364
  it "should double click an element" do
350
- pending "selenium-webdriver/geckodriver doesn't support mouse move_to" if marionette?(@session)
365
+ pending "selenium-webdriver/geckodriver doesn't generate double click event" if marionette?(@session)
351
366
  @session.visit('/with_js')
352
367
  @session.find(:css, '#click-test').double_click
353
368
  expect(@session.find(:css, '#has-been-double-clicked')).to be
@@ -356,7 +371,6 @@ Capybara::SpecHelper.spec "node" do
356
371
 
357
372
  describe '#right_click', requires: [:js] do
358
373
  it "should right click an element" do
359
- pending "selenium-webdriver/geckodriver doesn't support mouse move_to" if marionette?(@session)
360
374
  @session.visit('/with_js')
361
375
  @session.find(:css, '#click-test').right_click
362
376
  expect(@session.find(:css, '#has-been-right-clicked')).to be
@@ -24,6 +24,7 @@ Capybara::SpecHelper.spec "#select" do
24
24
  end
25
25
 
26
26
  it "should not allow selecting options where they are the only inexact match if `Capybara.exact_options = true`" do
27
+ expect_any_instance_of(Kernel).to receive(:warn).with(/^DEPRECATED:/)
27
28
  Capybara.exact_options = true
28
29
  expect do
29
30
  @session.select("Mis", from: 'Title')
@@ -33,7 +33,9 @@ module Capybara
33
33
  Capybara.default_max_wait_time = 1
34
34
  Capybara.ignore_hidden_elements = true
35
35
  Capybara.exact = false
36
- Capybara.exact_options = false
36
+ # `exact_options` is deprecated - set instancce var directly so we
37
+ # don't generate message every reset
38
+ Capybara.send(:config).session_options.instance_variable_set('@exact_options', false)
37
39
  Capybara.raise_server_errors = true
38
40
  Capybara.visible_text_only = false
39
41
  Capybara.match = :smart
@@ -52,7 +54,7 @@ module Capybara
52
54
  end
53
55
  end
54
56
 
55
- def spec(name, options={}, &block)
57
+ def spec(name, *options, &block)
56
58
  @specs ||= []
57
59
  @specs << [name, options, block]
58
60
  end
@@ -79,7 +81,7 @@ module Capybara
79
81
  end
80
82
 
81
83
  specs.each do |spec_name, spec_options, block|
82
- describe spec_name, spec_options do
84
+ describe spec_name, *spec_options do
83
85
  class_eval(&block)
84
86
  end
85
87
  end
@@ -14,5 +14,10 @@
14
14
  Some text here so the wrapper has size
15
15
  <div class="hidden_until_hover">Here I am</div>
16
16
  </div>
17
+ <div style="display: block; height: 1000px; width: 100%"></div>
18
+ <div class="wrapper scroll_needed" >
19
+ Some text here so the wrapper has size
20
+ <div class="hidden_until_hover">Here I am</div>
21
+ </div>
17
22
  </body>
18
23
  </html>
@@ -122,6 +122,10 @@ banana</textarea>
122
122
  <a id="link_blank_href" href="">Blank href</a>
123
123
  </div>
124
124
 
125
+ <div id="uppercase" style="text-transform: uppercase;">
126
+ text here
127
+ </div>
128
+
125
129
  <div id="ancestor3">
126
130
  Ancestor
127
131
  <div id="ancestor2">
@@ -121,6 +121,13 @@
121
121
  <input type="file" id="hidden_file" style="opacity:0; display: none;">
122
122
  </p>
123
123
 
124
+ <div id="drag_scroll">
125
+ <p>This is a draggable element.</p>
126
+ </div>
127
+ <div id="drop_scroll">
128
+ <p>It should be dropped here.</p>
129
+ </div>
130
+
124
131
  <script type="text/javascript">
125
132
  // a javascript comment
126
133
  var aVar = 123;
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Capybara
3
- VERSION = '2.16.1'
3
+ VERSION = '2.17.0'
4
4
  end
@@ -139,7 +139,7 @@ RSpec.describe Capybara do
139
139
  end
140
140
 
141
141
  RSpec.describe Capybara::Session do
142
- context 'with non-existant driver' do
142
+ context 'with nonexistent driver' do
143
143
  it "should raise an error" do
144
144
  expect {
145
145
  Capybara::Session.new(:quox, TestApp).driver
@@ -88,6 +88,14 @@ class MinitestTest < Minitest::Test
88
88
  refute_table('not_on_form')
89
89
  end
90
90
 
91
+ def test_assert_all_of_selectors
92
+ assert_all_of_selectors(:css, 'select#form_other_title', 'input#form_last_name')
93
+ end
94
+
95
+ def test_assert_none_of_selectors
96
+ assert_none_of_selectors(:css, 'input#not_on_page', 'input#also_not_on_page')
97
+ end
98
+
91
99
  def test_assert_matches_selector
92
100
  assert_matches_selector(find(:field, 'customer_email'), :field, 'customer_email')
93
101
  assert_not_matches_selector(find(:select, 'form_title'), :field, 'customer_email')
@@ -117,6 +125,6 @@ RSpec.describe 'capybara/minitest' do
117
125
  reporter.start
118
126
  MinitestTest.run reporter, {}
119
127
  reporter.report
120
- expect(output.string).to include("15 runs, 42 assertions, 0 failures, 0 errors, 0 skips")
128
+ expect(output.string).to include("17 runs, 44 assertions, 0 failures, 0 errors, 0 skips")
121
129
  end
122
130
  end
@@ -88,6 +88,14 @@ class MinitestSpecTest < Minitest::Spec
88
88
  page.wont_have_table('not_on_form')
89
89
  end
90
90
 
91
+ it "supports all_of_selectors expectations" do
92
+ page.must_have_all_of_selectors(:css, 'select#form_other_title', 'input#form_last_name')
93
+ end
94
+
95
+ it "supports none_of_selectors expectations" do
96
+ page.must_have_none_of_selectors(:css, 'input#not_on_page', 'input#also_not_on_page')
97
+ end
98
+
91
99
  it "supports match_selector expectations" do
92
100
  find(:field, 'customer_email').must_match_selector(:field, 'customer_email')
93
101
  find(:select, 'form_title').wont_match_selector(:field, 'customer_email')
@@ -120,7 +128,7 @@ RSpec.describe 'capybara/minitest/spec' do
120
128
  reporter.start
121
129
  MinitestSpecTest.run reporter, {}
122
130
  reporter.report
123
- expect(output.string).to include("16 runs, 39 assertions, 1 failures, 0 errors, 0 skips")
131
+ expect(output.string).to include("18 runs, 41 assertions, 1 failures, 0 errors, 0 skips")
124
132
  #Make sure error messages are displayed
125
133
  expect(output.string).to include('expected to find visible select box "non_existing_form_title" that is not disabled but there were no matches')
126
134
  end
@@ -40,8 +40,10 @@ RSpec.describe "Capybara::Session with chrome" do
40
40
  @session.find(:css, '#set-storage').click
41
41
  @session.reset!
42
42
  @session.visit('/with_js')
43
- expect(@session.driver.browser.local_storage.keys).not_to be_empty
44
- expect(@session.driver.browser.session_storage.keys).not_to be_empty
43
+ # expect(@session.driver.browser.local_storage.keys).not_to be_empty
44
+ # expect(@session.driver.browser.session_storage.keys).not_to be_empty
45
+ expect(@session.evaluate_script('Object.keys(localStorage)')).not_to be_empty
46
+ expect(@session.evaluate_script('Object.keys(sessionStorage)')).not_to be_empty
45
47
  end
46
48
 
47
49
  it "clears storage when set" do
@@ -50,8 +52,10 @@ RSpec.describe "Capybara::Session with chrome" do
50
52
  @session.find(:css, '#set-storage').click
51
53
  @session.reset!
52
54
  @session.visit('/with_js')
53
- expect(@session.driver.browser.local_storage.keys).to be_empty
54
- expect(@session.driver.browser.session_storage.keys).to be_empty
55
+ # expect(@session.driver.browser.local_storage.keys).to be_empty
56
+ # expect(@session.driver.browser.session_storage.keys).to be_empty
57
+ expect(@session.evaluate_script('Object.keys(localStorage)')).to be_empty
58
+ expect(@session.evaluate_script('Object.keys(sessionStorage)')).to be_empty
55
59
  end
56
60
  end
57
61
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.16.1
4
+ version: 2.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Walpole
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain:
12
12
  - gem-public_cert.pem
13
- date: 2017-11-20 00:00:00.000000000 Z
13
+ date: 2018-01-02 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: nokogiri
@@ -72,16 +72,22 @@ dependencies:
72
72
  name: xpath
73
73
  requirement: !ruby/object:Gem::Requirement
74
74
  requirements:
75
- - - "~>"
75
+ - - ">="
76
76
  - !ruby/object:Gem::Version
77
77
  version: '2.0'
78
+ - - "<"
79
+ - !ruby/object:Gem::Version
80
+ version: '4.0'
78
81
  type: :runtime
79
82
  prerelease: false
80
83
  version_requirements: !ruby/object:Gem::Requirement
81
84
  requirements:
82
- - - "~>"
85
+ - - ">="
83
86
  - !ruby/object:Gem::Version
84
87
  version: '2.0'
88
+ - - "<"
89
+ - !ruby/object:Gem::Version
90
+ version: '4.0'
85
91
  - !ruby/object:Gem::Dependency
86
92
  name: addressable
87
93
  requirement: !ruby/object:Gem::Requirement
@@ -390,11 +396,13 @@ files:
390
396
  - lib/capybara/spec/session/frame/within_frame_spec.rb
391
397
  - lib/capybara/spec/session/go_back_spec.rb
392
398
  - lib/capybara/spec/session/go_forward_spec.rb
399
+ - lib/capybara/spec/session/has_all_selectors_spec.rb
393
400
  - lib/capybara/spec/session/has_button_spec.rb
394
401
  - lib/capybara/spec/session/has_css_spec.rb
395
402
  - lib/capybara/spec/session/has_current_path_spec.rb
396
403
  - lib/capybara/spec/session/has_field_spec.rb
397
404
  - lib/capybara/spec/session/has_link_spec.rb
405
+ - lib/capybara/spec/session/has_none_selectors_spec.rb
398
406
  - lib/capybara/spec/session/has_select_spec.rb
399
407
  - lib/capybara/spec/session/has_selector_spec.rb
400
408
  - lib/capybara/spec/session/has_table_spec.rb
@@ -508,7 +516,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
508
516
  version: '0'
509
517
  requirements: []
510
518
  rubyforge_project:
511
- rubygems_version: 2.7.0
519
+ rubygems_version: 2.7.3
512
520
  signing_key:
513
521
  specification_version: 4
514
522
  summary: Capybara aims to simplify the process of integration testing Rack applications,
OSZAR »