capybara 2.16.1 → 2.17.0

Sign up to get free protection for your applications and to get access to all the features.
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,