capybara 3.10.1 → 3.11.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +13 -0
  3. data/README.md +2 -3
  4. data/lib/capybara.rb +16 -6
  5. data/lib/capybara/minitest.rb +8 -9
  6. data/lib/capybara/node/actions.rb +31 -28
  7. data/lib/capybara/node/base.rb +2 -1
  8. data/lib/capybara/node/document_matchers.rb +6 -2
  9. data/lib/capybara/node/element.rb +10 -10
  10. data/lib/capybara/node/finders.rb +13 -14
  11. data/lib/capybara/node/matchers.rb +1 -3
  12. data/lib/capybara/node/simple.rb +10 -2
  13. data/lib/capybara/queries/base_query.rb +7 -3
  14. data/lib/capybara/queries/selector_query.rb +60 -34
  15. data/lib/capybara/queries/style_query.rb +5 -1
  16. data/lib/capybara/queries/text_query.rb +2 -2
  17. data/lib/capybara/queries/title_query.rb +1 -1
  18. data/lib/capybara/rack_test/node.rb +16 -2
  19. data/lib/capybara/result.rb +9 -4
  20. data/lib/capybara/rspec/features.rb +4 -4
  21. data/lib/capybara/rspec/matcher_proxies.rb +3 -1
  22. data/lib/capybara/rspec/matchers.rb +25 -287
  23. data/lib/capybara/rspec/matchers/base.rb +98 -0
  24. data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
  25. data/lib/capybara/rspec/matchers/compound.rb +88 -0
  26. data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
  27. data/lib/capybara/rspec/matchers/have_selector.rb +69 -0
  28. data/lib/capybara/rspec/matchers/have_style.rb +23 -0
  29. data/lib/capybara/rspec/matchers/have_text.rb +33 -0
  30. data/lib/capybara/rspec/matchers/have_title.rb +29 -0
  31. data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
  32. data/lib/capybara/selector.rb +48 -20
  33. data/lib/capybara/selector/builders/xpath_builder.rb +3 -3
  34. data/lib/capybara/selector/css.rb +5 -5
  35. data/lib/capybara/selector/filters/base.rb +11 -3
  36. data/lib/capybara/selector/filters/expression_filter.rb +3 -3
  37. data/lib/capybara/selector/filters/node_filter.rb +16 -2
  38. data/lib/capybara/selector/regexp_disassembler.rb +116 -17
  39. data/lib/capybara/selector/selector.rb +52 -26
  40. data/lib/capybara/selenium/driver.rb +6 -2
  41. data/lib/capybara/selenium/node.rb +15 -14
  42. data/lib/capybara/selenium/nodes/marionette_node.rb +19 -5
  43. data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -3
  44. data/lib/capybara/server.rb +6 -1
  45. data/lib/capybara/server/animation_disabler.rb +1 -1
  46. data/lib/capybara/session.rb +4 -2
  47. data/lib/capybara/session/matchers.rb +7 -3
  48. data/lib/capybara/spec/public/test.js +5 -5
  49. data/lib/capybara/spec/session/all_spec.rb +5 -0
  50. data/lib/capybara/spec/session/has_css_spec.rb +4 -4
  51. data/lib/capybara/spec/session/has_field_spec.rb +17 -0
  52. data/lib/capybara/spec/session/node_spec.rb +45 -4
  53. data/lib/capybara/spec/spec_helper.rb +6 -1
  54. data/lib/capybara/spec/views/frame_child.erb +1 -1
  55. data/lib/capybara/spec/views/obscured.erb +44 -0
  56. data/lib/capybara/spec/views/with_html.erb +1 -1
  57. data/lib/capybara/version.rb +1 -1
  58. data/spec/rack_test_spec.rb +15 -0
  59. data/spec/regexp_dissassembler_spec.rb +88 -8
  60. data/spec/selector_spec.rb +3 -0
  61. data/spec/selenium_spec_chrome.rb +9 -15
  62. data/spec/selenium_spec_chrome_remote.rb +3 -2
  63. data/spec/selenium_spec_firefox_remote.rb +6 -2
  64. metadata +54 -3
  65. data/lib/capybara/rspec/compound.rb +0 -86
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Capybara
4
- VERSION = '3.10.1'
4
+ VERSION = '3.11.0'
5
5
  end
