From 79d5dcddbec9a7cfd9e39da747a85bcfc607326b Mon Sep 17 00:00:00 2001 From: Thomas Walpole Date: Sun, 22 Dec 2019 11:02:00 -0800 Subject: [PATCH] Remove support for Ruby 2.4 --- .rubocop.yml | 2 +- .travis.yml | 12 +-- History.md | 7 ++ capybara.gemspec | 2 +- features/step_definitions/capybara_steps.rb | 8 +- lib/capybara/node/actions.rb | 36 ++++---- lib/capybara/node/matchers.rb | 10 +-- lib/capybara/queries/style_query.rb | 2 +- lib/capybara/selector/definition.rb | 8 +- lib/capybara/selector/definition/table.rb | 2 +- .../driver_specializations/chrome_driver.rb | 14 ++- .../driver_specializations/edge_driver.rb | 14 ++- lib/capybara/selenium/nodes/firefox_node.rb | 2 +- lib/capybara/selenium/patches/logs.rb | 8 +- lib/capybara/spec/test_app.rb | 32 +++---- spec/server_spec.rb | 90 +++++++++---------- 16 files changed, 115 insertions(+), 134 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 9edc76e8..53659a02 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -4,7 +4,7 @@ require: AllCops: DisabledByDefault: false - TargetRubyVersion: 2.4 + TargetRubyVersion: 2.5 Exclude: - 'vendor/**/*' - 'gemfiles/vendor/**/*' diff --git a/.travis.yml b/.travis.yml index 059dde7f..4525cad0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,18 +34,18 @@ cache: matrix: include: - gemfile: gemfiles/Gemfile.gumbo - rvm: 2.5 + rvm: 2.6 script: bundle exec rake rack_smoke - gemfile: Gemfile - rvm: 2.5 + rvm: 2.6 env: CAPYBARA_REMOTE=true - gemfile: Gemfile - rvm: 2.5 + rvm: 2.6 env: - CAPYBARA_REMOTE=true - CAPYBARA_FF=true - gemfile: gemfiles/Gemfile.base-versions - rvm: 2.4 + rvm: 2.5 env: CAPYBARA_FF=true addons: firefox: latest @@ -53,7 +53,7 @@ matrix: packages: - awesome - gemfile: gemfiles/Gemfile.base-versions - rvm: 2.4 + rvm: 2.5 - gemfile: Gemfile rvm: 2.6 env: HEADLESS=true @@ -102,7 +102,7 @@ matrix: addons: firefox: latest - gemfile: Gemfile - rvm: 2.5 + rvm: 2.6 env: CHROME_BETA=true HEADLESS=true addons: chrome: beta diff --git a/History.md b/History.md index 0036ba3e..129cf06b 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,10 @@ +# Version 3.33.0 +Release date: unreleased + +### Changed + +* Ruby 2.5.0+ is now required + # Version 3.32.1 Release date: 2020-04-05 diff --git a/capybara.gemspec b/capybara.gemspec index 8b698ee3..efaa2af1 100644 --- a/capybara.gemspec +++ b/capybara.gemspec @@ -8,7 +8,7 @@ require 'capybara/version' Gem::Specification.new do |s| s.name = 'capybara' s.version = Capybara::VERSION - s.required_ruby_version = '>= 2.4.0' + s.required_ruby_version = '>= 2.5.0' s.license = 'MIT' s.authors = ['Thomas Walpole', 'Jonas Nicklas'] diff --git a/features/step_definitions/capybara_steps.rb b/features/step_definitions/capybara_steps.rb index 76e3de7c..71fb674f 100644 --- a/features/step_definitions/capybara_steps.rb +++ b/features/step_definitions/capybara_steps.rb @@ -13,11 +13,9 @@ Then(/^Capybara should use the "([^"]*)" driver$/) do |driver| end When(/^I use a matcher that fails$/) do - begin - expect(page).to have_css('h1#doesnotexist') - rescue StandardError, RSpec::Expectations::ExpectationNotMetError => e - @error_message = e.message - end + expect(page).to have_css('h1#doesnotexist') +rescue StandardError, RSpec::Expectations::ExpectationNotMetError => e + @error_message = e.message end Then(/^the failing exception should be nice$/) do diff --git a/lib/capybara/node/actions.rb b/lib/capybara/node/actions.rb index e1c6bdc9..7139f810 100644 --- a/lib/capybara/node/actions.rb +++ b/lib/capybara/node/actions.rb @@ -308,16 +308,14 @@ module Capybara def find_select_or_datalist_input(from, options) synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do - begin - find(:select, from, **options) - rescue Capybara::ElementNotFound => select_error # rubocop:disable Naming/RescuedExceptionsVariableName - raise if %i[selected with_selected multiple].any? { |option| options.key?(option) } + find(:select, from, **options) + rescue Capybara::ElementNotFound => select_error # rubocop:disable Naming/RescuedExceptionsVariableName + raise if %i[selected with_selected multiple].any? { |option| options.key?(option) } - begin - find(:datalist_input, from, **options) - rescue Capybara::ElementNotFound => dlinput_error # rubocop:disable Naming/RescuedExceptionsVariableName - raise Capybara::ElementNotFound, "#{select_error.message} and #{dlinput_error.message}" - end + begin + find(:datalist_input, from, **options) + rescue Capybara::ElementNotFound => dlinput_error # rubocop:disable Naming/RescuedExceptionsVariableName + raise Capybara::ElementNotFound, "#{select_error.message} and #{dlinput_error.message}" end end end @@ -367,18 +365,16 @@ module Capybara options[:allow_self] = true if locator.nil? synchronize(Capybara::Queries::BaseQuery.wait(options, session_options.default_max_wait_time)) do - begin - el = find(selector, locator, **options) - el.set(checked) - rescue StandardError => e - raise unless allow_label_click && catch_error?(e) + el = find(selector, locator, **options) + el.set(checked) + rescue StandardError => e + raise unless allow_label_click && catch_error?(e) - begin - el ||= find(selector, locator, **options.merge(visible: :all)) - el.session.find(:label, for: el, visible: true).click unless el.checked? == checked - rescue StandardError # swallow extra errors - raise original - raise e - end + begin + el ||= find(selector, locator, **options.merge(visible: :all)) + el.session.find(:label, for: el, visible: true).click unless el.checked? == checked + rescue StandardError # swallow extra errors - raise original + raise e end end end diff --git a/lib/capybara/node/matchers.rb b/lib/capybara/node/matchers.rb index d85a15c0..d8af7d5c 100644 --- a/lib/capybara/node/matchers.rb +++ b/lib/capybara/node/matchers.rb @@ -201,12 +201,10 @@ module Capybara selector = extract_selector(args) synchronize(wait) do res = args.map do |locator| - begin - assert_selector(selector, locator, options, &optional_filter_block) - break nil - rescue Capybara::ExpectationNotMet => e - e.message - end + assert_selector(selector, locator, options, &optional_filter_block) + break nil + rescue Capybara::ExpectationNotMet => e + e.message end raise Capybara::ExpectationNotMet, res.join(' or ') if res diff --git a/lib/capybara/queries/style_query.rb b/lib/capybara/queries/style_query.rb index f45af212..fc00cfc3 100644 --- a/lib/capybara/queries/style_query.rb +++ b/lib/capybara/queries/style_query.rb @@ -34,7 +34,7 @@ module Capybara private def stringify_keys(hsh) - hsh.each_with_object({}) { |(k, v), str_keys| str_keys[k.to_s] = v } + hsh.transform_keys(&:to_s) end def valid_keys diff --git a/lib/capybara/selector/definition.rb b/lib/capybara/selector/definition.rb index acbefa5e..ac544291 100644 --- a/lib/capybara/selector/definition.rb +++ b/lib/capybara/selector/definition.rb @@ -189,7 +189,7 @@ module Capybara def describe_all_expression_filters(**opts) expression_filters.map do |ef_name, ef| if ef.matcher? - handled_custom_keys(ef, opts.keys).map { |key| " with #{ef_name}[#{key} => #{opts[key]}]" }.join + handled_custom_options(ef, opts).map { |option, value| " with #{ef_name}[#{option} => #{value}]" }.join elsif opts.key?(ef_name) " with #{ef_name} #{opts[ef_name]}" end @@ -251,9 +251,9 @@ module Capybara private - def handled_custom_keys(filter, keys) - keys.select do |key| - filter.handles_option?(key) && !::Capybara::Queries::SelectorQuery::VALID_KEYS.include?(key) + def handled_custom_options(filter, options) + options.select do |option, _| + filter.handles_option?(option) && !::Capybara::Queries::SelectorQuery::VALID_KEYS.include?(option) end end diff --git a/lib/capybara/selector/definition/table.rb b/lib/capybara/selector/definition/table.rb index 182b66d1..e7fc7ed2 100644 --- a/lib/capybara/selector/definition/table.rb +++ b/lib/capybara/selector/definition/table.rb @@ -43,7 +43,7 @@ Capybara.add_selector(:table, locator_type: [String, Symbol]) do end expression_filter(:cols, valid_values: [Array]) do |xpath, cols| - raise ArgumentError, ':cols must be an Array of Arrays' unless cols.all? { |col| col.is_a? Array } + raise ArgumentError, ':cols must be an Array of Arrays' unless cols.all?(Array) rows = cols.transpose col_conditions = rows.map { |row| match_row(row, match_size: true) }.reduce(:&) diff --git a/lib/capybara/selenium/driver_specializations/chrome_driver.rb b/lib/capybara/selenium/driver_specializations/chrome_driver.rb index 333ec71f..6bf7aa21 100644 --- a/lib/capybara/selenium/driver_specializations/chrome_driver.rb +++ b/lib/capybara/selenium/driver_specializations/chrome_driver.rb @@ -13,14 +13,12 @@ module Capybara::Selenium::Driver::ChromeDriver def fullscreen_window(handle) within_given_window(handle) do - begin - super - rescue NoMethodError => e - raise unless e.message.match?(/full_screen_window/) + super + rescue NoMethodError => e + raise unless e.message.match?(/full_screen_window/) - result = bridge.http.call(:post, "session/#{bridge.session_id}/window/fullscreen", {}) - result['value'] - end + result = bridge.http.call(:post, "session/#{bridge.session_id}/window/fullscreen", {}) + result['value'] end end @@ -65,7 +63,7 @@ private end def clear_all_storage? - storage_clears.none? { |s| s == false } + storage_clears.none? false end def uniform_storage_clear? diff --git a/lib/capybara/selenium/driver_specializations/edge_driver.rb b/lib/capybara/selenium/driver_specializations/edge_driver.rb index 8e7b597a..2ea36141 100644 --- a/lib/capybara/selenium/driver_specializations/edge_driver.rb +++ b/lib/capybara/selenium/driver_specializations/edge_driver.rb @@ -13,14 +13,12 @@ module Capybara::Selenium::Driver::EdgeDriver return super if edgedriver_version < 75 within_given_window(handle) do - begin - super - rescue NoMethodError => e - raise unless e.message.match?(/full_screen_window/) + super + rescue NoMethodError => e + raise unless e.message.match?(/full_screen_window/) - result = bridge.http.call(:post, "session/#{bridge.session_id}/window/fullscreen", {}) - result['value'] - end + result = bridge.http.call(:post, "session/#{bridge.session_id}/window/fullscreen", {}) + result['value'] end end @@ -74,7 +72,7 @@ private end def clear_all_storage? - storage_clears.none? { |s| s == false } + storage_clears.none? false end def uniform_storage_clear? diff --git a/lib/capybara/selenium/nodes/firefox_node.rb b/lib/capybara/selenium/nodes/firefox_node.rb index 5caa09dc..e1cd6bd1 100644 --- a/lib/capybara/selenium/nodes/firefox_node.rb +++ b/lib/capybara/selenium/nodes/firefox_node.rb @@ -42,7 +42,7 @@ class Capybara::Selenium::FirefoxNode < Capybara::Selenium::Node def send_keys(*args) # https://github.com/mozilla/geckodriver/issues/846 - return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none? { |arg| arg.is_a? Array } + return super(*args.map { |arg| arg == :space ? ' ' : arg }) if args.none?(Array) native.click _send_keys(args).perform diff --git a/lib/capybara/selenium/patches/logs.rb b/lib/capybara/selenium/patches/logs.rb index eba7dce5..24676844 100644 --- a/lib/capybara/selenium/patches/logs.rb +++ b/lib/capybara/selenium/patches/logs.rb @@ -33,11 +33,9 @@ module Capybara end Array(data).map do |l| - begin - ::Selenium::WebDriver::LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message') - rescue KeyError - next - end + ::Selenium::WebDriver::LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message') + rescue KeyError + next end rescue ::Selenium::WebDriver::Error::UnknownCommandError raise NotImplementedError, LOG_MSG diff --git a/lib/capybara/spec/test_app.rb b/lib/capybara/spec/test_app.rb index d5841e46..fae3836a 100644 --- a/lib/capybara/spec/test_app.rb +++ b/lib/capybara/spec/test_app.rb @@ -188,28 +188,24 @@ class TestApp < Sinatra::Base end post '/upload' do - begin - buffer = [] - buffer << "Content-type: #{params.dig(:form, :document, :type)}" - buffer << "File content: #{params.dig(:form, :document, :tempfile).read}" - buffer.join(' | ') - rescue StandardError - 'No file uploaded' - end + buffer = [] + buffer << "Content-type: #{params.dig(:form, :document, :type)}" + buffer << "File content: #{params.dig(:form, :document, :tempfile).read}" + buffer.join(' | ') + rescue StandardError + 'No file uploaded' end post '/upload_multiple' do - begin - docs = params.dig(:form, :multiple_documents) - buffer = [docs.size.to_s] - docs.each do |doc| - buffer << "Content-type: #{doc[:type]}" - buffer << "File content: #{doc[:tempfile].read}" - end - buffer.join(' | ') - rescue StandardError - 'No files uploaded' + docs = params.dig(:form, :multiple_documents) + buffer = [docs.size.to_s] + docs.each do |doc| + buffer << "Content-type: #{doc[:type]}" + buffer << "File content: #{doc[:tempfile].read}" end + buffer.join(' | ') + rescue StandardError + 'No files uploaded' end get '/apple-touch-icon-precomposed.png' do diff --git a/spec/server_spec.rb b/spec/server_spec.rb index b85503fc..c21979bc 100644 --- a/spec/server_spec.rb +++ b/spec/server_spec.rb @@ -75,25 +75,21 @@ RSpec.describe Capybara::Server do end it 'should handle that getting available ports fails randomly' do - begin - # Use a port to force a EADDRINUSE error to be generated - server = TCPServer.new('0.0.0.0', 0) - server_port = server.addr[1] - d_server = instance_double('TCPServer', addr: [nil, server_port, nil, nil], close: nil) - call_count = 0 - allow(TCPServer).to receive(:new).and_wrap_original do |m, *args| - begin - call_count.zero? ? d_server : m.call(*args) - ensure - call_count += 1 - end - end - - port = described_class.new(Object.new, host: '0.0.0.0').port - expect(port).not_to eq(server_port) + # Use a port to force a EADDRINUSE error to be generated + server = TCPServer.new('0.0.0.0', 0) + server_port = server.addr[1] + d_server = instance_double('TCPServer', addr: [nil, server_port, nil, nil], close: nil) + call_count = 0 + allow(TCPServer).to receive(:new).and_wrap_original do |m, *args| + call_count.zero? ? d_server : m.call(*args) ensure - server&.close + call_count += 1 end + + port = described_class.new(Object.new, host: '0.0.0.0').port + expect(port).not_to eq(server_port) + ensure + server&.close end it 'should return its #base_url' do @@ -104,29 +100,27 @@ RSpec.describe Capybara::Server do end it 'should support SSL' do - begin - key = File.join(Dir.pwd, 'spec', 'fixtures', 'key.pem') - cert = File.join(Dir.pwd, 'spec', 'fixtures', 'certificate.pem') - Capybara.server = :puma, { Host: "ssl://#{Capybara.server_host}?key=#{key}&cert=#{cert}" } - app = proc { |_env| [200, {}, ['Hello SSL Server!']] } - server = described_class.new(app).boot + key = File.join(Dir.pwd, 'spec', 'fixtures', 'key.pem') + cert = File.join(Dir.pwd, 'spec', 'fixtures', 'certificate.pem') + Capybara.server = :puma, { Host: "ssl://#{Capybara.server_host}?key=#{key}&cert=#{cert}" } + app = proc { |_env| [200, {}, ['Hello SSL Server!']] } + server = described_class.new(app).boot - expect do - Net::HTTP.start(server.host, server.port, max_retries: 0) { |http| http.get('/__identify__') } - end.to(raise_error do |e| - expect(e.is_a?(EOFError) || e.is_a?(Net::ReadTimeout)).to be true - end) + expect do + Net::HTTP.start(server.host, server.port, max_retries: 0) { |http| http.get('/__identify__') } + end.to(raise_error do |e| + expect(e.is_a?(EOFError) || e.is_a?(Net::ReadTimeout)).to be true + end) - res = Net::HTTP.start(server.host, server.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https| - https.get('/') - end - - expect(res.body).to include('Hello SSL Server!') - uri = ::Addressable::URI.parse(server.base_url) - expect(uri.to_hash).to include(scheme: 'https', host: server.host, port: server.port) - ensure - Capybara.server = :default + res = Net::HTTP.start(server.host, server.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https| + https.get('/') end + + expect(res.body).to include('Hello SSL Server!') + uri = ::Addressable::URI.parse(server.base_url) + expect(uri.to_hash).to include(scheme: 'https', host: server.host, port: server.port) + ensure + Capybara.server = :default end context 'When Capybara.reuse_server is true' do @@ -224,19 +218,17 @@ RSpec.describe Capybara::Server do end it 'should raise server errors when the server errors before the timeout' do - begin - Capybara.register_server :kaboom do - sleep 0.1 - raise 'kaboom' - end - Capybara.server = :kaboom - - expect do - described_class.new(proc { |e| }).boot - end.to raise_error(RuntimeError, 'kaboom') - ensure - Capybara.server = :default + Capybara.register_server :kaboom do + sleep 0.1 + raise 'kaboom' end + Capybara.server = :kaboom + + expect do + described_class.new(proc { |e| }).boot + end.to raise_error(RuntimeError, 'kaboom') + ensure + Capybara.server = :default end it 'should raise an error when there are pending requests' do