capybara 3.32.0 → 3.35.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +99 -15
  3. data/README.md +9 -4
  4. data/lib/capybara.rb +18 -8
  5. data/lib/capybara/config.rb +4 -6
  6. data/lib/capybara/cucumber.rb +1 -1
  7. data/lib/capybara/driver/base.rb +4 -0
  8. data/lib/capybara/helpers.rb +25 -1
  9. data/lib/capybara/minitest.rb +2 -3
  10. data/lib/capybara/minitest/spec.rb +14 -11
  11. data/lib/capybara/node/actions.rb +16 -21
  12. data/lib/capybara/node/base.rb +6 -6
  13. data/lib/capybara/node/element.rb +1 -5
  14. data/lib/capybara/node/finders.rb +7 -6
  15. data/lib/capybara/node/matchers.rb +12 -12
  16. data/lib/capybara/node/simple.rb +5 -1
  17. data/lib/capybara/queries/ancestor_query.rb +1 -1
  18. data/lib/capybara/queries/current_path_query.rb +14 -4
  19. data/lib/capybara/queries/selector_query.rb +40 -18
  20. data/lib/capybara/queries/sibling_query.rb +1 -1
  21. data/lib/capybara/queries/style_query.rb +1 -1
  22. data/lib/capybara/queries/text_query.rb +7 -1
  23. data/lib/capybara/rack_test/browser.rb +7 -3
  24. data/lib/capybara/rack_test/driver.rb +1 -0
  25. data/lib/capybara/rack_test/form.rb +1 -1
  26. data/lib/capybara/rack_test/node.rb +1 -1
  27. data/lib/capybara/registration_container.rb +44 -0
  28. data/lib/capybara/registrations/drivers.rb +18 -12
  29. data/lib/capybara/registrations/patches/puma_ssl.rb +3 -1
  30. data/lib/capybara/registrations/servers.rb +3 -2
  31. data/lib/capybara/result.rb +10 -11
  32. data/lib/capybara/rspec.rb +2 -0
  33. data/lib/capybara/rspec/matcher_proxies.rb +1 -1
  34. data/lib/capybara/rspec/matchers.rb +7 -6
  35. data/lib/capybara/rspec/matchers/have_current_path.rb +2 -2
  36. data/lib/capybara/rspec/matchers/have_text.rb +1 -1
  37. data/lib/capybara/rspec/matchers/match_style.rb +5 -0
  38. data/lib/capybara/selector.rb +12 -3
  39. data/lib/capybara/selector/builders/css_builder.rb +1 -1
  40. data/lib/capybara/selector/builders/xpath_builder.rb +3 -1
  41. data/lib/capybara/selector/definition.rb +11 -9
  42. data/lib/capybara/selector/definition/button.rb +26 -14
  43. data/lib/capybara/selector/definition/css.rb +1 -1
  44. data/lib/capybara/selector/definition/datalist_input.rb +1 -1
  45. data/lib/capybara/selector/definition/element.rb +2 -1
  46. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  47. data/lib/capybara/selector/definition/label.rb +1 -1
  48. data/lib/capybara/selector/definition/link.rb +8 -0
  49. data/lib/capybara/selector/definition/select.rb +1 -1
  50. data/lib/capybara/selector/definition/table.rb +1 -1
  51. data/lib/capybara/selector/definition/table_row.rb +2 -2
  52. data/lib/capybara/selector/filter_set.rb +2 -2
  53. data/lib/capybara/selector/selector.rb +9 -1
  54. data/lib/capybara/selenium/atoms/src/isDisplayed.js +1 -1
  55. data/lib/capybara/selenium/driver.rb +51 -7
  56. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +9 -11
  57. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +9 -11
  58. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +3 -3
  59. data/lib/capybara/selenium/extensions/find.rb +4 -4
  60. data/lib/capybara/selenium/extensions/scroll.rb +8 -10
  61. data/lib/capybara/selenium/logger_suppressor.rb +1 -1
  62. data/lib/capybara/selenium/node.rb +23 -6
  63. data/lib/capybara/selenium/nodes/chrome_node.rb +23 -5
  64. data/lib/capybara/selenium/nodes/firefox_node.rb +7 -2
  65. data/lib/capybara/selenium/nodes/safari_node.rb +1 -1
  66. data/lib/capybara/selenium/patches/action_pauser.rb +4 -1
  67. data/lib/capybara/selenium/patches/atoms.rb +4 -4
  68. data/lib/capybara/selenium/patches/logs.rb +7 -9
  69. data/lib/capybara/server/animation_disabler.rb +8 -3
  70. data/lib/capybara/server/middleware.rb +4 -2
  71. data/lib/capybara/session.rb +23 -14
  72. data/lib/capybara/session/config.rb +3 -1
  73. data/lib/capybara/session/matchers.rb +11 -11
  74. data/lib/capybara/spec/public/test.js +13 -1
  75. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  76. data/lib/capybara/spec/session/check_spec.rb +6 -0
  77. data/lib/capybara/spec/session/click_button_spec.rb +11 -0
  78. data/lib/capybara/spec/session/current_url_spec.rb +11 -1
  79. data/lib/capybara/spec/session/has_button_spec.rb +51 -0
  80. data/lib/capybara/spec/session/has_css_spec.rb +2 -1
  81. data/lib/capybara/spec/session/has_current_path_spec.rb +15 -2
  82. data/lib/capybara/spec/session/has_field_spec.rb +16 -0
  83. data/lib/capybara/spec/session/has_select_spec.rb +4 -4
  84. data/lib/capybara/spec/session/has_selector_spec.rb +4 -4
  85. data/lib/capybara/spec/session/has_text_spec.rb +0 -11
  86. data/lib/capybara/spec/session/html_spec.rb +1 -1
  87. data/lib/capybara/spec/session/matches_style_spec.rb +2 -2
  88. data/lib/capybara/spec/session/node_spec.rb +29 -9
  89. data/lib/capybara/spec/session/refresh_spec.rb +2 -1
  90. data/lib/capybara/spec/session/save_page_spec.rb +4 -4
  91. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +1 -1
  92. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -1
  93. data/lib/capybara/spec/session/window/window_spec.rb +1 -1
  94. data/lib/capybara/spec/session/window/windows_spec.rb +1 -1
  95. data/lib/capybara/spec/spec_helper.rb +12 -12
  96. data/lib/capybara/spec/test_app.rb +23 -21
  97. data/lib/capybara/spec/views/form.erb +28 -1
  98. data/lib/capybara/spec/views/with_animation.erb +8 -0
  99. data/lib/capybara/spec/views/with_dragula.erb +3 -1
  100. data/lib/capybara/spec/views/with_jquery_animation.erb +24 -0
  101. data/lib/capybara/spec/views/with_js.erb +3 -0
  102. data/lib/capybara/spec/views/with_sortable_js.erb +1 -1
  103. data/lib/capybara/version.rb +1 -1
  104. data/lib/capybara/window.rb +3 -7
  105. data/spec/basic_node_spec.rb +9 -8
  106. data/spec/capybara_spec.rb +1 -1
  107. data/spec/dsl_spec.rb +14 -1
  108. data/spec/fixtures/selenium_driver_rspec_success.rb +1 -1
  109. data/spec/minitest_spec.rb +3 -2
  110. data/spec/rack_test_spec.rb +16 -5
  111. data/spec/result_spec.rb +1 -17
  112. data/spec/rspec/features_spec.rb +3 -1
  113. data/spec/rspec/scenarios_spec.rb +4 -0
  114. data/spec/rspec/shared_spec_matchers.rb +63 -51
  115. data/spec/rspec_spec.rb +4 -0
  116. data/spec/selector_spec.rb +17 -2
  117. data/spec/selenium_spec_chrome.rb +39 -20
  118. data/spec/selenium_spec_chrome_remote.rb +5 -1
  119. data/spec/selenium_spec_firefox.rb +15 -13
  120. data/spec/server_spec.rb +60 -49
  121. data/spec/shared_selenium_node.rb +10 -0
  122. data/spec/shared_selenium_session.rb +98 -7
  123. data/spec/spec_helper.rb +1 -1
  124. metadata +50 -15
  125. data/lib/capybara/spec/session/source_spec.rb +0 -0
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rubocop:disable RSpec/MultipleDescribes
4
+
3
5
  require 'spec_helper'