@@ -1,6 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
+ nokogumbo_required = begin
5
+ require 'nokogumbo'
6
+ true
7
+ rescue LoadError
8
+ false
9
+ end
4
10
 
5
11
  module TestSessions
6
12
  RackTest = Capybara::Session.new(:rack_test, TestApp)
@@ -231,6 +237,15 @@ RSpec.describe Capybara::RackTest::Driver do
231
237
  end
232
238
  end
233
239
 
240
+ RSpec.describe 'Capybara::String' do
241
+ it 'should use gumbo' do
242
+ skip 'Only valid if gumbo is included' unless nokogumbo_required
243
+ allow(Nokogiri).to receive(:HTML5).and_call_original
244
+ Capybara.string('<div id=test_div></div>')
245
+ expect(Nokogiri).to have_received(:HTML5)
246
+ end
247
+ end
248
+
234
249
  module CSSHandlerIncludeTester
235
250
  def dont_extend_css_handler
236
251
  raise 'should never be called'
@@ -27,18 +27,37 @@ RSpec.describe Capybara::Selector::RegexpDisassembler do
27
27
  /abc./ => %w[abc],
28
28
  /abc.*/ => %w[abc],
29
29
  /abc.def/ => %w[abc def],
30
- /abc.def.ghi/ => %w[abc def ghi]
30
+ /abc.def.ghi/ => %w[abc def ghi],
31
+ /abc.abcd.abcde/ => %w[abcde],
32
+ /.*/ => []
31
33
  )
32
34
  end
33
35
 
34
- it 'handles optional characters' do
35
- verify_strings(
36
+ it 'ignores optional characters for substrings' do
37
+ {
36
38
  /abc*def/ => %w[ab def],
37
39
  /abc*/ => %w[ab],
40
+ /c*/ => [],
38
41
  /abc?def/ => %w[ab def],
39
42
  /abc?/ => %w[ab],
40
43
  /abc?def?/ => %w[ab de],
41
- /abc?def?g/ => %w[ab de g]
44
+ /abc?def?g/ => %w[ab de g],
45
+ /d?/ => []
46
+ }.each do |regexp, expected|
47
+ expect(Capybara::Selector::RegexpDisassembler.new(regexp).substrings).to eq expected
48
+ end
49
+ end
50
+
51
+ it 'handles optional characters for #alternated_substrings' do
52
+ verify_alternated_strings(
53
+ /abc*def/ => [%w[ab def]],
54
+ /abc*/ => [%w[ab]],
55
+ /c*/ => [],
56
+ /abc?def/ => [%w[abdef], %w[abcdef]],
57
+ /abc?/ => [%w[ab]],
58
+ /abc?def?/ => [%w[abde], %w[abcde]],
59
+ /abc?def?g/ => [%w[abdeg], %w[abdefg], %w[abcdeg], %w[abcdefg]],
60
+ /d?/ => []
42
61
  )
43
62
  end
44
63
 
@@ -47,7 +66,7 @@ RSpec.describe Capybara::Selector::RegexpDisassembler do
47
66
  /abc[a-z]/ => %w[abc],
48
67
  /abc[a-z]def[0-9]g/ => %w[abc def g],
49
68
  /[0-9]abc/ => %w[abc],
50
- /[0-9]+/ => %w[],
69
+ /[0-9]+/ => [],
51
70
  /abc[0-9&&[^7]]/ => %w[abc]
52
71
  )
53
72
  end
@@ -88,11 +107,64 @@ RSpec.describe Capybara::Selector::RegexpDisassembler do
88
107
  )
