diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..7de53eb --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,102 @@ +AllCops: + DisabledByDefault: false + TargetRubyVersion: 2.3.0 + +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyleAlignWith, AutoCorrect, Severity. +# SupportedStylesAlignWith: keyword, variable, start_of_line +Layout/EndAlignment: + EnforcedStyleAlignWith: variable + +# Offense count: 2 +Lint/HandleExceptions: + Exclude: + - 'lib/capybara/poltergeist/client.rb' + - 'lib/capybara/poltergeist/driver.rb' + +# Offense count: 8 +Metrics/AbcSize: + Max: 36 + +# Configuration parameters: CountComments, ExcludedMethods. +Metrics/BlockLength: + Max: 1217 + +# Configuration parameters: CountComments. +Metrics/ClassLength: + Max: 383 + +Metrics/CyclomaticComplexity: + Max: 12 + +# Configuration parameters: CountComments. +Metrics/MethodLength: + Max: 28 + +# Configuration parameters: CountComments. +Metrics/ModuleLength: + Max: 1219 + +Metrics/PerceivedComplexity: + Max: 12 + +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. +# URISchemes: http, https +Metrics/LineLength: + Max: 172 + +Naming/AccessorMethodName: + Exclude: + - 'lib/capybara/poltergeist/browser.rb' + - 'spec/**/*' + +Naming/MemoizedInstanceVariableName: + Exclude: + - 'lib/capybara/poltergeist/inspector.rb' + +Naming/UncommunicativeMethodParamName: + AllowedNames: io, id, to, by, on, in, at, x, y, ip + +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: prefer_alias, prefer_alias_method +Style/Alias: + Exclude: + - 'lib/capybara/poltergeist/driver.rb' + - 'lib/capybara/poltergeist/node.rb' + +# Cop supports --auto-correct. +# Configuration parameters: AutoCorrect, EnforcedStyle. +# SupportedStyles: nested, compact +Style/ClassAndModuleChildren: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/DoubleNegation: + Exclude: + - 'lib/capybara/poltergeist/browser.rb' + - 'lib/capybara/poltergeist/node.rb' + +# Cop supports --auto-correct. +# Configuration parameters: Strict. +Style/NumericLiterals: + MinDigits: 6 + +# Cop supports --auto-correct. +Style/RescueModifier: + Exclude: + - 'lib/capybara/poltergeist/driver.rb' + - 'spec/**/*' + +# Cop supports --auto-correct. +# Configuration parameters: AllowAsExpressionSeparator. +Style/Semicolon: + AllowAsExpressionSeparator: true + +# Cop supports --auto-correct. +# Configuration parameters: . +# SupportedStyles: use_perl_names, use_english_names +Style/SpecialGlobalVars: + Enabled: false diff --git a/Gemfile b/Gemfile index d53dec2..682fca5 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + source 'https://rubygems.org' gemspec @@ -5,7 +7,7 @@ gemspec gem 'puma' platforms :rbx do - gem 'rubysl' - gem 'racc' gem 'json' + gem 'racc' + gem 'rubysl' end diff --git a/Guardfile b/Guardfile index 8754c7a..1889096 100644 --- a/Guardfile +++ b/Guardfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + guard 'coffeescript', input: 'lib/capybara/poltergeist/client', output: 'lib/capybara/poltergeist/client/compiled', bare: true diff --git a/Rakefile b/Rakefile index e630a4e..0c9c956 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'bundler/setup' require 'rspec/core/rake_task' @@ -5,7 +7,7 @@ require 'capybara/poltergeist/version' require 'coffee-script' RSpec::Core::RakeTask.new('test') -task default: [:compile, :test] +task default: %i[compile test] task(:autocompile) { system 'guard' } diff --git a/config.ru b/config.ru index 51f963b..3b9a1f2 100644 --- a/config.ru +++ b/config.ru @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'bundler/setup' require File.expand_path('spec/support/test_app') run TestApp diff --git a/lib/capybara/poltergeist.rb b/lib/capybara/poltergeist.rb index f4eb70b..723ff1f 100644 --- a/lib/capybara/poltergeist.rb +++ b/lib/capybara/poltergeist.rb @@ -1,10 +1,5 @@ # frozen_string_literal: true -if RUBY_VERSION < "1.9.2" - raise "This version of Capybara/Poltergeist does not support Ruby versions " \ - "less than 1.9.2." -end - require 'capybara' module Capybara diff --git a/lib/capybara/poltergeist/browser.rb b/lib/capybara/poltergeist/browser.rb index 203b29c..30f40a0 100644 --- a/lib/capybara/poltergeist/browser.rb +++ b/lib/capybara/poltergeist/browser.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require "capybara/poltergeist/errors" -require "capybara/poltergeist/command" +require 'capybara/poltergeist/errors' +require 'capybara/poltergeist/command' require 'json' require 'time' @@ -15,8 +15,8 @@ module Capybara::Poltergeist 'Poltergeist.NoSuchWindowError' => NoSuchWindowError, 'Poltergeist.ScriptTimeoutError' => ScriptTimeoutError, 'Poltergeist.UnsupportedFeature' => UnsupportedFeature, - 'Poltergeist.KeyError' => KeyError, - } + 'Poltergeist.KeyError' => KeyError + }.freeze attr_reader :server, :client, :logger @@ -144,7 +144,7 @@ module Capybara::Poltergeist command 'execute', script, *args end - def within_frame(handle, &block) + def within_frame(handle) if handle.is_a?(Capybara::Node::Base) command 'push_frame', [handle.native.page_id, handle.native.id] else @@ -192,10 +192,10 @@ module Capybara::Poltergeist handle = command 'window_handle', locator raise NoSuchWindowError unless handle - return handle + handle end - def within_window(locator, &block) + def within_window(locator) original = window_handle handle = find_window_handle(locator) switch_to_window(handle) @@ -204,15 +204,15 @@ module Capybara::Poltergeist switch_to_window(original) end - def click(page_id, id, keys=[], offset={}) + def click(page_id, id, keys = [], offset = {}) command 'click', page_id, id, keys, offset end - def right_click(page_id, id, keys=[], offset={}) + def right_click(page_id, id, keys = [], offset = {}) command 'right_click', page_id, id, keys, offset end - def double_click(page_id, id, keys=[], offset={}) + def double_click(page_id, id, keys = [], offset = {}) command 'double_click', page_id, id, keys, offset end @@ -313,7 +313,7 @@ module Capybara::Poltergeist command 'add_headers', headers end - def add_header(header, options={}) + def add_header(header, options = {}) command 'add_header', header, options end @@ -326,10 +326,7 @@ module Capybara::Poltergeist end def set_cookie(cookie) - if cookie[:expires] - cookie[:expires] = cookie[:expires].to_i * 1000 - end - + cookie[:expires] = cookie[:expires].to_i * 1000 if cookie[:expires] command 'set_cookie', cookie end @@ -389,11 +386,11 @@ module Capybara::Poltergeist response = server.send(cmd) log response - json = JSON.load(response) + json = JSON.parse(response) if json['error'] klass = ERROR_MAPPINGS[json['error']['name']] || BrowserError - raise klass.new(json['error']) + raise klass, json['error'] else json['response'] end @@ -443,14 +440,13 @@ module Capybara::Poltergeist private def log(message) - logger.puts message if logger + logger&.puts message end def check_render_options!(options) - if !!options[:full] && options.has_key?(:selector) - warn "Ignoring :selector in #render since :full => true was given at #{caller.first}" - options.delete(:selector) - end + return unless options[:full] && options.key?(:selector) + warn "Ignoring :selector in #render since :full => true was given at #{caller(1..1).first}" + options.delete(:selector) end KEY_ALIASES = { @@ -463,7 +459,7 @@ module Capybara::Poltergeist divide: 'numpad/', subtract: 'numpad-', decimal: 'numpad.' - } + }.freeze def normalize_keys(keys) keys.map do |key_desc| @@ -474,9 +470,9 @@ module Capybara::Poltergeist # [:Ctrl, :Left] => { modifier: "ctrl", key: 'Left' } # [:Ctrl, :Shift, :Left] => { modifier: "ctrl,shift", key: 'Left' } # [:Ctrl, :Left, :Left] => { modifier: "ctrl", key: [:Left, :Left] } - _keys = key_desc.chunk {|k| k.is_a?(Symbol) && %w(shift ctrl control alt meta command).include?(k.to_s.downcase) } - modifiers = if _keys.peek[0] - _keys.next[1].map do |k| + chunked_keys = key_desc.chunk { |k| k.is_a?(Symbol) && %w[shift ctrl control alt meta command].include?(k.to_s.downcase) } + modifiers = if chunked_keys.peek[0] + chunked_keys.next[1].map do |k| k = k.to_s.downcase k = 'ctrl' if k == 'control' k = 'meta' if k == 'command' @@ -485,15 +481,15 @@ module Capybara::Poltergeist else '' end - letters = normalize_keys(_keys.next[1].map {|k| k.is_a?(String) ? k.upcase : k }) + letters = normalize_keys(chunked_keys.next[1].map { |k| k.is_a?(String) ? k.upcase : k }) { modifier: modifiers, keys: letters } when Symbol # Return a known sequence for PhantomJS key = KEY_ALIASES.fetch(key_desc, key_desc) - if match = key.to_s.match(/numpad(.)/) + if (match = key.to_s.match(/numpad(.)/)) res = { keys: match[1], modifier: 'keypad' } elsif key !~ /^[A-Z]/ - key = key.to_s.split('_').map{ |e| e.capitalize }.join + key = key.to_s.split('_').map(&:capitalize).join end res || { key: key } when String diff --git a/lib/capybara/poltergeist/client.rb b/lib/capybara/poltergeist/client.rb index c23d55e..e3b749a 100644 --- a/lib/capybara/poltergeist/client.rb +++ b/lib/capybara/poltergeist/client.rb @@ -1,13 +1,12 @@ # frozen_string_literal: true -require "timeout" -require "capybara/poltergeist/utility" +require 'capybara/poltergeist/utility' require 'cliver' module Capybara::Poltergeist class Client - PHANTOMJS_SCRIPT = File.expand_path('../client/compiled/main.js', __FILE__) - PHANTOMJS_VERSION = ['>= 1.8.1', '< 3.0'] + PHANTOMJS_SCRIPT = File.expand_path('client/compiled/main.js', __dir__) + PHANTOMJS_VERSION = ['>= 1.8.1', '< 3.0'].freeze PHANTOMJS_NAME = 'phantomjs' KILL_TIMEOUT = 2 # seconds @@ -32,11 +31,10 @@ module Capybara::Poltergeist start = Time.now while Process.wait(pid, Process::WNOHANG).nil? sleep 0.05 - if (Time.now - start) > KILL_TIMEOUT - Process.kill('KILL', pid) - Process.wait(pid) - break - end + next unless (Time.now - start) > KILL_TIMEOUT + Process.kill('KILL', pid) + Process.wait(pid) + break end end rescue Errno::ESRCH, Errno::ECHILD @@ -49,8 +47,8 @@ module Capybara::Poltergeist def initialize(server, options = {}) @server = server - @path = Cliver::detect((options[:path] || PHANTOMJS_NAME), *['>=2.1.0', '< 3.0']) - @path ||= Cliver::detect!((options[:path] || PHANTOMJS_NAME), *PHANTOMJS_VERSION).tap do + @path = Cliver.detect((options[:path] || PHANTOMJS_NAME), '>=2.1.0', '< 3.0') + @path ||= Cliver.detect!((options[:path] || PHANTOMJS_NAME), *PHANTOMJS_VERSION).tap do warn "You're running an old version of PhantomJS, update to >= 2.1.1 for a better experience." end @@ -61,13 +59,13 @@ module Capybara::Poltergeist def start @read_io, @write_io = IO.pipe - @out_thread = Thread.new { - while !@read_io.eof? && data = @read_io.readpartial(1024) + @out_thread = Thread.new do + while !@read_io.eof? && (data = @read_io.readpartial(1024)) @phantomjs_logger.write(data) end - } + end - process_options = {in: File::NULL} + process_options = { in: File::NULL } process_options[:pgroup] = true unless Capybara::Poltergeist.windows? process_options[:out] = @write_io if Capybara::Poltergeist.mri? @@ -78,12 +76,11 @@ module Capybara::Poltergeist end def stop - if pid - kill_phantomjs - @out_thread.kill - close_io - ObjectSpace.undefine_finalizer(self) - end + return unless pid + kill_phantomjs + @out_thread.kill + close_io + ObjectSpace.undefine_finalizer(self) end def restart diff --git a/lib/capybara/poltergeist/command.rb b/lib/capybara/poltergeist/command.rb index 35a3ffd..ab46f2b 100644 --- a/lib/capybara/poltergeist/command.rb +++ b/lib/capybara/poltergeist/command.rb @@ -15,7 +15,7 @@ module Capybara::Poltergeist end def message - JSON.dump({ 'id' => @id, 'name' => @name, 'args' => @args }) + JSON.dump('id' => @id, 'name' => @name, 'args' => @args) end end end diff --git a/lib/capybara/poltergeist/driver.rb b/lib/capybara/poltergeist/driver.rb index c1a1775..c9bd412 100644 --- a/lib/capybara/poltergeist/driver.rb +++ b/lib/capybara/poltergeist/driver.rb @@ -45,11 +45,10 @@ module Capybara::Poltergeist def client @client ||= Client.start(server, - :path => options[:phantomjs], - :window_size => options[:window_size], - :phantomjs_options => phantomjs_options, - :phantomjs_logger => phantomjs_logger - ) + path: options[:phantomjs], + window_size: options[:window_size], + phantomjs_options: phantomjs_options, + phantomjs_logger: phantomjs_logger) end def phantomjs_options @@ -58,9 +57,9 @@ module Capybara::Poltergeist # PhantomJS defaults to only using SSLv3, which since POODLE (Oct 2014) # many sites have dropped from their supported protocols (eg PayPal, # Braintree). - list += ["--ignore-ssl-errors=yes"] unless list.grep(/ignore-ssl-errors/).any? - list += ["--ssl-protocol=TLSv1"] unless list.grep(/ssl-protocol/).any? - list += ["--remote-debugger-port=#{inspector.port}", "--remote-debugger-autorun=yes"] if inspector + list += ['--ignore-ssl-errors=yes'] unless list.grep(/ignore-ssl-errors/).any? + list += ['--ssl-protocol=TLSv1'] unless list.grep(/ssl-protocol/).any? + list += ["--remote-debugger-port=#{inspector.port}", '--remote-debugger-autorun=yes'] if inspector list end @@ -154,17 +153,17 @@ module Capybara::Poltergeist end def evaluate_script(script, *args) - result = browser.evaluate(script, *args.map { |arg| arg.is_a?(Capybara::Poltergeist::Node) ? arg.native : arg}) + result = browser.evaluate(script, *native_args(args)) unwrap_script_result(result) end def evaluate_async_script(script, *args) - result = browser.evaluate_async(script, session_wait_time, *args.map { |arg| arg.is_a?(Capybara::Poltergeist::Node) ? arg.native : arg}) + result = browser.evaluate_async(script, session_wait_time, *native_args(args)) unwrap_script_result(result) end def execute_script(script, *args) - browser.execute(script, *args.map { |arg| arg.is_a?(Capybara::Poltergeist::Node) ? arg.native : arg}) + browser.execute(script, *native_args(args)) nil end @@ -261,7 +260,7 @@ module Capybara::Poltergeist browser.clear_network_traffic end - def set_proxy(ip, port, type = "http", user = nil, password = nil) + def set_proxy(ip, port, type = 'http', user = nil, password = nil) browser.set_proxy(ip, port, type, user, password) end @@ -296,7 +295,7 @@ module Capybara::Poltergeist if @started URI.parse(browser.current_url).host else - URI.parse(default_cookie_host).host || "127.0.0.1" + URI.parse(default_cookie_host).host || '127.0.0.1' end end @@ -338,8 +337,8 @@ module Capybara::Poltergeist inspector.open(scheme) pause else - raise Error, "To use the remote debugging, you have to launch the driver " \ - "with `:inspector => true` configuration option" + raise Error, 'To use the remote debugging, you have to launch the driver ' \ + 'with `:inspector => true` configuration option' end end @@ -358,12 +357,13 @@ module Capybara::Poltergeist old_trap = trap('SIGCONT') { signal = true; STDERR.puts "\nSignal SIGCONT received" } keyboard = IO.select([read], nil, nil, 1) until keyboard || signal # wait for data on STDIN or signal SIGCONT received - begin - input = read.read_nonblock(80) # clear out the read buffer - puts unless input && input =~ /\n\z/ - rescue EOFError, IO::WaitReadable # Ignore problems reading from STDIN. - end unless signal - + unless signal + begin + input = read.read_nonblock(80) # clear out the read buffer + puts unless input&.end_with?("\n") + rescue EOFError, IO::WaitReadable # Ignore problems reading from STDIN. + end + end ensure trap('SIGCONT', old_trap) # Restore the previous signal handler, if there was one. STDERR.puts 'Continuing' @@ -416,8 +416,12 @@ module Capybara::Poltergeist private + def native_args(args) + args.map { |arg| arg.is_a?(Capybara::Poltergeist::Node) ? arg.native : arg } + end + def screen_size - options[:screen_size] || [1366,768] + options[:screen_size] || [1366, 768] end def find_modal(options) diff --git a/lib/capybara/poltergeist/errors.rb b/lib/capybara/poltergeist/errors.rb index 4dda584..bb4f73b 100644 --- a/lib/capybara/poltergeist/errors.rb +++ b/lib/capybara/poltergeist/errors.rb @@ -36,9 +36,9 @@ module Capybara end def message - "There was an error inside the PhantomJS portion of Poltergeist. " \ - "If this is the error returned, and not the cause of a more detailed error response, " \ - "this is probably a bug, so please report it. " \ + 'There was an error inside the PhantomJS portion of Poltergeist. ' \ + 'If this is the error returned, and not the cause of a more detailed error response, ' \ + 'this is probably a bug, so please report it. ' \ "\n\n#{name}: #{error_parameters}" end end @@ -49,10 +49,10 @@ module Capybara end def message - "One or more errors were raised in the Javascript code on the page. " \ + 'One or more errors were raised in the Javascript code on the page. ' \ "If you don't care about these errors, you can ignore them by " \ - "setting js_errors: false in your Poltergeist configuration (see " \ - "documentation for details)." \ + 'setting js_errors: false in your Poltergeist configuration (see ' \ + 'documentation for details).' \ "\n\n#{javascript_errors.map(&:to_s).join("\n")}" end end @@ -93,7 +93,7 @@ module Capybara end def message - "The browser raised a syntax error while trying to evaluate " \ + 'The browser raised a syntax error while trying to evaluate ' \ "#{method} selector #{selector.inspect}" end end @@ -109,11 +109,11 @@ module Capybara class ObsoleteNode < NodeError def message - "The element you are trying to interact with is either not part of the DOM, or is " \ - "not currently visible on the page (perhaps display: none is set). " \ + 'The element you are trying to interact with is either not part of the DOM, or is ' \ + 'not currently visible on the page (perhaps display: none is set). ' \ "It's possible the element has been replaced by another element and you meant to interact with " \ "the new element. If so you need to do a new 'find' in order to get a reference to the " \ - "new element." + 'new element.' end end @@ -127,7 +127,7 @@ module Capybara end def version - response['args'][1].values_at(*%w(major minor patch)).join '.' + response['args'][1].values_at('major', 'minor', 'patch').join '.' end def message @@ -151,14 +151,14 @@ module Capybara def message "Firing a #{name} at co-ordinates [#{position.join(', ')}] failed. Poltergeist detected " \ "another element with CSS selector '#{selector}' at this position. " \ - "It may be overlapping the element you are trying to interact with. " \ + 'It may be overlapping the element you are trying to interact with. ' \ "If you don't care about overlapping elements, try using node.trigger('#{name}')." end end class KeyError < ::ArgumentError def initialize(response) - super(response["args"].first) + super(response['args'].first) end end @@ -169,20 +169,19 @@ module Capybara def message "Timed out waiting for response to #{@message}. It's possible that this happened " \ - "because something took a very long time (for example a page load was slow). " \ - "If so, setting the Poltergeist :timeout option to a higher value will help " \ - "(see the docs for details). If increasing the timeout does not help, this is " \ - "probably a bug in Poltergeist - please report it to the issue tracker." + 'because something took a very long time (for example a page load was slow). ' \ + 'If so, setting the Poltergeist :timeout option to a higher value will help ' \ + '(see the docs for details). If increasing the timeout does not help, this is ' \ + 'probably a bug in Poltergeist - please report it to the issue tracker.' end end class ScriptTimeoutError < Error def message - "Timed out waiting for evaluated script to resturn a value" + 'Timed out waiting for evaluated script to resturn a value' end end - class DeadClient < Error def initialize(message) @message = message @@ -195,10 +194,10 @@ module Capybara class PhantomJSTooOld < Error def self.===(other) - if Cliver::Dependency::VersionMismatch === other - warn "#{name} exception has been deprecated in favor of using the " + - "cliver gem for command-line dependency detection. Please " + - "handle Cliver::Dependency::VersionMismatch instead." + if other.is_a? Cliver::Dependency::VersionMismatch + warn "#{name} exception has been deprecated in favor of using the " \ + 'cliver gem for command-line dependency detection. Please ' \ + 'handle Cliver::Dependency::VersionMismatch instead.' true else super @@ -208,10 +207,10 @@ module Capybara class PhantomJSFailed < Error def self.===(other) - if Cliver::Dependency::NotMet === other - warn "#{name} exception has been deprecated in favor of using the " + - "cliver gem for command-line dependency detection. Please " + - "handle Cliver::Dependency::NotMet instead." + if other.is_a? Cliver::Dependency::NotMet + warn "#{name} exception has been deprecated in favor of using the " \ + 'cliver gem for command-line dependency detection. Please ' \ + 'handle Cliver::Dependency::NotMet instead.' true else super diff --git a/lib/capybara/poltergeist/inspector.rb b/lib/capybara/poltergeist/inspector.rb index 7896f11..5e15034 100644 --- a/lib/capybara/poltergeist/inspector.rb +++ b/lib/capybara/poltergeist/inspector.rb @@ -2,7 +2,7 @@ module Capybara::Poltergeist class Inspector - BROWSERS = %w(chromium chromium-browser google-chrome open) + BROWSERS = %w[chromium chromium-browser google-chrome open].freeze DEFAULT_PORT = 9664 def self.detect_browser @@ -30,19 +30,19 @@ module Capybara::Poltergeist else raise Error, "Could not find a browser executable to open #{url(scheme)}. " \ "You can specify one manually using e.g. `:inspector => 'chromium'` " \ - "as a configuration option for Poltergeist." + 'as a configuration option for Poltergeist.' end end def self.browser_binary_exists?(browser) exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| - exts.each { |ext| + exts.each do |ext| exe = "#{path}#{File::SEPARATOR}#{browser}#{ext}" return exe if File.executable? exe - } + end end - return nil + nil end end end diff --git a/lib/capybara/poltergeist/network_traffic/response.rb b/lib/capybara/poltergeist/network_traffic/response.rb index 33b8c04..875fa61 100644 --- a/lib/capybara/poltergeist/network_traffic/response.rb +++ b/lib/capybara/poltergeist/network_traffic/response.rb @@ -39,4 +39,3 @@ module Capybara::Poltergeist::NetworkTraffic end end end - diff --git a/lib/capybara/poltergeist/node.rb b/lib/capybara/poltergeist/node.rb index eb9405b..b1c2381 100644 --- a/lib/capybara/poltergeist/node.rb +++ b/lib/capybara/poltergeist/node.rb @@ -53,8 +53,8 @@ module Capybara::Poltergeist filter_text command(:visible_text) else command(:visible_text).to_s - .gsub(/\A[[:space:]&&[^\u00a0]]+/, "") - .gsub(/[[:space:]&&[^\u00a0]]+\z/, "") + .gsub(/\A[[:space:]&&[^\u00a0]]+/, '') + .gsub(/[[:space:]&&[^\u00a0]]+\z/, '') .gsub(/\n+/, "\n") .tr("\u00a0", ' ') end @@ -67,10 +67,9 @@ module Capybara::Poltergeist def [](name) # Although the attribute matters, the property is consistent. Return that in # preference to the attribute for links and images. - if (tag_name == 'img' and name == 'src') or (tag_name == 'a' and name == 'href' ) - #if attribute exists get the property - value = command(:attribute, name) && command(:property, name) - return value + if ((tag_name == 'img') && (name == 'src')) || ((tag_name == 'a') && (name == 'href')) + # if attribute exists get the property + return command(:attribute, name) && command(:property, name) end value = property(name) @@ -115,8 +114,8 @@ module Capybara::Poltergeist end def unselect_option - command(:select, false) or - raise(Capybara::UnselectNotAllowed, "Cannot unselect option from single select box.") + command(:select, false) || + raise(Capybara::UnselectNotAllowed, 'Cannot unselect option from single select box.') end def tag_name @@ -139,15 +138,15 @@ module Capybara::Poltergeist command :disabled? end - def click(keys=[], offset={}) + def click(keys = [], offset = {}) command :click, keys, offset end - def right_click(keys=[], offset={}) + def right_click(keys = [], offset = {}) command :right_click, keys, offset end - def double_click(keys=[], offset={}) + def double_click(keys = [], offset = {}) command :double_click, keys, offset end @@ -187,19 +186,19 @@ module Capybara::Poltergeist # @api private def as_json(*) - { ELEMENT: {page_id: @page_id, id: @id} } + { ELEMENT: { page_id: @page_id, id: @id } } end private - def filter_text(text, visible = true) + def filter_text(text) if Capybara::VERSION.to_f < 3 Capybara::Helpers.normalize_whitespace(text.to_s) else text.gsub(/[\u200b\u200e\u200f]/, '') .gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ') - .gsub(/\A[[:space:]&&[^\u00a0]]+/, "") - .gsub(/[[:space:]&&[^\u00a0]]+\z/, "") + .gsub(/\A[[:space:]&&[^\u00a0]]+/, '') + .gsub(/[[:space:]&&[^\u00a0]]+\z/, '') .tr("\u00a0", ' ') end end diff --git a/lib/capybara/poltergeist/server.rb b/lib/capybara/poltergeist/server.rb index a60fa57..9cc021d 100644 --- a/lib/capybara/poltergeist/server.rb +++ b/lib/capybara/poltergeist/server.rb @@ -42,7 +42,7 @@ module Capybara::Poltergeist command.args.push(timeout) # set the client set visit timeout parameter receive_timeout = timeout + 5 # Add a couple of seconds to let the client timeout first end - @socket.send(command.id, command.message, receive_timeout) or raise DeadClient.new(command.message) + @socket.send(command.id, command.message, receive_timeout) || raise(DeadClient, command.message) end end end diff --git a/lib/capybara/poltergeist/utility.rb b/lib/capybara/poltergeist/utility.rb index 02f5ef1..3885f21 100644 --- a/lib/capybara/poltergeist/utility.rb +++ b/lib/capybara/poltergeist/utility.rb @@ -4,11 +4,11 @@ module Capybara module Poltergeist class << self def windows? - RbConfig::CONFIG["host_os"] =~ /mingw|mswin|cygwin/ + RbConfig::CONFIG['host_os'] =~ /mingw|mswin|cygwin/ end def mri? - defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" + defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' end end end diff --git a/lib/capybara/poltergeist/version.rb b/lib/capybara/poltergeist/version.rb index c57dc1c..1de6f38 100644 --- a/lib/capybara/poltergeist/version.rb +++ b/lib/capybara/poltergeist/version.rb @@ -2,6 +2,6 @@ module Capybara module Poltergeist - VERSION = "1.18.1" + VERSION = '1.18.1' end end diff --git a/lib/capybara/poltergeist/web_socket_server.rb b/lib/capybara/poltergeist/web_socket_server.rb index ff107e2..c862253 100644 --- a/lib/capybara/poltergeist/web_socket_server.rb +++ b/lib/capybara/poltergeist/web_socket_server.rb @@ -38,12 +38,9 @@ module Capybara::Poltergeist @host = server.addr[2] end rescue Errno::EADDRINUSE - if (Time.now - time) < BIND_TIMEOUT - sleep(0.01) - retry - else - raise - end + raise if (Time.now - time) >= BIND_TIMEOUT + sleep(0.01) + retry end end @@ -58,9 +55,9 @@ module Capybara::Poltergeist @messages = {} @driver = ::WebSocket::Driver.server(self) - @driver.on(:connect) { |event| @driver.start } + @driver.on(:connect) { |_event| @driver.start } @driver.on(:message) do |event| - command_id = JSON.load(event.data)['command_id'] + command_id = JSON.parse(event.data)['command_id'] @messages[command_id] = event.data end end @@ -71,15 +68,15 @@ module Capybara::Poltergeist # Block until the next message is available from the Web Socket. # Raises Errno::EWOULDBLOCK if timeout is reached. - def receive(cmd_id, receive_timeout=nil) + def receive(cmd_id, receive_timeout = nil) receive_timeout ||= timeout start = Time.now - until @messages.has_key?(cmd_id) + until @messages.key?(cmd_id) raise Errno::EWOULDBLOCK if (Time.now - start) >= receive_timeout if @receive_mutex.try_lock begin - IO.select([socket], [], [], receive_timeout) or raise Errno::EWOULDBLOCK + IO.select([socket], [], [], receive_timeout) || raise(Errno::EWOULDBLOCK) data = socket.recv(RECV_SIZE) break if data.empty? driver.parse(data) @@ -94,12 +91,12 @@ module Capybara::Poltergeist end # Send a message and block until there is a response - def send(cmd_id, message, accept_timeout=nil) + def send(cmd_id, message, accept_timeout = nil) accept unless connected? driver.text(message) receive(cmd_id, accept_timeout) rescue Errno::EWOULDBLOCK - raise TimeoutError.new(message) + raise TimeoutError, message end # Closing sockets separately as `close_read`, `close_write` diff --git a/poltergeist.gemspec b/poltergeist.gemspec index 78f5342..cc33684 100644 --- a/poltergeist.gemspec +++ b/poltergeist.gemspec @@ -1,4 +1,6 @@ -lib = File.expand_path('../lib/', __FILE__) +# frozen_string_literal: true + +lib = File.expand_path('lib', __dir__) $:.unshift lib unless $:.include?(lib) require 'capybara/poltergeist/version' @@ -16,23 +18,23 @@ Gem::Specification.new do |s| 'PhantomJS.' s.license = 'MIT' s.require_paths = ['lib'] - s.files = Dir.glob('{lib}/**/*') + %w(LICENSE README.md) + s.files = Dir.glob('{lib}/**/*') + %w[LICENSE README.md] s.required_ruby_version = '>= 2.3.0' s.add_runtime_dependency 'capybara', '>= 2.1', '< 4' - s.add_runtime_dependency 'websocket-driver', '>= 0.2.0' s.add_runtime_dependency 'cliver', '~> 0.3.1' + s.add_runtime_dependency 'websocket-driver', '>= 0.2.0' + s.add_development_dependency 'coffee-script', '~> 2.2' + s.add_development_dependency 'coffee-script-source', '~>1.12.2' + s.add_development_dependency 'erubi' # required by rbx + s.add_development_dependency 'guard-coffeescript', '~> 2.0.0' + s.add_development_dependency 'image_size', '~> 1.0' s.add_development_dependency 'launchy', '~> 2.0' + s.add_development_dependency 'listen', '~> 3.0.6' # listen is required by guard and listen 3.1.0 requires ruby 2.2+ + s.add_development_dependency 'pdf-reader', '< 3.0', '>= 1.3.3' + s.add_development_dependency 'rake' s.add_development_dependency 'rspec', '~> 3.7' s.add_development_dependency 'sinatra', '<= 3.0' - s.add_development_dependency 'rake' - s.add_development_dependency 'image_size', '~> 1.0' - s.add_development_dependency 'pdf-reader', '< 3.0', '>= 1.3.3' - s.add_development_dependency 'coffee-script', '~> 2.2' - s.add_development_dependency 'guard-coffeescript', '~> 2.0.0' - s.add_development_dependency 'coffee-script-source', '~>1.12.2' - s.add_development_dependency 'listen', '~> 3.0.6' # listen is required by guard and listen 3.1.0 requires ruby 2.2+ - s.add_development_dependency 'erubi' # required by rbx end diff --git a/spec/integration/driver_spec.rb b/spec/integration/driver_spec.rb index 75c89d2..c3340aa 100644 --- a/spec/integration/driver_spec.rb +++ b/spec/integration/driver_spec.rb @@ -39,7 +39,7 @@ module Capybara::Poltergeist expect(File.exist?(file)).to be true ensure - driver.quit if driver + driver&.quit end end @@ -63,20 +63,20 @@ module Capybara::Poltergeist end it 'is threadsafe in how it captures console.log' do - pending("JRuby and Rubinius do not support the :out parameter to Process.spawn, so there is no threadsafe way to redirect output") unless Capybara::Poltergeist.mri? + pending('JRuby and Rubinius do not support the :out parameter to Process.spawn, so there is no threadsafe way to redirect output') unless Capybara::Poltergeist.mri? # Write something to STDOUT right before Process.spawn is called - allow(Process).to receive(:spawn).and_wrap_original do |m,*args| - STDOUT.puts "1" - $stdout.puts "2" + allow(Process).to receive(:spawn).and_wrap_original do |m, *args| + STDOUT.puts '1' + $stdout.puts '2' m.call(*args) end - expect { + expect do session.visit('/poltergeist/console_log') - }.to output("1\n2\n").to_stdout_from_any_process + end.to output("1\n2\n").to_stdout_from_any_process - expect(logger.string).not_to match /\d/ + expect(logger.string).not_to match(/\d/) end end @@ -118,7 +118,7 @@ module Capybara::Poltergeist @session.visit('/') @session.current_window.maximize expect(@session.current_window.size).to eq([1600, 1200]) - ensure + ensure @driver.options.delete(:screen_size) end end @@ -142,12 +142,12 @@ module Capybara::Poltergeist ) end driver = Capybara::Session.new(:poltergeist_with_custom_window_size, TestApp).driver - driver.visit(session_url '/') + driver.visit(session_url('/')) expect( driver.evaluate_script('[window.innerWidth, window.innerHeight]') ).to eq([800, 600]) ensure - driver.quit if driver + driver&.quit end end @@ -187,13 +187,13 @@ module Capybara::Poltergeist create_screenshot file, selector: '#penultimate' File.open(file, 'rb') do |f| - size = @driver.evaluate_script <<-EOS + size = @driver.evaluate_script <<-JS function() { var ele = document.getElementById('penultimate'); var rect = ele.getBoundingClientRect(); return [rect.width, rect.height]; }(); - EOS + JS expect(ImageSize.new(f.read).size).to eq(size) end end @@ -214,7 +214,7 @@ module Capybara::Poltergeist it 'resets element positions after' do @session.visit('poltergeist/long_page') el = @session.find(:css, '#middleish') - #make the page scroll an element into view + # make the page scroll an element into view el.click position_script = 'document.querySelector("#middleish").getBoundingClientRect()' offset = @session.evaluate_script(position_script) @@ -251,7 +251,7 @@ module Capybara::Poltergeist it 'supports rendering the page to file without extension when format is specified' do begin - file = POLTERGEIST_ROOT + "/spec/tmp/screenshot" + file = POLTERGEIST_ROOT + '/spec/tmp/screenshot' FileUtils.rm_f file @session.visit('/') @@ -286,8 +286,8 @@ module Capybara::Poltergeist it 'changes image dimensions' do @session.visit('/poltergeist/zoom_test') - black_pixels_count = ->(file) { - File.read(file).to_s[/{.*}/m][1...-1].split(/\W/).map{|n| n.hex.to_s(2).count('1')}.reduce(:+) + black_pixels_count = lambda { |file| + File.read(file).to_s[/{.*}/m][1...-1].split(/\W/).map { |n| n.hex.to_s(2).count('1') }.reduce(:+) } @driver.save_screenshot(file) before = black_pixels_count[file] @@ -296,7 +296,7 @@ module Capybara::Poltergeist @driver.save_screenshot(file) after = black_pixels_count[file] - expect(after.to_f/before.to_f).to eq(zoom_factor**2) + expect(after.to_f / before.to_f).to eq(zoom_factor**2) end end @@ -408,8 +408,8 @@ module Capybara::Poltergeist it 'sets headers on the initial request' do @driver.headers = { 'PermanentA' => 'a' } @driver.add_headers('PermanentB' => 'b') - @driver.add_header('Referer', 'http://google.com', :permanent => false) - @driver.add_header('TempA', 'a', :permanent => false) + @driver.add_header('Referer', 'http://google.com', permanent: false) + @driver.add_header('TempA', 'a', permanent: false) @session.visit('/poltergeist/headers_with_ajax') initial_request = @session.find(:css, '#initial_request').text @@ -427,14 +427,14 @@ module Capybara::Poltergeist end it 'keeps added headers on redirects by default' do - @driver.add_header('X-Custom-Header', '1', :permanent => false) + @driver.add_header('X-Custom-Header', '1', permanent: false) @session.visit('/poltergeist/redirect_to_headers') expect(@driver.body).to include('X_CUSTOM_HEADER: 1') end it 'does not keep added headers on redirect when ' \ 'permanent is no_redirect' do - @driver.add_header('X-Custom-Header', '1', :permanent => :no_redirect) + @driver.add_header('X-Custom-Header', '1', permanent: :no_redirect) @session.visit('/poltergeist/redirect_to_headers') expect(@driver.body).not_to include('X_CUSTOM_HEADER: 1') @@ -476,7 +476,7 @@ module Capybara::Poltergeist it 'keeps temporary headers local to the current window' do @session.open_new_window - @driver.add_header('X-Custom-Header', '1', :permanent => false) + @driver.add_header('X-Custom-Header', '1', permanent: false) @session.switch_to_window @session.windows.last @session.visit('/poltergeist/headers') @@ -489,7 +489,7 @@ module Capybara::Poltergeist it 'does not mix temporary headers with permanent ones when propagating to other windows' do @session.open_new_window - @driver.add_header('X-Custom-Header', '1', :permanent => false) + @driver.add_header('X-Custom-Header', '1', permanent: false) @driver.add_header('Host', 'foo.com') @session.switch_to_window @session.windows.last @@ -505,7 +505,7 @@ module Capybara::Poltergeist it 'does not propagate temporary headers to new windows' do @session.visit '/' - @driver.add_header('X-Custom-Header', '1', :permanent => false) + @driver.add_header('X-Custom-Header', '1', permanent: false) @session.open_new_window @session.switch_to_window @session.windows.last @@ -562,8 +562,8 @@ module Capybara::Poltergeist @extended_driver = Capybara::Poltergeist::Driver.new( @session.app, logger: TestSessions.logger, - inspector: ENV['DEBUG'] != nil, - extensions: %W% #{File.expand_path '../../support/geolocation.js', __FILE__ } % + inspector: !ENV['DEBUG'].nil?, + extensions: %W[#{File.expand_path '../support/geolocation.js', __dir__}] ) end @@ -573,8 +573,9 @@ module Capybara::Poltergeist it 'supports extending the phantomjs world' do @extended_driver.visit session_url('/poltergeist/requiring_custom_extension') - expect(@extended_driver.body). - to include(%Q%Location: 1,-1%) + expect( + @extended_driver.body + ).to include(%(Location: 1,-1)) expect( @extended_driver.evaluate_script("document.getElementById('location').innerHTML") ).to eq('1,-1') @@ -588,8 +589,8 @@ module Capybara::Poltergeist @failing_driver = Capybara::Poltergeist::Driver.new( @session.app, logger: TestSessions.logger, - inspector: ENV['DEBUG'] != nil, - extensions: %W% #{File.expand_path '../../support/non_existent.js', __FILE__} % + inspector: !ENV['DEBUG'].nil?, + extensions: %W[#{File.expand_path '../support/non_existent.js', __dir__}] ) expect { @failing_driver.visit '/' }.to raise_error(Capybara::Poltergeist::BrowserError, /Unable to load extension: .*non_existent\.js/) ensure @@ -600,9 +601,9 @@ module Capybara::Poltergeist context 'javascript errors' do it 'propagates a Javascript error inside Poltergeist to a ruby exception' do - expect { + expect do @driver.browser.command 'browser_error' - }.to raise_error(BrowserError) { |e| + end.to raise_error(BrowserError) { |e| expect(e.message).to include('Error: zomg') # PhantomJS 2.1 refers to files as being in code subdirectory expect(e.message).to include('compiled/browser.js').or include('code/browser.js') @@ -610,25 +611,25 @@ module Capybara::Poltergeist end it 'propagates an asynchronous Javascript error on the page to a ruby exception' do - expect { + expect do @driver.execute_script 'setTimeout(function() { omg }, 0)' sleep 0.01 @driver.execute_script '' - }.to raise_error(JavascriptError, /ReferenceError.*omg/) + end.to raise_error(JavascriptError, /ReferenceError.*omg/) end it 'propagates a synchronous Javascript error on the page to a ruby exception' do - expect { + expect do @driver.execute_script 'omg' - }.to raise_error(JavascriptError, /ReferenceError.*omg/) + end.to raise_error(JavascriptError, /ReferenceError.*omg/) end it 'does not re-raise a Javascript error if it is rescued' do - expect { + expect do @driver.execute_script 'setTimeout(function() { omg }, 0)' sleep 0.01 @driver.execute_script '' - }.to raise_error(JavascriptError) + end.to raise_error(JavascriptError) # should not raise again expect(@driver.evaluate_script('1+1')).to eq(2) @@ -646,7 +647,7 @@ module Capybara::Poltergeist sleep 0.1 expect(driver.body).to include('hello') ensure - driver.quit if driver + driver&.quit end end @@ -659,7 +660,7 @@ module Capybara::Poltergeist sleep 0.1 expect(driver.body).to include('hello') ensure - driver.quit if driver + driver&.quit end end @@ -670,7 +671,7 @@ module Capybara::Poltergeist driver.visit session_url('/poltergeist/headers') expect(driver.body).to include('USER_AGENT: PageSettingsOverride') ensure - driver.quit if driver + driver&.quit end end @@ -679,12 +680,11 @@ module Capybara::Poltergeist # If PJS resource timeout is less than drivers timeout it should ignore resources not loading in time driver = Capybara::Poltergeist::Driver.new(@session.app, page_settings: { resourceTimeout: 1000 }, logger: TestSessions.logger) driver.timeout = 3 - start = Time.now - expect{ + expect do driver.visit session_url('/poltergeist/visit_timeout') - }.not_to raise_error + end.not_to raise_error ensure - driver.quit if driver + driver&.quit end end end @@ -703,18 +703,18 @@ module Capybara::Poltergeist it 'has a descriptive message when DNS incorrect' do url = "http://nope:#{@port}/" - expect { + expect do @session.visit(url) - }.to raise_error(StatusFailError, "Request to '#{url}' failed to reach server, check DNS and/or server status") + end.to raise_error(StatusFailError, "Request to '#{url}' failed to reach server, check DNS and/or server status") end it 'reports open resource requests' do old_timeout = @session.driver.timeout begin @session.driver.timeout = 2 - expect{ + expect do @session.visit('/poltergeist/visit_timeout') - }.to raise_error(StatusFailError, /resources still waiting http:\/\/.*\/poltergeist\/really_slow/) + end.to raise_error(StatusFailError, %r{resources still waiting http://.*/poltergeist/really_slow}) ensure @session.driver.timeout = old_timeout end @@ -724,9 +724,9 @@ module Capybara::Poltergeist old_timeout = @session.driver.timeout begin @session.driver.timeout = 2 - expect{ + expect do @session.visit('/poltergeist/really_slow') - }.to raise_error(StatusFailError) {|error| + end.to raise_error(StatusFailError) { |error| expect(error.message).not_to include('resources still waiting') } ensure @@ -814,14 +814,13 @@ module Capybara::Poltergeist end end - context "memory cache clearing" do - + context 'memory cache clearing' do before do @driver.restart end - it "can clear memory cache when supported (phantomjs >=2.0.0)" do - skip "clear_memory_cache is not supported by tested PhantomJS" unless phantom_version_is? ">= 2.0.0", @driver + it 'can clear memory cache when supported (phantomjs >=2.0.0)' do + skip 'clear_memory_cache is not supported by tested PhantomJS' unless phantom_version_is? '>= 2.0.0', @driver @driver.clear_memory_cache @@ -841,15 +840,15 @@ module Capybara::Poltergeist expect(another_request.response_parts.last.status).to eq(200) end - it "raises error when it is unsupported (phantomjs <2.0.0)" do - skip "clear_memory_cache is supported by tested PhantomJS" if phantom_version_is? ">= 2.0.0", @driver + it 'raises error when it is unsupported (phantomjs <2.0.0)' do + skip 'clear_memory_cache is supported by tested PhantomJS' if phantom_version_is? '>= 2.0.0', @driver @session.visit('/poltergeist/cacheable') first_request = @driver.network_traffic.last expect(@driver.network_traffic.length).to eq(1) expect(first_request.response_parts.last.status).to eq(200) - expect{@driver.clear_memory_cache}.to raise_error(Capybara::Poltergeist::UnsupportedFeature) + expect { @driver.clear_memory_cache }.to raise_error(Capybara::Poltergeist::UnsupportedFeature) @session.visit('/poltergeist/cacheable') expect(@driver.network_traffic.length).to eq(2) @@ -996,14 +995,14 @@ module Capybara::Poltergeist # If var is unspecified, skip test host = ENV['POLTERGEIST_TEST_HOST'] - skip "POLTERGEIST_TEST_HOST not set" if host.nil? + skip 'POLTERGEIST_TEST_HOST not set' if host.nil? driver = Capybara::Poltergeist::Driver.new(@driver.app, host: host, port: 12345) driver.visit session_url('/') expect { TCPServer.new(host, 12345) }.to raise_error(Errno::EADDRINUSE) ensure - driver.quit if driver + driver&.quit end end @@ -1014,7 +1013,7 @@ module Capybara::Poltergeist window.open('/poltergeist/simple', 'popup') JS - expect(@driver.window_handles).to eq(['0', '1']) + expect(@driver.window_handles).to eq(%w[0 1]) popup2 = @session.window_opened_by do @session.execute_script <<-JS @@ -1022,24 +1021,24 @@ module Capybara::Poltergeist JS end - expect(@driver.window_handles).to eq(['0', '1', '2']) + expect(@driver.window_handles).to eq(%w[0 1 2]) @session.within_window(popup2) do expect(@session.html).to include('Test') @session.execute_script('window.close()') end - sleep 0.1; + sleep 0.1 - expect(@driver.window_handles).to eq(['0', '1']) + expect(@driver.window_handles).to eq(%w[0 1]) end context 'a new window inherits settings' do it 'inherits size' do @session.visit '/' - @session.current_window.resize_to(1200,800) + @session.current_window.resize_to(1200, 800) new_tab = @session.open_new_window - expect(new_tab.size).to eq [1200,800] + expect(new_tab.size).to eq [1200, 800] end it 'inherits url_blacklist' do @@ -1067,14 +1066,13 @@ module Capybara::Poltergeist expect(@session).to have_content('We should see this.') end @session.within_frame 'unwantedframe' do - #make sure non whitelisted urls are blocked + # make sure non whitelisted urls are blocked expect(@session).not_to have_content("We shouldn't see this.") end end end end - it 'resizes windows' do @session.visit '/' @@ -1090,11 +1088,11 @@ module Capybara::Poltergeist JS end - popup1.resize_to(100,200) - popup2.resize_to(200,100) + popup1.resize_to(100, 200) + popup2.resize_to(200, 100) - expect(popup1.size).to eq([100,200]) - expect(popup2.size).to eq([200,100]) + expect(popup1.size).to eq([100, 200]) + expect(popup2.size).to eq([200, 100]) end it 'clears local storage between tests' do @@ -1282,7 +1280,7 @@ module Capybara::Poltergeist end session.within_frame 'unwantedframe' do - #make sure non whitelisted urls are blocked + # make sure non whitelisted urls are blocked expect(session).not_to have_content("We shouldn't see this.") end @@ -1294,13 +1292,12 @@ module Capybara::Poltergeist expect(session).to have_content('We should see this.') end session.within_frame 'unwantedframe' do - #make sure non whitelisted urls are blocked + # make sure non whitelisted urls are blocked expect(session).not_to have_content("We shouldn't see this.") end end end - context 'has ability to send keys' do before { @session.visit('/poltergeist/send_keys') } @@ -1389,7 +1386,7 @@ module Capybara::Poltergeist it 'sends sequences with modifiers and symbols' do input = @session.find(:css, '#empty_input') - input.native.send_keys('t', 'r', 'i', 'n', 'g', [:Ctrl, :Left], 's') + input.native.send_keys('t', 'r', 'i', 'n', 'g', %i[Ctrl Left], 's') expect(input.value).to eq('string') end @@ -1397,7 +1394,7 @@ module Capybara::Poltergeist it 'sends sequences with multiple modifiers and symbols' do input = @session.find(:css, '#empty_input') - input.native.send_keys('t', 'r', 'i', 'n', 'g', [:Ctrl, :Shift, :Left], 's') + input.native.send_keys('t', 'r', 'i', 'n', 'g', %i[Ctrl Shift Left], 's') expect(input.value).to eq('s') end @@ -1413,7 +1410,7 @@ module Capybara::Poltergeist it 'sends modifiers with multiple keys' do input = @session.find(:css, '#empty_input') - input.native.send_keys('poltre', [:Shift, :Left, :Left], 'ergeist') + input.native.send_keys('poltre', %i[Shift Left Left], 'ergeist') expect(input.value).to eq('poltergeist') end @@ -1431,38 +1428,38 @@ module Capybara::Poltergeist input.send_keys([:shift, '.'], [:shift, 't']) - expect(@session.find(:css, '#key-events-output')).to have_text("keydown:16 keydown:190 keydown:16 keydown:84") + expect(@session.find(:css, '#key-events-output')).to have_text('keydown:16 keydown:190 keydown:16 keydown:84') end it 'suuports snake_case sepcified keys (Capybara standard)' do input = @session.find(:css, '#empty_input') input.send_keys(:PageUp, :page_up) - expect(@session.find(:css, '#key-events-output')).to have_text("keydown:33", count: 2) + expect(@session.find(:css, '#key-events-output')).to have_text('keydown:33', count: 2) end it 'supports :control alias for :Ctrl' do input = @session.find(:css, '#empty_input') input.send_keys([:Ctrl, 'a'], [:control, 'a']) - expect(@session.find(:css, '#key-events-output')).to have_text("keydown:17 keydown:65", count: 2) + expect(@session.find(:css, '#key-events-output')).to have_text('keydown:17 keydown:65', count: 2) end it 'supports :command alias for :Meta' do input = @session.find(:css, '#empty_input') input.send_keys([:Meta, 'z'], [:command, 'z']) - expect(@session.find(:css, '#key-events-output')).to have_text("keydown:91 keydown:90", count: 2) + expect(@session.find(:css, '#key-events-output')).to have_text('keydown:91 keydown:90', count: 2) end it 'supports Capybara specified numpad keys' do input = @session.find(:css, '#empty_input') input.send_keys(:numpad2, :numpad8, :divide, :decimal) - expect(@session.find(:css, '#key-events-output')).to have_text("keydown:98 keydown:104 keydown:111 keydown:110") + expect(@session.find(:css, '#key-events-output')).to have_text('keydown:98 keydown:104 keydown:111 keydown:110') end it 'raises error for unknown keys' do input = @session.find(:css, '#empty_input') - expect { + expect do input.send_keys('abc', :blah) - }.to raise_error Capybara::Poltergeist::KeyError, 'Unknown key: Blah' + end.to raise_error Capybara::Poltergeist::KeyError, 'Unknown key: Blah' end end @@ -1487,10 +1484,10 @@ module Capybara::Poltergeist expect(input.text).to eq('replacement text') end - it "sets a content editable childs content" do + it 'sets a content editable childs content' do @session.visit('/with_js') - @session.find(:css,'#existing_content_editable_child').set('WYSIWYG') - expect(@session.find(:css,'#existing_content_editable_child').text).to eq('WYSIWYG') + @session.find(:css, '#existing_content_editable_child').set('WYSIWYG') + expect(@session.find(:css, '#existing_content_editable_child').text).to eq('WYSIWYG') end end @@ -1512,22 +1509,22 @@ module Capybara::Poltergeist end end - context 'evaluate_script'do + context 'evaluate_script' do it 'can return an element' do @session.visit('/poltergeist/send_keys') element = @session.driver.evaluate_script('document.getElementById("empty_input")') expect(element).to eq(@session.find(:id, 'empty_input').native) end - it 'can return structures with elements' do + it 'can return structures with elements' do @session.visit('/poltergeist/send_keys') result = @session.driver.evaluate_script('{ a: document.getElementById("empty_input"), b: { c: document.querySelectorAll("#empty_textarea, #filled_textarea") } }') - expect(result).to eq({ + expect(result).to eq( 'a' => @session.driver.find_css('#empty_input').first, 'b' => { 'c' => @session.driver.find_css('#empty_textarea, #filled_textarea') } - }) + ) end end @@ -1537,15 +1534,15 @@ module Capybara::Poltergeist expect(@session.driver.evaluate_async_script('arguments[0](null)')).to be_nil expect(@session.driver.evaluate_async_script('arguments[0](false)')).to be false expect(@session.driver.evaluate_async_script('arguments[0](true)')).to be true - expect(@session.driver.evaluate_async_script("arguments[0]({foo: 'bar'})")).to eq({'foo' => 'bar'}) + expect(@session.driver.evaluate_async_script("arguments[0]({foo: 'bar'})")).to eq('foo' => 'bar') end end it 'will timeout' do @session.using_wait_time(1) do - expect { + expect do @session.driver.evaluate_async_script('var callback=arguments[0]; setTimeout(function(){callback(true)}, 4000)') - }.to raise_error Capybara::Poltergeist::ScriptTimeoutError + end.to raise_error Capybara::Poltergeist::ScriptTimeoutError end end end diff --git a/spec/integration/session_spec.rb b/spec/integration/session_spec.rb index fde19d4..13511dc 100644 --- a/spec/integration/session_spec.rb +++ b/spec/integration/session_spec.rb @@ -1,4 +1,3 @@ -# coding: utf-8 # frozen_string_literal: true require 'spec_helper' @@ -57,11 +56,11 @@ describe Capybara::Session do context 'when someone (*cough* prototype *cough*) messes with Array#toJSON' do before do @session.visit('/poltergeist/index') - array_munge = <<-EOS + array_munge = <<-JS Array.prototype.toJSON = function() { return "ohai"; } - EOS + JS @session.execute_script array_munge end @@ -193,7 +192,7 @@ describe Capybara::Session do it 'accepts negatives in a number field' do element = @session.find(:css, '#change_me_number') - element.set -100 + element.set(-100) expect(element.value).to eq('-100') end @@ -290,13 +289,13 @@ describe Capybara::Session do end it 'gets innerHTML' do - expect(@session.find(:css,'.some_other_class')['innerHTML']).to eq '