4
6
 
5
7
  RSpec.describe 'capybara/rspec' do
@@ -143,3 +145,5 @@ feature 'Feature DSL' do
143
145
  expect(page.body).to include('Another World')
144
146
  end
145
147
  end
148
+
149
+ # rubocop:enable RSpec/MultipleDescribes
@@ -3,6 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe Capybara do
6
+ include Capybara::RSpecMatchers
6
7
  describe 'Selectors' do
7
8
  let :string do
8
9
  described_class.string <<-STRING
@@ -326,9 +327,23 @@ RSpec.describe Capybara do
326
327
  expect(string.find(:custom_xpath_selector, './/div', class: /dOm WoR/i)[:id]).to eq 'random_words'
327
328
  end
328
329
 
329
- it 'accepts Regexp for CSS base selectors' do
330
+ it 'accepts Regexp for CSS based selectors' do
330
331
  expect(string.find(:custom_css_selector, 'div', class: /random/)[:id]).to eq 'random_words'
331
332
  end
333
+
334
+ it 'accepts Regexp for individual class names for XPath based selectors' do
335
+ expect(string.find(:custom_xpath_selector, './/div', class: [/random/, 'some'])[:id]).to eq 'random_words'
336
+ expect(string.find(:custom_xpath_selector, './/div', class: [/om/, /wor/])[:id]).to eq 'random_words'
337
+ expect { string.find(:custom_xpath_selector, './/div', class: [/not/, /wor/]) }.to raise_error(Capybara::ElementNotFound)
338
+ expect { string.find(:custom_xpath_selector, './/div', class: [/dom wor/]) }.to raise_error(Capybara::ElementNotFound)
339
+ end
340
+
341
+ it 'accepts Regexp for individual class names for CSS based selectors' do
342
+ expect(string.find(:custom_css_selector, 'div', class: [/random/])[:id]).to eq 'random_words'
343
+ expect(string.find(:custom_css_selector, 'div', class: [/om/, /wor/, 'some'])[:id]).to eq 'random_words'
344
+ expect { string.find(:custom_css_selector, 'div', class: [/not/, /wor/]) }.to raise_error(Capybara::ElementNotFound)
345
+ expect { string.find(:custom_css_selector, 'div', class: [/dom wor/]) }.to raise_error(Capybara::ElementNotFound)
346
+ end
332
347
  end