89
108
  end
90
109
 
91
- it 'handles alternation' do
92
- verify_strings(
110
+ it 'ignores alternation for #substrings' do
111
+ {
93
112
  /abc|def/ => [],
94
113
  /ab(?:c|d)/ => %w[ab],
95
- /ab(c|d)ef/ => %w[ab ef]
114
+ /ab(c|d|e)fg/ => %w[ab fg],
115
+ /ab?(c|d)fg/ => %w[a fg],
116
+ /ab(c|d)ef/ => %w[ab ef],
117
+ /ab(cd?|ef)g/ => %w[ab g],
118
+ /ab(cd|ef*)g/ => %w[ab g],
119
+ /ab|cd*/ => [],
120
+ /cd(?:ef|gh)|xyz/ => [],
121
+ /(cd(?:ef|gh)|xyz)/ => [],
122
+ /cd(ef|gh)+/ => %w[cd],
123
+ /cd(ef|gh)?/ => %w[cd],
124
+ /cd(ef|gh)?ij/ => %w[cd ij],
125
+ /cd(ef|gh)+ij/ => %w[cd ij],
126
+ /cd(ef|gh){2}ij/ => %w[cd ij],
127
+ /(cd(ef|g*))/ => %w[cd],
128
+ /ab(cd){0,2}ef/ => %w[ab ef],
129
+ /ab(cd){0,1}ef/ => %w[ab ef],
130
+ /ab(cd|cd)ef/ => %w[ab ef],
131
+ /ab(cd|cd)?ef/ => %w[ab ef],
132
+ /ab\\?cd/ => %w[ab cd]
133
+ }.each do |regexp, expected|
134
+ expect(Capybara::Selector::RegexpDisassembler.new(regexp).substrings).to eq expected
135
+ end
136
+ end
137
+
138
+ it 'handles alternation for #alternated_substrings' do
139
+ verify_alternated_strings(
140
+ /abc|def/ => [%w[abc], %w[def]],
141
+ /ab(?:c|d)/ => [%w[abc], %w[abd]],
142
+ /ab(c|d|e)fg/ => [%w[abcfg], %w[abdfg], %w[abefg]],
143
+ /ab?(c|d)fg/ => [%w[acfg], %w[adfg], %w[abcfg], %w[abdfg]],
144
+ /ab(c|d)ef/ => [%w[abcef], %w[abdef]],
145
+ /ab(cd?|ef)g/ => [%w[abcg], %w[abcdg], %w[abefg]],
146
+ /ab(cd|ef*)g/ => [%w[abcdg], %w[abe g]],
147
+ /ab|cd*/ => [%w[ab], %w[c]],
148
+ /cd(?:ef|gh)|xyz/ => [%w[cdef], %w[cdgh], %w[xyz]],
149
+ /(cd(?:ef|gh)|xyz)/ => [%w[cdef], %w[cdgh], %w[xyz]],
150
+ /cd(ef|gh)+/ => [%w[cdef], %w[cdgh]],
151
+ /cd(ef|gh)?/ => [%w[cd]],
152
+ /cd(ef|gh)?ij/ => [%w[cdij], %w[cdefij], %w[cdghij]],
153
+ /cd(ef|gh)+ij/ => [%w[cdef ij], %w[cdgh ij]],
154
+ /cd(ef|gh){2}ij/ => [%w[cdefefij], %w[cdefghij], %w[cdghefij], %w[cdghghij]],
155
+ /(cd(ef|g*))/ => [%w[cd]],
156
+ /a|b*/ => [],
157
+ /ab(?:c|d?)/ => [%w[ab]],
158
+ /ab(c|d)|a*/ => [],
159
+ /(abc)?(d|e)/ => [%w[d], %w[e]],
160
+ /(abc*de)?(d|e)/ => [%w[d], %w[e]],
161
+ /(abc*de)?(d|e?)/ => [],
162
+ /(abc)?(d|e?)/ => [],
163
+ /ab(cd){0,2}ef/ => [%w[ab ef]],
164
+ /ab(cd){0,1}ef/ => [%w[abef], %w[abcdef]],
165
+ /ab(cd|cd)ef/ => [%w[abcdef]],
166
+ /ab(cd|cd)?ef/ => [%w[abef], %w[abcdef]],
167
+ /ab\\?cd/ => [%w[abcd], %w[ab\cd]]
96
168
  )
97
169
  end
98
170
 
@@ -152,5 +224,13 @@ RSpec.describe Capybara::Selector::RegexpDisassembler do
152
224
  hsh.each do |regexp, expected|
153
225
  expect(Capybara::Selector::RegexpDisassembler.new(regexp).substrings).to eq expected
154
226
  end
227
+ verify_alternated_strings(hsh, wrap: true)
228
+ end
229
+
230
+ def verify_alternated_strings(hsh, wrap: false)
231
+ hsh.each do |regexp, expected|
232
+ expected = [expected] if wrap && (expected != [])
233
+ expect(Capybara::Selector::RegexpDisassembler.new(regexp).alternated_substrings).to eq expected
234
+ end
155
235
  end
156
236
  end
@@ -301,6 +301,9 @@ RSpec.describe Capybara do
301
301
  describe ':id selector' do
302
302
  it 'finds by locator' do
303
303
  expect(string.find(:id, 'my_text_input')[:name]).to eq 'form[my_text_input]'
304
+ expect(string.find(:id, /my_text_input/)[:name]).to eq 'form[my_text_input]'
305
+ expect(string.find(:id, /_text_/)[:name]).to eq 'form[my_text_input]'
306
+ expect(string.find(:id, /i[nmo]/)[:name]).to eq 'form[my_text_input]'
304
307
  end
305
308
  end
306
309
 
@@ -5,29 +5,23 @@ require 'selenium-webdriver'
5
5
  require 'shared_selenium_session'
6
6
  require 'rspec/shared_spec_matchers'
7
7
 
8
- CHROME_DRIVER = ENV['HEADLESS'] ? :selenium_chrome_headless : :selenium_chrome
8
+ CHROME_DRIVER = :selenium_chrome
9
9
 
10
- Capybara.register_driver :selenium_chrome do |app|
11
- driver = Capybara::Selenium::Driver.new(app, browser: :chrome)
12
- driver.browser.download_path = Capybara.save_path
13
- driver
14
- end
10
+ browser_options = ::Selenium::WebDriver::Chrome::Options.new
11
+ browser_options.headless! if ENV['HEADLESS']
12
+ browser_options.add_option(:w3c, !!ENV['W3C'])
15
13
 
16
- Capybara.register_driver :selenium_chrome_headless do |app|
17
- browser_options = ::Selenium::WebDriver::Chrome::Options.new
18
- browser_options.headless!
19
- browser_options.add_option(:w3c, !!ENV['W3C'])
20
- driver = Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options)
21
- driver.browser.download_path = Capybara.save_path
22
- driver
14
+ Capybara.register_driver :selenium_chrome do |app|
15
+ Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options).tap do |driver|
16
+ driver.browser.download_path = Capybara.save_path
17
+ end
23
18
  end
