capybara 3.10.1 → 3.11.0

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