333
348
 
334
349
  context 'with :style option' do
@@ -476,7 +491,7 @@ RSpec.describe Capybara do
476
491
  end
477
492
 
478
493
  describe ':link_or_button selector' do
479
- around(:all) do |example|
494
+ around do |example|
480
495
  described_class.modify_selector(:link_or_button) do
481
496
  expression_filter(:random) { |xpath, _| xpath } # do nothing filter
482
497
  end
@@ -19,39 +19,56 @@ browser_options.add_preference('download.default_directory', Capybara.save_path)
19
19
  browser_options.add_preference(:download, default_directory: Capybara.save_path)
20
20
 
21
21
  Capybara.register_driver :selenium_chrome do |app|
22
- Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options, timeout: 30).tap do |driver|
22
+ version = Capybara::Selenium::Driver.load_selenium
23
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
24
+ driver_options = { browser: :chrome, timeout: 30 }.tap do |opts|
25
+ opts[options_key] = browser_options
26
+ end
27
+
28
+ Capybara::Selenium::Driver.new(app, **driver_options).tap do |driver|
23
29
  # Set download dir for Chrome < 77
24
30
  driver.browser.download_path = Capybara.save_path
25
31
  end
26
32
  end
27
33
 
28
34
  Capybara.register_driver :selenium_chrome_not_clear_storage do |app|
29
- chrome_options = {
30
- browser: :chrome,
31
- options: browser_options
32
- }
33
- Capybara::Selenium::Driver.new(app, **chrome_options.merge(clear_local_storage: false, clear_session_storage: false))
35
+ version = Capybara::Selenium::Driver.load_selenium
36
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
37
+ chrome_options = { browser: :chrome, clear_local_storage: false, clear_session_storage: false }.tap do |opts|
38
+ opts[options_key] = browser_options
39
+ end
40
+
41
+ Capybara::Selenium::Driver.new(app, **chrome_options)
34
42
  end
35
43
 
36
44
  Capybara.register_driver :selenium_chrome_not_clear_session_storage do |app|