24
19
 
25
20
  Capybara.register_driver :selenium_chrome_clear_storage do |app|
26
21
  chrome_options = {
27
22
  browser: :chrome,
28
- options: ::Selenium::WebDriver::Chrome::Options.new
23
+ options: browser_options
29
24
  }
30
- chrome_options[:options].headless! if ENV['HEADLESS']
31
25
  Capybara::Selenium::Driver.new(app, chrome_options.merge(clear_local_storage: true, clear_session_storage: true))
32
26
  end
33
27
 
@@ -38,11 +38,12 @@ Capybara.register_driver :selenium_chrome_remote do |app|
38
38
  ensure_selenium_running!
39
39
 
40
40
  url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
41
- caps = Selenium::WebDriver::Remote::Capabilities.chrome
41
+ browser_options = ::Selenium::WebDriver::Chrome::Options.new
42
42
 
43
43
  Capybara::Selenium::Driver.new app,
44
44
  browser: :remote,
45
- desired_capabilities: caps,
45
+ desired_capabilities: :chrome,
46
+ options: browser_options,
46
47
  url: url
47
48
  end
48
49
 
@@ -34,11 +34,12 @@ Capybara.register_driver :selenium_firefox_remote do |app|
34
34
  ensure_selenium_running!
35
35
 