foobar

' + expect(@session.find(:css, '.some_other_class')['innerHTML']).to eq '

foobar

' end it 'gets attribute' do link = @session.find(:link, 'Loop') expect(link['data-random']).to eq '42' - expect(link['onclick']).to eq "return false;" + expect(link['onclick']).to eq 'return false;' end it 'gets boolean attributes as booleans' do @@ -355,7 +354,7 @@ describe Capybara::Session do expect(@session.evaluate_script('null')).to be_nil expect(@session.evaluate_script('false')).to be false expect(@session.evaluate_script('true')).to be true - expect(@session.evaluate_script("{foo: 'bar'}")).to eq({'foo' => 'bar'}) + expect(@session.evaluate_script("{foo: 'bar'}")).to eq('foo' => 'bar') end it 'can evaluate a statement ending with a semicolon' do @@ -382,8 +381,8 @@ describe Capybara::Session do @session.driver.resize(200, 200) log = @session.find(:css, '#log') - instructions = %w(one four one two three) - instructions.each do |instruction, i| + instructions = %w[one four one two three] + instructions.each do |instruction| @session.find(:css, "##{instruction}").click expect(log.text).to eq(instruction) end @@ -411,18 +410,18 @@ describe Capybara::Session do end it 'detects if an element is obscured when clicking' do - expect { + expect do @session.find(:css, '#one').click - }.to raise_error(Capybara::Poltergeist::MouseEventFailed) { |error| + end.to raise_error(Capybara::Poltergeist::MouseEventFailed) { |error| expect(error.selector).to eq('html body div#two.box') expect(error.message).to include('[200, 200]') } end it 'clicks in the centre of an element' do - expect { + expect do @session.find(:css, '#one').click - }.to raise_error(Capybara::Poltergeist::MouseEventFailed) { |error| + end.to raise_error(Capybara::Poltergeist::MouseEventFailed) { |error| expect(error.position).to eq([200, 200]) } end @@ -430,9 +429,9 @@ describe Capybara::Session do it 'clicks in the centre of an element within the viewport, if part is outside the viewport' do @session.driver.resize(200, 200) - expect { + expect do @session.find(:css, '#one').click - }.to raise_error(Capybara::Poltergeist::MouseEventFailed) { |error| + end.to raise_error(Capybara::Poltergeist::MouseEventFailed) { |error| expect(error.position.first).to eq(150) } end @@ -449,16 +448,16 @@ describe Capybara::Session do end it 'detects if an element is obscured when clicking' do - expect { + expect do @session.find(:css, '#one').click - }.to raise_error(Capybara::Poltergeist::MouseEventFailed) { |error| + end.to raise_error(Capybara::Poltergeist::MouseEventFailed) { |error| expect(error.selector).to eq('html body svg#svg.box') expect(error.message).to include('[200, 200]') } end end - context "with image maps" do + context 'with image maps' do before do @session.visit('/poltergeist/image_map') end @@ -471,12 +470,12 @@ describe Capybara::Session do end it "doesn't click if the associated img is hidden" do - expect { + expect do @session.find(:css, 'map[name=testmap2] area[shape=circle]').click - }.to raise_error(Capybara::ElementNotFound) - expect { + end.to raise_error(Capybara::ElementNotFound) + expect do @session.find(:css, 'map[name=testmap2] area[shape=circle]', visible: false).click - }.to raise_error(Capybara::Poltergeist::MouseEventFailed) + end.to raise_error(Capybara::Poltergeist::MouseEventFailed) end end end @@ -490,8 +489,8 @@ describe Capybara::Session do @session.driver.resize(200, 200) log = @session.find(:css, '#log') - instructions = %w(one four one two three) - instructions.each do |instruction, i| + instructions = %w[one four one two three] + instructions.each do |instruction| @session.find(:css, "##{instruction}").base.double_click expect(log.text).to eq(instruction) end @@ -531,7 +530,7 @@ describe Capybara::Session do return a; })() JS - expect(@session.evaluate_script(code)).to eq({"a"=>"(cyclic structure)", "b"=>{}, "c"=>{"a"=>"(cyclic structure)"}}) + expect(@session.evaluate_script(code)).to eq('a' => '(cyclic structure)', 'b' => {}, 'c' => { 'a' => '(cyclic structure)' }) end if Capybara::VERSION.to_f < 3.0 @@ -548,12 +547,12 @@ describe Capybara::Session do it 'handles hash changes' do @session.visit '/#omg' - expect(@session.current_url).to match(/\/#omg$/) + expect(@session.current_url).to match(%r{/#omg$}) @session.execute_script <<-JS window.onhashchange = function() { window.last_hashchange = window.location.hash } JS @session.visit '/#foo' - expect(@session.current_url).to match(/\/#foo$/) + expect(@session.current_url).to match(%r{/#foo$}) expect(@session.evaluate_script('window.last_hashchange')).to eq('#foo') end @@ -571,12 +570,12 @@ describe Capybara::Session do end it 'supports url in parameter' do - @session.visit "/poltergeist/arbitrary_path/200/foo%20asd?a=http://example.com/asd%20asd" + @session.visit '/poltergeist/arbitrary_path/200/foo%20asd?a=http://example.com/asd%20asd' expect(request_uri).to eq('/poltergeist/arbitrary_path/200/foo%20asd?a=http://example.com/asd%20asd') end it 'supports restricted characters " []:/+&="' do - @session.visit "/poltergeist/arbitrary_path/200/foo?a=%20%5B%5D%3A%2F%2B%26%3D" + @session.visit '/poltergeist/arbitrary_path/200/foo?a=%20%5B%5D%3A%2F%2B%26%3D' expect(request_uri).to eq('/poltergeist/arbitrary_path/200/foo?a=%20%5B%5D%3A%2F%2B%26%3D') end @@ -596,7 +595,7 @@ describe Capybara::Session do droppable = @session.find(:css, '#drag_to #droppable') draggable.drag_to(droppable) - expect( droppable ).to have_content( "Dropped" ) + expect(droppable).to have_content('Dropped') end it 'supports drag_by on native element' do @@ -610,10 +609,9 @@ describe Capybara::Session do top_after = @session.evaluate_script('$("#drag_by .draggable").position().top') left_after = @session.evaluate_script('$("#drag_by .draggable").position().left') - expect( top_after ).to eq( top_before + 15 ) - expect( left_after ).to eq( left_before + 15 ) + expect(top_after).to eq(top_before + 15) + expect(left_after).to eq(left_before + 15) end - end context 'window switching support' do @@ -721,7 +719,7 @@ describe Capybara::Session do expect(@session.driver.frame_url).to end_with('/poltergeist/frames') end - context "with src == about:blank" do + context 'with src == about:blank' do it "doesn't hang if no document created" do @session.visit '/' @session.execute_script <<-JS @@ -749,9 +747,9 @@ describe Capybara::Session do end end - context "with no src attribute" do + context 'with no src attribute' do it "doesn't hang if the srcdoc attribute is used" do - skip "srcdoc attribute not supported by tested PhantomJS version" unless phantom_version_is? ">= 2.0.0", @session.driver + skip 'srcdoc attribute not supported by tested PhantomJS version' unless phantom_version_is? '>= 2.0.0', @session.driver @session.visit '/' @session.execute_script <<-JS document.body.innerHTML += '