37
- chrome_options = {
38
- browser: :chrome,
39
- options: browser_options
40
- }
41
- Capybara::Selenium::Driver.new(app, **chrome_options.merge(clear_session_storage: false))
45
+ version = Capybara::Selenium::Driver.load_selenium
46
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
47
+ chrome_options = { browser: :chrome, clear_session_storage: false }.tap do |opts|
48
+ opts[options_key] = browser_options
49
+ end
50
+
51
+ Capybara::Selenium::Driver.new(app, **chrome_options)
42
52
  end
43
53
 
44
54
  Capybara.register_driver :selenium_chrome_not_clear_local_storage do |app|
45
- chrome_options = {
46
- browser: :chrome,
47
- options: browser_options
48
- }
49
- Capybara::Selenium::Driver.new(app, **chrome_options.merge(clear_local_storage: false))
55
+ version = Capybara::Selenium::Driver.load_selenium
56
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
57
+ chrome_options = { browser: :chrome, clear_local_storage: false }.tap do |opts|
58
+ opts[options_key] = browser_options
59
+ end
60
+ Capybara::Selenium::Driver.new(app, **chrome_options)
50
61
  end
51
62
 
52
63
  Capybara.register_driver :selenium_driver_subclass_with_chrome do |app|
64
+ version = Capybara::Selenium::Driver.load_selenium
65
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
53
66
  subclass = Class.new(Capybara::Selenium::Driver)
54
- subclass.new(app, browser: :chrome, options: browser_options, timeout: 30)
67
+ chrome_options = { browser: :chrome, timeout: 30 }.tap do |opts|
68
+ opts[options_key] = browser_options
69
+ end
70
+
71
+ subclass.new(app, **chrome_options)
55
72
  end
56
73
 
57
74
  module TestSessions
@@ -70,8 +87,6 @@ Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_DRIVER.to_s, capybar
70
87
  pending "Chrome headless doesn't support maximize" if ENV['HEADLESS']
71
88
  when /Capybara::Window#fullscreen should be able to fullscreen the window/
72
89
  skip 'Chromedriver hangs on attempts to fullscreen in headless mode' if ENV['HEADLESS']
73
- when /details non-summary descendants should be non-visible/
74
- pending 'Chromedriver built-in is_displayed is currently broken' if ENV['W3C'] == 'false'
75
90
  when /node #right_click delay should delay the mouse up/
76
91
  skip "Legacy selenium doesn't support separate right button down/up" if ENV['W3C'] == 'false'
77
92
  end
@@ -173,7 +188,7 @@ RSpec.describe 'Capybara::Session with chrome' do
173
188
  before { skip 'Only makes sense in W3C mode' if ENV['W3C'] == 'false' }
174
189
 
175
190
  it 'does not error getting log types' do
176
- skip if Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0]) < Gem::Version.new('75.0.3770.90')
191
+ skip if Gem::Requirement.new('< 75.0.3770.90').satisfied_by? chromedriver_version
177
192
  expect do
178
193
  session.driver.browser.manage.logs.available_types
179
194
  end.not_to raise_error
@@ -185,4 +200,8 @@ RSpec.describe 'Capybara::Session with chrome' do
185
200
  end.not_to raise_error
186
201
  end
187
202
  end
203
+
204
+ def chromedriver_version
205
+ Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0])
206
+ end
188
207
  end
@@ -81,7 +81,7 @@ RSpec.describe 'Capybara::Session with remote Chrome' do
81
81
  before { skip 'Only makes sense in W3C mode' if ENV['W3C'] == 'false' }
82
82
 
83
83
  it 'does not error when getting log types' do
84
- skip if Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0]) < Gem::Version.new('75.0.3770.90')
84
+ skip unless Gem::Requirement.new('>= 75.0.3770.90').satisfied_by? chromedriver_version
85
85
  expect do
86
86
  session.driver.browser.manage.logs.available_types
87
87
  end.not_to raise_error
@@ -93,4 +93,8 @@ RSpec.describe 'Capybara::Session with remote Chrome' do
93
93
  end.not_to raise_error
94
94
  end
95
95
  end
96
+
97
+ def chromedriver_version
98
+ Gem::Version.new(session.driver.browser.capabilities['chrome']['chromedriverVersion'].split[0])
99
+ end
96
100
  end
@@ -14,28 +14,30 @@ browser_options.profile = Selenium::WebDriver::Firefox::Profile.new.tap do |prof
14
14
  profile['browser.download.dir'] = Capybara.save_path