36
36
  url = "http://#{selenium_host}:#{selenium_port}/wd/hub"
37
- caps = Selenium::WebDriver::Remote::Capabilities.firefox
37
+ browser_options = ::Selenium::WebDriver::Firefox::Options.new
38
38
 
39
39
  Capybara::Selenium::Driver.new app,
40
40
  browser: :remote,
41
- desired_capabilities: caps,
41
+ desired_capabilities: :firefox,
42
+ options: browser_options,
42
43
  url: url
43
44
  end
44
45
 
@@ -71,6 +72,9 @@ Capybara::SpecHelper.run_specs TestSessions::RemoteFirefox, FIREFOX_REMOTE_DRIVE
71
72
  pending "FF < 62 doesn't support setting all files at once" if marionette_lt?(62, @session)
72
73
  when 'Capybara::Session selenium_firefox_remote #reset_session! removes ALL cookies'
73
74
  pending "Geckodriver doesn't provide a way to remove cookies outside the current domain"
75
+ when /#accept_confirm should work with nested modals$/
76
+ # skip because this is timing based and hence flaky when set to pending
77
+ skip 'Broken in FF 63 - https://bugzilla.mozilla.org/show_bug.cgi?id=1487358' if marionette_gte?(63, @session)
74
78
  end
75
79
  end
76
80
 
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: 3.10.1
4
+ version: 3.11.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: 2018-11-03 00:00:00.000000000 Z
13
+ date: 2018-11-14 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: addressable
@@ -110,6 +110,20 @@ dependencies:
110
110
  - - "~>"
111
111
  - !ruby/object:Gem::Version
112
112
  version: '3.2'
113
+ - !ruby/object:Gem::Dependency
114
+ name: byebug
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ type: :development
121
+ prerelease: false
122
+ version_requirements: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
113
127
  - !ruby/object:Gem::Dependency
114
128
  name: cucumber
115
129
  requirement: !ruby/object:Gem::Requirement
@@ -222,6 +236,34 @@ dependencies:
222
236
  - - ">="
223
237
  - !ruby/object:Gem::Version
224
238
  version: 3.4.0
239
+ - !ruby/object:Gem::Dependency
240
+ name: rubocop
241
+ requirement: !ruby/object:Gem::Requirement
242
+ requirements:
243
+ - - ">="
244
+ - !ruby/object:Gem::Version
245
+ version: '0'
246
+ type: :development
247
+ prerelease: false
248
+ version_requirements: !ruby/object:Gem::Requirement
249
+ requirements:
250
+ - - ">="
251
+ - !ruby/object:Gem::Version
252
+ version: '0'
253
+ - !ruby/object:Gem::Dependency
254
+ name: rubocop-rspec
255
+ requirement: !ruby/object:Gem::Requirement
256
+ requirements:
257
+ - - ">="
258
+ - !ruby/object:Gem::Version
259
+ version: '0'
260
+ type: :development
261
+ prerelease: false
262
+ version_requirements: !ruby/object:Gem::Requirement
263
+ requirements:
264
+ - - ">="
265
+ - !ruby/object:Gem::Version
266
+ version: '0'
225
267
  - !ruby/object:Gem::Dependency
226
268
  name: selenium-webdriver
227
269
  requirement: !ruby/object:Gem::Requirement