15
15
  profile['browser.download.folderList'] = 2
16
16
  profile['browser.helperApps.neverAsk.saveToDisk'] = 'text/csv'
17
+ profile['browser.startup.homepage'] = 'about:blank' # workaround bug in Selenium 4 alpha4-7
17
18
  end
18
19
 
19
20
  Capybara.register_driver :selenium_firefox do |app|
20
21
  # ::Selenium::WebDriver.logger.level = "debug"
21
- Capybara::Selenium::Driver.new(
22
- app,
23
- browser: :firefox,
24
- options: browser_options,
25
- timeout: 31
22
+ version = Capybara::Selenium::Driver.load_selenium
23
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
24
+ driver_options = { browser: :firefox, timeout: 31 }.tap do |opts|
25
+ opts[options_key] = browser_options
26
26
  # Get a trace level log from geckodriver
27
27
  # :driver_opts => { args: ['-vv'] }
28
- )
28
+ end
29
+
30
+ Capybara::Selenium::Driver.new(app, **driver_options)
29
31
  end
30
32
 
31
33
  Capybara.register_driver :selenium_firefox_not_clear_storage do |app|
32
- Capybara::Selenium::Driver.new(
33
- app,
34
- browser: :firefox,
35
- clear_local_storage: false,
36
- clear_session_storage: false,
37
- options: browser_options
38
- )
34
+ version = Capybara::Selenium::Driver.load_selenium
35
+ options_key = Capybara::Selenium::Driver::CAPS_VERSION.satisfied_by?(version) ? :capabilities : :options
36
+ driver_options = { browser: :firefox, clear_local_storage: false, clear_session_storage: false }.tap do |opts|
37
+ opts[options_key] = browser_options
38
+ end
39
+
40
+ Capybara::Selenium::Driver.new(app, **driver_options)
39
41
  end
40
42
 
41
43
  module TestSessions
@@ -75,25 +75,21 @@ RSpec.describe Capybara::Server do
75
75
  end
76
76
 
77
77
  it 'should handle that getting available ports fails randomly' do
78
- begin
79
- # Use a port to force a EADDRINUSE error to be generated
80
- server = TCPServer.new('0.0.0.0', 0)
81
- server_port = server.addr[1]
82
- d_server = instance_double('TCPServer', addr: [nil, server_port, nil, nil], close: nil)
83
- call_count = 0
84
- allow(TCPServer).to receive(:new).and_wrap_original do |m, *args|
85
- begin
86
- call_count.zero? ? d_server : m.call(*args)
87
- ensure
88
- call_count += 1
89
- end
90
- end
91
-
92
- port = described_class.new(Object.new, host: '0.0.0.0').port
93
- expect(port).not_to eq(server_port)
78
+ # Use a port to force a EADDRINUSE error to be generated
79
+ server = TCPServer.new('0.0.0.0', 0)
80
+ server_port = server.addr[1]
81
+ d_server = instance_double('TCPServer', addr: [nil, server_port, nil, nil], close: nil)
82
+ call_count = 0
83
+ allow(TCPServer).to receive(:new).and_wrap_original do |m, *args|
84
+ call_count.zero? ? d_server : m.call(*args)
94
85
  ensure
95
- server&.close
86
+ call_count += 1
96
87
  end
88
+
89
+ port = described_class.new(Object.new, host: '0.0.0.0').port
90
+ expect(port).not_to eq(server_port)
91
+ ensure
92
+ server&.close
97
93
  end
98
94
 
99
95
  it 'should return its #base_url' do
@@ -103,30 +99,47 @@ RSpec.describe Capybara::Server do
103
99
  expect(uri.to_hash).to include(scheme: 'http', host: server.host, port: server.port)
104
100
  end
105
101
 