@@ -310,10 +352,18 @@ files:
310
352
  - lib/capybara/rails.rb
311
353
  - lib/capybara/result.rb
312
354
  - lib/capybara/rspec.rb
313
- - lib/capybara/rspec/compound.rb
314
355
  - lib/capybara/rspec/features.rb
315
356
  - lib/capybara/rspec/matcher_proxies.rb
316
357
  - lib/capybara/rspec/matchers.rb
358
+ - lib/capybara/rspec/matchers/base.rb
359
+ - lib/capybara/rspec/matchers/become_closed.rb
360
+ - lib/capybara/rspec/matchers/compound.rb
361
+ - lib/capybara/rspec/matchers/have_current_path.rb
362
+ - lib/capybara/rspec/matchers/have_selector.rb
363
+ - lib/capybara/rspec/matchers/have_style.rb
364
+ - lib/capybara/rspec/matchers/have_text.rb
365
+ - lib/capybara/rspec/matchers/have_title.rb
366
+ - lib/capybara/rspec/matchers/match_selector.rb
317
367
  - lib/capybara/selector.rb
318
368
  - lib/capybara/selector/builders/css_builder.rb
319
369
  - lib/capybara/selector/builders/xpath_builder.rb
@@ -446,6 +496,7 @@ files:
446
496
  - lib/capybara/spec/views/header_links.erb
447
497
  - lib/capybara/spec/views/host_links.erb
448
498
  - lib/capybara/spec/views/initial_alert.erb
499
+ - lib/capybara/spec/views/obscured.erb
449
500
  - lib/capybara/spec/views/path.erb
450
501
  - lib/capybara/spec/views/popup_one.erb
451
502
  - lib/capybara/spec/views/popup_two.erb
@@ -1,86 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- if defined?(::RSpec::Expectations::Version)
4
- module Capybara
5
- module RSpecMatchers
6
- module Compound
7
- include ::RSpec::Matchers::Composable
8
-
9
- def and(matcher)
10
- And.new(self, matcher)
11
- end
12
-
13
- def and_then(matcher)
14
- ::RSpec::Matchers::BuiltIn::Compound::And.new(self, matcher)
15
- end
16
-
17
- def or(matcher)
18
- Or.new(self, matcher)
19
- end
20
-
21
- class CapybaraEvaluator
22
- def initialize(actual)
23
- @actual = actual
24
- @match_results = Hash.new { |hsh, matcher| hsh[matcher] = matcher.matches?(@actual) }
25
- end
26
-
27
- def matcher_matches?(matcher)
28
- @match_results[matcher]
29
- end
30
-
31
- def reset
32
- @match_results.clear
33
- end
34
- end
35
-
36
- # @api private
37
- module Synchronizer
38
- def match(_expected, actual)
39
- @evaluator = CapybaraEvaluator.new(actual)
40
- syncer = sync_element(actual)
41
- begin
42
- syncer.synchronize do
43
- @evaluator.reset
44
- raise ::Capybara::ElementNotFound unless synchronized_match?
45
-
46
- true
47
- end
48
- rescue StandardError
49
- false
50
- end
51
- end
52
-
53
- def sync_element(el)
54
- if el.respond_to? :synchronize
55
- el
56
- elsif el.respond_to? :current_scope
57
- el.current_scope
58
- else
59
- Capybara.string(el)
60
- end
61
- end
62
- end
63
-
64
- class And < ::RSpec::Matchers::BuiltIn::Compound::And
65
- include Synchronizer
66
-
67
- private
68
-
69
- def synchronized_match?
70
- [matcher_1_matches?, matcher_2_matches?].all?
71
- end
72
- end
73
-
74
- class Or < ::RSpec::Matchers::BuiltIn::Compound::Or
75
- include Synchronizer
76
-
77
- private
78
-
79
- def synchronized_match?
80
- [matcher_1_matches?, matcher_2_matches?].any?
81
- end
82
- end
83
- end
84
- end
85
- end
86
- end