106
- it 'should support SSL' do
107
- begin
108
- key = File.join(Dir.pwd, 'spec', 'fixtures', 'key.pem')
109
- cert = File.join(Dir.pwd, 'spec', 'fixtures', 'certificate.pem')
110
- Capybara.server = :puma, { Host: "ssl://#{Capybara.server_host}?key=#{key}&cert=#{cert}" }
111
- app = proc { |_env| [200, {}, ['Hello SSL Server!']] }
112
- server = described_class.new(app).boot
102
+ it 'should call #clamp on the puma configuration to ensure that environment is a string' do
103
+ Capybara.server = :puma
104
+ app_proc = proc { |_env| [200, {}, ['Hello Puma!']] }
105
+ require 'puma'
106
+ allow(Puma::Server).to receive(:new).and_wrap_original do |method, app, events, options|
107
+ # If #clamp is not called on the puma config then this will be a Proc
108
+ expect(options.fetch(:environment)).to be_a(String)
109
+ method.call(app, events, options)
110
+ end
111
+ server = described_class.new(app_proc).boot
112
+ expect(Puma::Server).to have_received(:new).with(
113
+ anything,
114
+ anything,
115
+ satisfy { |opts| opts.final_options[:Port] == server.port }
116
+ )
117
+ ensure
118
+ Capybara.server = :default
119
+ end
113
120
 
114
- expect do
115
- Net::HTTP.start(server.host, server.port, max_retries: 0) { |http| http.get('/__identify__') }
116
- end.to(raise_error do |e|
117
- expect(e.is_a?(EOFError) || e.is_a?(Net::ReadTimeout)).to be true
118
- end)
121
+ it 'should support SSL' do
122
+ key = File.join(Dir.pwd, 'spec', 'fixtures', 'key.pem')
123
+ cert = File.join(Dir.pwd, 'spec', 'fixtures', 'certificate.pem')
124
+ Capybara.server = :puma, { Host: "ssl://#{Capybara.server_host}?key=#{key}&cert=#{cert}" }
125
+ app = proc { |_env| [200, {}, ['Hello SSL Server!']] }
126
+ server = described_class.new(app).boot
119
127
 
120
- res = Net::HTTP.start(server.host, server.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https|
121
- https.get('/')
122
- end
128
+ expect do
129
+ Net::HTTP.start(server.host, server.port, max_retries: 0) { |http| http.get('/__identify__') }
130
+ end.to(raise_error do |e|
131
+ expect(e.is_a?(EOFError) || e.is_a?(Net::ReadTimeout)).to be true
132
+ end)
123
133
 
124
- expect(res.body).to include('Hello SSL Server!')
125
- uri = ::Addressable::URI.parse(server.base_url)
126
- expect(uri.to_hash).to include(scheme: 'https', host: server.host, port: server.port)
127
- ensure
128
- Capybara.server = :default
134
+ res = Net::HTTP.start(server.host, server.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https|
135
+ https.get('/')
129
136
  end
137
+
138
+ expect(res.body).to include('Hello SSL Server!')
139
+ uri = ::Addressable::URI.parse(server.base_url)
140
+ expect(uri.to_hash).to include(scheme: 'https', host: server.host, port: server.port)
141
+ ensure
142
+ Capybara.server = :default
130
143
  end
131
144
 
132
145
  context 'When Capybara.reuse_server is true' do
@@ -224,19 +237,17 @@ RSpec.describe Capybara::Server do
224
237
  end
225
238
 
226
239
  it 'should raise server errors when the server errors before the timeout' do
227
- begin
228
- Capybara.register_server :kaboom do
229
- sleep 0.1
230
- raise 'kaboom'
231
- end
232
- Capybara.server = :kaboom
233
-
234
- expect do
235
- described_class.new(proc { |e| }).boot
236
- end.to raise_error(RuntimeError, 'kaboom')
237
- ensure
238
- Capybara.server = :default
240
+ Capybara.register_server :kaboom do
241
+ sleep 0.1
242
+ raise 'kaboom'
239
243
  end
244
+ Capybara.server = :kaboom
245
+
246
+ expect do
247
+ described_class.new(proc { |e| }).boot
248
+ end.to raise_error(RuntimeError, 'kaboom')
249
+ ensure
250
+ Capybara.server = :default
240
251
  end
241
252
 
242
253
  it 'should raise an error when there are pending requests' do
@@ -35,6 +35,16 @@ RSpec.shared_examples 'Capybara::Node' do |session, _mode|
35
35
  end
36
36
  end
37
37
 
38
+ describe '#set' do
39
+ it 'respects maxlength when using rapid set' do
40
+ session.visit('/form')
41
+ inp = session.find(:css, '#long_length')
42
+ value = (0...50).map { |i| ((i % 26) + 65).chr }.join
43
+ inp.set(value, rapid: true)
44
+ expect(inp.value).to eq value[0...35]
45
+ end
46
+ end
47
+
38
48
  describe '#visible?' do
39
49
  let(:bridge) do
40
50
  session.driver.browser.send(:bridge)
@@ -160,6 +160,15 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
160
160
  fill_options: { clear: :none })
161
161
  expect(session.find(:fillable_field, 'form_first_name').value).to eq('JohnHarry')
162
162
  end
163
+
164
+ it 'works with rapid fill' do
165
+ pending 'Safari overwrites by default - need to figure out a workaround' if safari?(session)
166
+
167
+ long_string = (0...60).map { |i| ((i % 26) + 65).chr }.join
168
+ session.visit('/form')
169
+ session.fill_in('form_first_name', with: long_string, fill_options: { clear: :none })
170
+ expect(session.find(:fillable_field, 'form_first_name').value).to eq("John#{long_string}")
171
+ end
163
172
  end
164
173
 
165
174
  describe '#fill_in with Date' do
@@ -205,6 +214,26 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
205
214
  end
206
215
  end
207
216
 
217
+ describe '#fill_in with Emoji' do
218
+ it 'sends emojis' do
219
+ session.visit('/form')
220
+ session.fill_in('form_first_name', with: 'a😀cd😴 🛌🏽🇵🇹 e🤾🏽‍♀️f')
221
+ expect(session.find(:fillable_field, 'form_first_name').value).to eq('a😀cd😴 🛌🏽🇵🇹 e🤾🏽‍♀️f')
222
+ end
223
+ end
224
+
225
+ describe '#send_keys' do
226
+ it 'defaults to sending keys to the document.activeElement' do
227
+ session.visit('/form')
228
+
229
+ expect(session.evaluate_script('document.activeElement')).to eq(session.find('//body'))
230
+
231
+ session.send_keys(:tab)
232
+
233
+ expect(session.evaluate_script('document.activeElement')).to eq(session.first(:field))
234
+ end
235
+ end
236
+
208
237
  describe '#path' do
209
238
  it 'returns xpath' do
210
239
  # this is here because it is testing for an XPath that is specific to the algorithm used in the selenium driver
@@ -360,15 +389,64 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
360
389
 
361
390
  it 'should disable CSS animations (set to 0s)' do
362
391
  @animation_session.visit('with_animation')
392
+ sleep 1
363
393
  @animation_session.click_link('animate me away')
364
394
  expect(@animation_session).to have_no_link('animate me away', wait: 0.5)
365
395
  end
366
396
 
367
397
  it 'should disable CSS animations on pseudo elements (set to 0s)' do
368
398
  @animation_session.visit('with_animation')
399
+ sleep 1
369
400
  @animation_session.find_link('animate me away').right_click
370
401
  expect(@animation_session).to have_content('Animation Ended', wait: 0.1)
371
402
  end
403
+
404
+ it 'should scroll the page instantly', requires: [:js] do
405
+ @animation_session.visit('with_animation')
406
+ scroll_y = @animation_session.evaluate_script(<<~JS)
407
+ (function(){
408
+ window.scrollTo(0,500);
409
+ return window.scrollY;
410
+ })()
411
+ JS
412
+ expect(scroll_y).to eq 500
413
+ end
414
+
415
+ it 'should scroll the page instantly without jquery animation', requires: [:js] do
416
+ @animation_session.visit('with_jquery_animation')
417
+ @animation_session.click_link('scroll top 500')
418
+ scroll_y = @animation_session.evaluate_script('window.scrollY')
419
+ expect(scroll_y).to eq 500
420
+ end
421
+ end
422
+
423
+ context 'when set to `false`' do
424
+ before(:context) do # rubocop:disable RSpec/BeforeAfterAll
425
+ skip "Safari doesn't support multiple sessions" if safari?(session)
426
+ # NOTE: Although Capybara.SpecHelper.reset! sets Capybara.disable_animation to false,
427
+ # it doesn't affect any of these tests because the settings are applied per-session
428
+ Capybara.disable_animation = false
429
+ @animation_session = Capybara::Session.new(session.mode, TestApp.new)
430
+ end
431
+
432
+ it 'should scroll the page with a smooth animation', requires: [:js] do
433
+ @animation_session.visit('with_animation')
434
+ scroll_y = @animation_session.evaluate_script(<<~JS)
435
+ (function(){
436
+ window.scrollTo(0,500);
437
+ return window.scrollY;
438
+ })()
439
+ JS
440
+ # measured over 0.5 seconds: 0, 75, 282, 478, 500
441
+ expect(scroll_y).to be < 500
442
+ end
443
+
444
+ it 'should scroll the page with jquery animation', requires: [:js] do
445
+ @animation_session.visit('with_jquery_animation')
446
+ @animation_session.click_link('scroll top 500')
447
+ scroll_y = @animation_session.evaluate_script('window.scrollY')
448
+ expect(scroll_y).to be < 500
449
+ end
372
450
  end
373
451
 
374
452
  context 'if we pass in css that matches elements' do
@@ -382,12 +460,14 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
382
460
 
383
461
  it 'should disable CSS transitions' do
384
462
  @animation_session_with_matching_css.visit('with_animation')
463
+ sleep 1
385
464
  @animation_session_with_matching_css.click_link('transition me away')
386
465
  expect(@animation_session_with_matching_css).to have_no_link('transition me away', wait: 0.5)
387
466
  end
388
467
 
389
468
  it 'should disable CSS animations' do
390
469
  @animation_session_with_matching_css.visit('with_animation')
470
+ sleep 1
391
471
  @animation_session_with_matching_css.click_link('animate me away')
392
472
  expect(@animation_session_with_matching_css).to have_no_link('animate me away', wait: 0.5)
393
473
  end
@@ -404,6 +484,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
404
484
 
405
485
  it 'should not disable CSS transitions' do
406
486
  @animation_session_without_matching_css.visit('with_animation')
487
+ sleep 1
407
488
  @animation_session_without_matching_css.click_link('transition me away')
408
489
  sleep 0.5 # Wait long enough for click to have been processed
409
490
  expect(@animation_session_without_matching_css).to have_link('transition me away', wait: false)
@@ -412,6 +493,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
412
493
 
413
494
  it 'should not disable CSS animations' do
414
495
  @animation_session_without_matching_css.visit('with_animation')
496
+ sleep 1
415
497
  @animation_session_without_matching_css.click_link('animate me away')
416
498
  sleep 0.5 # Wait long enough for click to have been processed
417
499
  expect(@animation_session_without_matching_css).to have_link('animate me away', wait: false)
@@ -425,7 +507,7 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
425
507
  it 'can find html5 svg elements' do
426
508
  session.visit('with_html5_svg')
427
509
  expect(session).to have_selector(:element, :svg)
428
- expect(session).to have_selector(:element, :rect, visible: true)
510
+ expect(session).to have_selector(:element, :rect, visible: :visible)
429
511
  expect(session).to have_selector(:element, :circle)
430
512
  expect(session).to have_selector(:element, :linearGradient, visible: :all)
431
513
  end
@@ -441,21 +523,30 @@ RSpec.shared_examples 'Capybara::Session' do |session, mode|
441
523
  context 'controlled components' do
442
524
  it 'can set and clear a text field' do
443
525
  skip "This test doesn't support older browsers" if ie?(session)
444
- # session.visit 'https://reactjs.org/docs/forms.html'
445
- # session.all(:css, 'h2#controlled-components ~ p a', text: 'Try it on CodePen')[0].click
446
- # copied into local view
526
+
447
527
  session.visit 'react'
448
- # Not necessary when accessed locally
449
- # session.within_frame(:css, 'iframe.result-iframe:not([src=""])', wait: 10) do
528
+
450
529
  session.fill_in('Name:', with: 'abc')
451
530
  session.accept_prompt 'A name was submitted: abc' do
452
531
  session.click_button('Submit')
453
532
  end
533
+
454
534
  session.fill_in('Name:', with: '')
455
535
  session.accept_prompt(/A name was submitted: $/) do
456
536
  session.click_button('Submit')
457
537
  end
458
- # end
538
+ end
539
+
540
+ it 'works with rapid fill' do
541
+ skip "This test doesn't support older browsers" if ie?(session)
542
+
543
+ session.visit 'react'
544
+ long_string = (0...60).map { |i| ((i % 26) + 65).chr }.join
545
+
546
+ session.fill_in('Name:', with: long_string)
547
+ session.accept_prompt "A name was submitted: #{long_string}" do
548
+ session.click_button('Submit')
549
+ end
459
550
  end
460
551
  end
461
552
  end