Code cleanup driven by rubocop

This commit is contained in:
Thomas Walpole 2018-05-22 13:22:03 -07:00
parent e016661f60
commit 53beed0623
26 changed files with 438 additions and 347 deletions

102
.rubocop.yml Normal file
View File

@ -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

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
source 'https://rubygems.org' source 'https://rubygems.org'
gemspec gemspec
@ -5,7 +7,7 @@ gemspec
gem 'puma' gem 'puma'
platforms :rbx do platforms :rbx do
gem 'rubysl'
gem 'racc'
gem 'json' gem 'json'
gem 'racc'
gem 'rubysl'
end end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
guard 'coffeescript', input: 'lib/capybara/poltergeist/client', guard 'coffeescript', input: 'lib/capybara/poltergeist/client',
output: 'lib/capybara/poltergeist/client/compiled', output: 'lib/capybara/poltergeist/client/compiled',
bare: true bare: true

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'bundler/setup' require 'bundler/setup'
require 'rspec/core/rake_task' require 'rspec/core/rake_task'
@ -5,7 +7,7 @@ require 'capybara/poltergeist/version'
require 'coffee-script' require 'coffee-script'
RSpec::Core::RakeTask.new('test') RSpec::Core::RakeTask.new('test')
task default: [:compile, :test] task default: %i[compile test]
task(:autocompile) { system 'guard' } task(:autocompile) { system 'guard' }

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'bundler/setup' require 'bundler/setup'
require File.expand_path('spec/support/test_app') require File.expand_path('spec/support/test_app')
run TestApp run TestApp

View File

@ -1,10 +1,5 @@
# frozen_string_literal: true # 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' require 'capybara'
module Capybara module Capybara

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require "capybara/poltergeist/errors" require 'capybara/poltergeist/errors'
require "capybara/poltergeist/command" require 'capybara/poltergeist/command'
require 'json' require 'json'
require 'time' require 'time'
@ -15,8 +15,8 @@ module Capybara::Poltergeist
'Poltergeist.NoSuchWindowError' => NoSuchWindowError, 'Poltergeist.NoSuchWindowError' => NoSuchWindowError,
'Poltergeist.ScriptTimeoutError' => ScriptTimeoutError, 'Poltergeist.ScriptTimeoutError' => ScriptTimeoutError,
'Poltergeist.UnsupportedFeature' => UnsupportedFeature, 'Poltergeist.UnsupportedFeature' => UnsupportedFeature,
'Poltergeist.KeyError' => KeyError, 'Poltergeist.KeyError' => KeyError
} }.freeze
attr_reader :server, :client, :logger attr_reader :server, :client, :logger
@ -144,7 +144,7 @@ module Capybara::Poltergeist
command 'execute', script, *args command 'execute', script, *args
end end
def within_frame(handle, &block) def within_frame(handle)
if handle.is_a?(Capybara::Node::Base) if handle.is_a?(Capybara::Node::Base)
command 'push_frame', [handle.native.page_id, handle.native.id] command 'push_frame', [handle.native.page_id, handle.native.id]
else else
@ -192,10 +192,10 @@ module Capybara::Poltergeist
handle = command 'window_handle', locator handle = command 'window_handle', locator
raise NoSuchWindowError unless handle raise NoSuchWindowError unless handle
return handle handle
end end
def within_window(locator, &block) def within_window(locator)
original = window_handle original = window_handle
handle = find_window_handle(locator) handle = find_window_handle(locator)
switch_to_window(handle) switch_to_window(handle)
@ -204,15 +204,15 @@ module Capybara::Poltergeist
switch_to_window(original) switch_to_window(original)
end end
def click(page_id, id, keys=[], offset={}) def click(page_id, id, keys = [], offset = {})
command 'click', page_id, id, keys, offset command 'click', page_id, id, keys, offset
end 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 command 'right_click', page_id, id, keys, offset
end 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 command 'double_click', page_id, id, keys, offset
end end
@ -313,7 +313,7 @@ module Capybara::Poltergeist
command 'add_headers', headers command 'add_headers', headers
end end
def add_header(header, options={}) def add_header(header, options = {})
command 'add_header', header, options command 'add_header', header, options
end end
@ -326,10 +326,7 @@ module Capybara::Poltergeist
end end
def set_cookie(cookie) def set_cookie(cookie)
if cookie[:expires] cookie[:expires] = cookie[:expires].to_i * 1000 if cookie[:expires]
cookie[:expires] = cookie[:expires].to_i * 1000
end
command 'set_cookie', cookie command 'set_cookie', cookie
end end
@ -389,11 +386,11 @@ module Capybara::Poltergeist
response = server.send(cmd) response = server.send(cmd)
log response log response
json = JSON.load(response) json = JSON.parse(response)
if json['error'] if json['error']
klass = ERROR_MAPPINGS[json['error']['name']] || BrowserError klass = ERROR_MAPPINGS[json['error']['name']] || BrowserError
raise klass.new(json['error']) raise klass, json['error']
else else
json['response'] json['response']
end end
@ -443,14 +440,13 @@ module Capybara::Poltergeist
private private
def log(message) def log(message)
logger.puts message if logger logger&.puts message
end end
def check_render_options!(options) def check_render_options!(options)
if !!options[:full] && options.has_key?(:selector) return unless options[:full] && options.key?(:selector)
warn "Ignoring :selector in #render since :full => true was given at #{caller.first}" warn "Ignoring :selector in #render since :full => true was given at #{caller(1..1).first}"
options.delete(:selector) options.delete(:selector)
end
end end
KEY_ALIASES = { KEY_ALIASES = {
@ -463,7 +459,7 @@ module Capybara::Poltergeist
divide: 'numpad/', divide: 'numpad/',
subtract: 'numpad-', subtract: 'numpad-',
decimal: 'numpad.' decimal: 'numpad.'
} }.freeze
def normalize_keys(keys) def normalize_keys(keys)
keys.map do |key_desc| keys.map do |key_desc|
@ -474,9 +470,9 @@ module Capybara::Poltergeist
# [:Ctrl, :Left] => { modifier: "ctrl", key: 'Left' } # [:Ctrl, :Left] => { modifier: "ctrl", key: 'Left' }
# [:Ctrl, :Shift, :Left] => { modifier: "ctrl,shift", key: 'Left' } # [:Ctrl, :Shift, :Left] => { modifier: "ctrl,shift", key: 'Left' }
# [:Ctrl, :Left, :Left] => { modifier: "ctrl", key: [:Left, :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) } chunked_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] modifiers = if chunked_keys.peek[0]
_keys.next[1].map do |k| chunked_keys.next[1].map do |k|
k = k.to_s.downcase k = k.to_s.downcase
k = 'ctrl' if k == 'control' k = 'ctrl' if k == 'control'
k = 'meta' if k == 'command' k = 'meta' if k == 'command'
@ -485,15 +481,15 @@ module Capybara::Poltergeist
else else
'' ''
end 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 } { modifier: modifiers, keys: letters }
when Symbol when Symbol
# Return a known sequence for PhantomJS # Return a known sequence for PhantomJS
key = KEY_ALIASES.fetch(key_desc, key_desc) 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' } res = { keys: match[1], modifier: 'keypad' }
elsif key !~ /^[A-Z]/ elsif key !~ /^[A-Z]/
key = key.to_s.split('_').map{ |e| e.capitalize }.join key = key.to_s.split('_').map(&:capitalize).join
end end
res || { key: key } res || { key: key }
when String when String

View File

@ -1,13 +1,12 @@
# frozen_string_literal: true # frozen_string_literal: true
require "timeout" require 'capybara/poltergeist/utility'
require "capybara/poltergeist/utility"
require 'cliver' require 'cliver'
module Capybara::Poltergeist module Capybara::Poltergeist
class Client class Client
PHANTOMJS_SCRIPT = File.expand_path('../client/compiled/main.js', __FILE__) PHANTOMJS_SCRIPT = File.expand_path('client/compiled/main.js', __dir__)
PHANTOMJS_VERSION = ['>= 1.8.1', '< 3.0'] PHANTOMJS_VERSION = ['>= 1.8.1', '< 3.0'].freeze
PHANTOMJS_NAME = 'phantomjs' PHANTOMJS_NAME = 'phantomjs'
KILL_TIMEOUT = 2 # seconds KILL_TIMEOUT = 2 # seconds
@ -32,11 +31,10 @@ module Capybara::Poltergeist
start = Time.now start = Time.now
while Process.wait(pid, Process::WNOHANG).nil? while Process.wait(pid, Process::WNOHANG).nil?
sleep 0.05 sleep 0.05
if (Time.now - start) > KILL_TIMEOUT next unless (Time.now - start) > KILL_TIMEOUT
Process.kill('KILL', pid) Process.kill('KILL', pid)
Process.wait(pid) Process.wait(pid)
break break
end
end end
end end
rescue Errno::ESRCH, Errno::ECHILD rescue Errno::ESRCH, Errno::ECHILD
@ -49,8 +47,8 @@ module Capybara::Poltergeist
def initialize(server, options = {}) def initialize(server, options = {})
@server = server @server = server
@path = Cliver::detect((options[:path] || PHANTOMJS_NAME), *['>=2.1.0', '< 3.0']) @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), *PHANTOMJS_VERSION).tap do
warn "You're running an old version of PhantomJS, update to >= 2.1.1 for a better experience." warn "You're running an old version of PhantomJS, update to >= 2.1.1 for a better experience."
end end
@ -61,13 +59,13 @@ module Capybara::Poltergeist
def start def start
@read_io, @write_io = IO.pipe @read_io, @write_io = IO.pipe
@out_thread = Thread.new { @out_thread = Thread.new do
while !@read_io.eof? && data = @read_io.readpartial(1024) while !@read_io.eof? && (data = @read_io.readpartial(1024))
@phantomjs_logger.write(data) @phantomjs_logger.write(data)
end end
} end
process_options = {in: File::NULL} process_options = { in: File::NULL }
process_options[:pgroup] = true unless Capybara::Poltergeist.windows? process_options[:pgroup] = true unless Capybara::Poltergeist.windows?
process_options[:out] = @write_io if Capybara::Poltergeist.mri? process_options[:out] = @write_io if Capybara::Poltergeist.mri?
@ -78,12 +76,11 @@ module Capybara::Poltergeist
end end
def stop def stop
if pid return unless pid
kill_phantomjs kill_phantomjs
@out_thread.kill @out_thread.kill
close_io close_io
ObjectSpace.undefine_finalizer(self) ObjectSpace.undefine_finalizer(self)
end
end end
def restart def restart

View File

@ -15,7 +15,7 @@ module Capybara::Poltergeist
end end
def message def message
JSON.dump({ 'id' => @id, 'name' => @name, 'args' => @args }) JSON.dump('id' => @id, 'name' => @name, 'args' => @args)
end end
end end
end end

View File

@ -45,11 +45,10 @@ module Capybara::Poltergeist
def client def client
@client ||= Client.start(server, @client ||= Client.start(server,
:path => options[:phantomjs], path: options[:phantomjs],
:window_size => options[:window_size], window_size: options[:window_size],
:phantomjs_options => phantomjs_options, phantomjs_options: phantomjs_options,
:phantomjs_logger => phantomjs_logger phantomjs_logger: phantomjs_logger)
)
end end
def phantomjs_options def phantomjs_options
@ -58,9 +57,9 @@ module Capybara::Poltergeist
# PhantomJS defaults to only using SSLv3, which since POODLE (Oct 2014) # PhantomJS defaults to only using SSLv3, which since POODLE (Oct 2014)
# many sites have dropped from their supported protocols (eg PayPal, # many sites have dropped from their supported protocols (eg PayPal,
# Braintree). # Braintree).
list += ["--ignore-ssl-errors=yes"] unless list.grep(/ignore-ssl-errors/).any? list += ['--ignore-ssl-errors=yes'] unless list.grep(/ignore-ssl-errors/).any?
list += ["--ssl-protocol=TLSv1"] unless list.grep(/ssl-protocol/).any? list += ['--ssl-protocol=TLSv1'] unless list.grep(/ssl-protocol/).any?
list += ["--remote-debugger-port=#{inspector.port}", "--remote-debugger-autorun=yes"] if inspector list += ["--remote-debugger-port=#{inspector.port}", '--remote-debugger-autorun=yes'] if inspector
list list
end end
@ -154,17 +153,17 @@ module Capybara::Poltergeist
end end
def evaluate_script(script, *args) 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) unwrap_script_result(result)
end end
def evaluate_async_script(script, *args) 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) unwrap_script_result(result)
end end
def execute_script(script, *args) 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 nil
end end
@ -261,7 +260,7 @@ module Capybara::Poltergeist
browser.clear_network_traffic browser.clear_network_traffic
end 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) browser.set_proxy(ip, port, type, user, password)
end end
@ -296,7 +295,7 @@ module Capybara::Poltergeist
if @started if @started
URI.parse(browser.current_url).host URI.parse(browser.current_url).host
else else
URI.parse(default_cookie_host).host || "127.0.0.1" URI.parse(default_cookie_host).host || '127.0.0.1'
end end
end end
@ -338,8 +337,8 @@ module Capybara::Poltergeist
inspector.open(scheme) inspector.open(scheme)
pause pause
else else
raise Error, "To use the remote debugging, you have to launch the driver " \ raise Error, 'To use the remote debugging, you have to launch the driver ' \
"with `:inspector => true` configuration option" 'with `:inspector => true` configuration option'
end end
end end
@ -358,12 +357,13 @@ module Capybara::Poltergeist
old_trap = trap('SIGCONT') { signal = true; STDERR.puts "\nSignal SIGCONT received" } 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 keyboard = IO.select([read], nil, nil, 1) until keyboard || signal # wait for data on STDIN or signal SIGCONT received
begin unless signal
input = read.read_nonblock(80) # clear out the read buffer begin
puts unless input && input =~ /\n\z/ input = read.read_nonblock(80) # clear out the read buffer
rescue EOFError, IO::WaitReadable # Ignore problems reading from STDIN. puts unless input&.end_with?("\n")
end unless signal rescue EOFError, IO::WaitReadable # Ignore problems reading from STDIN.
end
end
ensure ensure
trap('SIGCONT', old_trap) # Restore the previous signal handler, if there was one. trap('SIGCONT', old_trap) # Restore the previous signal handler, if there was one.
STDERR.puts 'Continuing' STDERR.puts 'Continuing'
@ -416,8 +416,12 @@ module Capybara::Poltergeist
private private
def native_args(args)
args.map { |arg| arg.is_a?(Capybara::Poltergeist::Node) ? arg.native : arg }
end
def screen_size def screen_size
options[:screen_size] || [1366,768] options[:screen_size] || [1366, 768]
end end
def find_modal(options) def find_modal(options)

View File

@ -36,9 +36,9 @@ module Capybara
end end
def message def message
"There was an error inside the PhantomJS portion of Poltergeist. " \ '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, " \ '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. " \ 'this is probably a bug, so please report it. ' \
"\n\n#{name}: #{error_parameters}" "\n\n#{name}: #{error_parameters}"
end end
end end
@ -49,10 +49,10 @@ module Capybara
end end
def message 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 " \ "If you don't care about these errors, you can ignore them by " \
"setting js_errors: false in your Poltergeist configuration (see " \ 'setting js_errors: false in your Poltergeist configuration (see ' \
"documentation for details)." \ 'documentation for details).' \
"\n\n#{javascript_errors.map(&:to_s).join("\n")}" "\n\n#{javascript_errors.map(&:to_s).join("\n")}"
end end
end end
@ -93,7 +93,7 @@ module Capybara
end end
def message 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}" "#{method} selector #{selector.inspect}"
end end
end end
@ -109,11 +109,11 @@ module Capybara
class ObsoleteNode < NodeError class ObsoleteNode < NodeError
def message def message
"The element you are trying to interact with is either not part of the DOM, or is " \ '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). " \ '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 " \ "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 " \ "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
end end
@ -127,7 +127,7 @@ module Capybara
end end
def version def version
response['args'][1].values_at(*%w(major minor patch)).join '.' response['args'][1].values_at('major', 'minor', 'patch').join '.'
end end
def message def message
@ -151,14 +151,14 @@ module Capybara
def message def message
"Firing a #{name} at co-ordinates [#{position.join(', ')}] failed. Poltergeist detected " \ "Firing a #{name} at co-ordinates [#{position.join(', ')}] failed. Poltergeist detected " \
"another element with CSS selector '#{selector}' at this position. " \ "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}')." "If you don't care about overlapping elements, try using node.trigger('#{name}')."
end end
end end
class KeyError < ::ArgumentError class KeyError < ::ArgumentError
def initialize(response) def initialize(response)
super(response["args"].first) super(response['args'].first)
end end
end end
@ -169,20 +169,19 @@ module Capybara
def message def message
"Timed out waiting for response to #{@message}. It's possible that this happened " \ "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). " \ '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 " \ '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 " \ '(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." 'probably a bug in Poltergeist - please report it to the issue tracker.'
end end
end end
class ScriptTimeoutError < Error class ScriptTimeoutError < Error
def message def message
"Timed out waiting for evaluated script to resturn a value" 'Timed out waiting for evaluated script to resturn a value'
end end
end end
class DeadClient < Error class DeadClient < Error
def initialize(message) def initialize(message)
@message = message @message = message
@ -195,10 +194,10 @@ module Capybara
class PhantomJSTooOld < Error class PhantomJSTooOld < Error
def self.===(other) def self.===(other)
if Cliver::Dependency::VersionMismatch === other if other.is_a? Cliver::Dependency::VersionMismatch
warn "#{name} exception has been deprecated in favor of using the " + warn "#{name} exception has been deprecated in favor of using the " \
"cliver gem for command-line dependency detection. Please " + 'cliver gem for command-line dependency detection. Please ' \
"handle Cliver::Dependency::VersionMismatch instead." 'handle Cliver::Dependency::VersionMismatch instead.'
true true
else else
super super
@ -208,10 +207,10 @@ module Capybara
class PhantomJSFailed < Error class PhantomJSFailed < Error
def self.===(other) def self.===(other)
if Cliver::Dependency::NotMet === other if other.is_a? Cliver::Dependency::NotMet
warn "#{name} exception has been deprecated in favor of using the " + warn "#{name} exception has been deprecated in favor of using the " \
"cliver gem for command-line dependency detection. Please " + 'cliver gem for command-line dependency detection. Please ' \
"handle Cliver::Dependency::NotMet instead." 'handle Cliver::Dependency::NotMet instead.'
true true
else else
super super

View File

@ -2,7 +2,7 @@
module Capybara::Poltergeist module Capybara::Poltergeist
class Inspector class Inspector
BROWSERS = %w(chromium chromium-browser google-chrome open) BROWSERS = %w[chromium chromium-browser google-chrome open].freeze
DEFAULT_PORT = 9664 DEFAULT_PORT = 9664
def self.detect_browser def self.detect_browser
@ -30,19 +30,19 @@ module Capybara::Poltergeist
else else
raise Error, "Could not find a browser executable to open #{url(scheme)}. " \ raise Error, "Could not find a browser executable to open #{url(scheme)}. " \
"You can specify one manually using e.g. `:inspector => 'chromium'` " \ "You can specify one manually using e.g. `:inspector => 'chromium'` " \
"as a configuration option for Poltergeist." 'as a configuration option for Poltergeist.'
end end
end end
def self.browser_binary_exists?(browser) def self.browser_binary_exists?(browser)
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
exts.each { |ext| exts.each do |ext|
exe = "#{path}#{File::SEPARATOR}#{browser}#{ext}" exe = "#{path}#{File::SEPARATOR}#{browser}#{ext}"
return exe if File.executable? exe return exe if File.executable? exe
} end
end end
return nil nil
end end
end end
end end

View File

@ -39,4 +39,3 @@ module Capybara::Poltergeist::NetworkTraffic
end end
end end
end end

View File

@ -53,8 +53,8 @@ module Capybara::Poltergeist
filter_text command(:visible_text) filter_text command(:visible_text)
else else
command(:visible_text).to_s command(:visible_text).to_s
.gsub(/\A[[:space:]&&[^\u00a0]]+/, "") .gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
.gsub(/[[:space:]&&[^\u00a0]]+\z/, "") .gsub(/[[:space:]&&[^\u00a0]]+\z/, '')
.gsub(/\n+/, "\n") .gsub(/\n+/, "\n")
.tr("\u00a0", ' ') .tr("\u00a0", ' ')
end end
@ -67,10 +67,9 @@ module Capybara::Poltergeist
def [](name) def [](name)
# Although the attribute matters, the property is consistent. Return that in # Although the attribute matters, the property is consistent. Return that in
# preference to the attribute for links and images. # preference to the attribute for links and images.
if (tag_name == 'img' and name == 'src') or (tag_name == 'a' and name == 'href' ) if ((tag_name == 'img') && (name == 'src')) || ((tag_name == 'a') && (name == 'href'))
#if attribute exists get the property # if attribute exists get the property
value = command(:attribute, name) && command(:property, name) return command(:attribute, name) && command(:property, name)
return value
end end
value = property(name) value = property(name)
@ -115,8 +114,8 @@ module Capybara::Poltergeist
end end
def unselect_option def unselect_option
command(:select, false) or command(:select, false) ||
raise(Capybara::UnselectNotAllowed, "Cannot unselect option from single select box.") raise(Capybara::UnselectNotAllowed, 'Cannot unselect option from single select box.')
end end
def tag_name def tag_name
@ -139,15 +138,15 @@ module Capybara::Poltergeist
command :disabled? command :disabled?
end end
def click(keys=[], offset={}) def click(keys = [], offset = {})
command :click, keys, offset command :click, keys, offset
end end
def right_click(keys=[], offset={}) def right_click(keys = [], offset = {})
command :right_click, keys, offset command :right_click, keys, offset
end end
def double_click(keys=[], offset={}) def double_click(keys = [], offset = {})
command :double_click, keys, offset command :double_click, keys, offset
end end
@ -187,19 +186,19 @@ module Capybara::Poltergeist
# @api private # @api private
def as_json(*) def as_json(*)
{ ELEMENT: {page_id: @page_id, id: @id} } { ELEMENT: { page_id: @page_id, id: @id } }
end end
private private
def filter_text(text, visible = true) def filter_text(text)
if Capybara::VERSION.to_f < 3 if Capybara::VERSION.to_f < 3
Capybara::Helpers.normalize_whitespace(text.to_s) Capybara::Helpers.normalize_whitespace(text.to_s)
else else
text.gsub(/[\u200b\u200e\u200f]/, '') text.gsub(/[\u200b\u200e\u200f]/, '')
.gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ') .gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
.gsub(/\A[[:space:]&&[^\u00a0]]+/, "") .gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
.gsub(/[[:space:]&&[^\u00a0]]+\z/, "") .gsub(/[[:space:]&&[^\u00a0]]+\z/, '')
.tr("\u00a0", ' ') .tr("\u00a0", ' ')
end end
end end

View File

@ -42,7 +42,7 @@ module Capybara::Poltergeist
command.args.push(timeout) # set the client set visit timeout parameter 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 receive_timeout = timeout + 5 # Add a couple of seconds to let the client timeout first
end 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 end
end end

View File

@ -4,11 +4,11 @@ module Capybara
module Poltergeist module Poltergeist
class << self class << self
def windows? def windows?
RbConfig::CONFIG["host_os"] =~ /mingw|mswin|cygwin/ RbConfig::CONFIG['host_os'] =~ /mingw|mswin|cygwin/
end end
def mri? def mri?
defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby'
end end
end end
end end

View File

@ -2,6 +2,6 @@
module Capybara module Capybara
module Poltergeist module Poltergeist
VERSION = "1.18.1" VERSION = '1.18.1'
end end
end end

View File

@ -38,12 +38,9 @@ module Capybara::Poltergeist
@host = server.addr[2] @host = server.addr[2]
end end
rescue Errno::EADDRINUSE rescue Errno::EADDRINUSE
if (Time.now - time) < BIND_TIMEOUT raise if (Time.now - time) >= BIND_TIMEOUT
sleep(0.01) sleep(0.01)
retry retry
else
raise
end
end end
end end
@ -58,9 +55,9 @@ module Capybara::Poltergeist
@messages = {} @messages = {}
@driver = ::WebSocket::Driver.server(self) @driver = ::WebSocket::Driver.server(self)
@driver.on(:connect) { |event| @driver.start } @driver.on(:connect) { |_event| @driver.start }
@driver.on(:message) do |event| @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 @messages[command_id] = event.data
end end
end end
@ -71,15 +68,15 @@ module Capybara::Poltergeist
# Block until the next message is available from the Web Socket. # Block until the next message is available from the Web Socket.
# Raises Errno::EWOULDBLOCK if timeout is reached. # Raises Errno::EWOULDBLOCK if timeout is reached.
def receive(cmd_id, receive_timeout=nil) def receive(cmd_id, receive_timeout = nil)
receive_timeout ||= timeout receive_timeout ||= timeout
start = Time.now start = Time.now
until @messages.has_key?(cmd_id) until @messages.key?(cmd_id)
raise Errno::EWOULDBLOCK if (Time.now - start) >= receive_timeout raise Errno::EWOULDBLOCK if (Time.now - start) >= receive_timeout
if @receive_mutex.try_lock if @receive_mutex.try_lock
begin begin
IO.select([socket], [], [], receive_timeout) or raise Errno::EWOULDBLOCK IO.select([socket], [], [], receive_timeout) || raise(Errno::EWOULDBLOCK)
data = socket.recv(RECV_SIZE) data = socket.recv(RECV_SIZE)
break if data.empty? break if data.empty?
driver.parse(data) driver.parse(data)
@ -94,12 +91,12 @@ module Capybara::Poltergeist
end end
# Send a message and block until there is a response # 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? accept unless connected?
driver.text(message) driver.text(message)
receive(cmd_id, accept_timeout) receive(cmd_id, accept_timeout)
rescue Errno::EWOULDBLOCK rescue Errno::EWOULDBLOCK
raise TimeoutError.new(message) raise TimeoutError, message
end end
# Closing sockets separately as `close_read`, `close_write` # Closing sockets separately as `close_read`, `close_write`

View File

@ -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) $:.unshift lib unless $:.include?(lib)
require 'capybara/poltergeist/version' require 'capybara/poltergeist/version'
@ -16,23 +18,23 @@ Gem::Specification.new do |s|
'PhantomJS.' 'PhantomJS.'
s.license = 'MIT' s.license = 'MIT'
s.require_paths = ['lib'] 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.required_ruby_version = '>= 2.3.0'
s.add_runtime_dependency 'capybara', '>= 2.1', '< 4' 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 '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 '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 'rspec', '~> 3.7'
s.add_development_dependency 'sinatra', '<= 3.0' 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 end

View File

@ -39,7 +39,7 @@ module Capybara::Poltergeist
expect(File.exist?(file)).to be true expect(File.exist?(file)).to be true
ensure ensure
driver.quit if driver driver&.quit
end end
end end
@ -63,20 +63,20 @@ module Capybara::Poltergeist
end end
it 'is threadsafe in how it captures console.log' do 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 # Write something to STDOUT right before Process.spawn is called
allow(Process).to receive(:spawn).and_wrap_original do |m,*args| allow(Process).to receive(:spawn).and_wrap_original do |m, *args|
STDOUT.puts "1" STDOUT.puts '1'
$stdout.puts "2" $stdout.puts '2'
m.call(*args) m.call(*args)
end end
expect { expect do
session.visit('/poltergeist/console_log') 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
end end
@ -118,7 +118,7 @@ module Capybara::Poltergeist
@session.visit('/') @session.visit('/')
@session.current_window.maximize @session.current_window.maximize
expect(@session.current_window.size).to eq([1600, 1200]) expect(@session.current_window.size).to eq([1600, 1200])
ensure ensure
@driver.options.delete(:screen_size) @driver.options.delete(:screen_size)
end end
end end
@ -142,12 +142,12 @@ module Capybara::Poltergeist
) )
end end
driver = Capybara::Session.new(:poltergeist_with_custom_window_size, TestApp).driver driver = Capybara::Session.new(:poltergeist_with_custom_window_size, TestApp).driver
driver.visit(session_url '/') driver.visit(session_url('/'))
expect( expect(
driver.evaluate_script('[window.innerWidth, window.innerHeight]') driver.evaluate_script('[window.innerWidth, window.innerHeight]')
).to eq([800, 600]) ).to eq([800, 600])
ensure ensure
driver.quit if driver driver&.quit
end end
end end
@ -187,13 +187,13 @@ module Capybara::Poltergeist
create_screenshot file, selector: '#penultimate' create_screenshot file, selector: '#penultimate'
File.open(file, 'rb') do |f| File.open(file, 'rb') do |f|
size = @driver.evaluate_script <<-EOS size = @driver.evaluate_script <<-JS
function() { function() {
var ele = document.getElementById('penultimate'); var ele = document.getElementById('penultimate');
var rect = ele.getBoundingClientRect(); var rect = ele.getBoundingClientRect();
return [rect.width, rect.height]; return [rect.width, rect.height];
}(); }();
EOS JS
expect(ImageSize.new(f.read).size).to eq(size) expect(ImageSize.new(f.read).size).to eq(size)
end end
end end
@ -214,7 +214,7 @@ module Capybara::Poltergeist
it 'resets element positions after' do it 'resets element positions after' do
@session.visit('poltergeist/long_page') @session.visit('poltergeist/long_page')
el = @session.find(:css, '#middleish') el = @session.find(:css, '#middleish')
#make the page scroll an element into view # make the page scroll an element into view
el.click el.click
position_script = 'document.querySelector("#middleish").getBoundingClientRect()' position_script = 'document.querySelector("#middleish").getBoundingClientRect()'
offset = @session.evaluate_script(position_script) 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 it 'supports rendering the page to file without extension when format is specified' do
begin begin
file = POLTERGEIST_ROOT + "/spec/tmp/screenshot" file = POLTERGEIST_ROOT + '/spec/tmp/screenshot'
FileUtils.rm_f file FileUtils.rm_f file
@session.visit('/') @session.visit('/')
@ -286,8 +286,8 @@ module Capybara::Poltergeist
it 'changes image dimensions' do it 'changes image dimensions' do
@session.visit('/poltergeist/zoom_test') @session.visit('/poltergeist/zoom_test')
black_pixels_count = ->(file) { 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(:+) File.read(file).to_s[/{.*}/m][1...-1].split(/\W/).map { |n| n.hex.to_s(2).count('1') }.reduce(:+)
} }
@driver.save_screenshot(file) @driver.save_screenshot(file)
before = black_pixels_count[file] before = black_pixels_count[file]
@ -296,7 +296,7 @@ module Capybara::Poltergeist
@driver.save_screenshot(file) @driver.save_screenshot(file)
after = black_pixels_count[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
end end
@ -408,8 +408,8 @@ module Capybara::Poltergeist
it 'sets headers on the initial request' do it 'sets headers on the initial request' do
@driver.headers = { 'PermanentA' => 'a' } @driver.headers = { 'PermanentA' => 'a' }
@driver.add_headers('PermanentB' => 'b') @driver.add_headers('PermanentB' => 'b')
@driver.add_header('Referer', 'http://google.com', :permanent => false) @driver.add_header('Referer', 'http://google.com', permanent: false)
@driver.add_header('TempA', 'a', :permanent => false) @driver.add_header('TempA', 'a', permanent: false)
@session.visit('/poltergeist/headers_with_ajax') @session.visit('/poltergeist/headers_with_ajax')
initial_request = @session.find(:css, '#initial_request').text initial_request = @session.find(:css, '#initial_request').text
@ -427,14 +427,14 @@ module Capybara::Poltergeist
end end
it 'keeps added headers on redirects by default' do 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') @session.visit('/poltergeist/redirect_to_headers')
expect(@driver.body).to include('X_CUSTOM_HEADER: 1') expect(@driver.body).to include('X_CUSTOM_HEADER: 1')
end end
it 'does not keep added headers on redirect when ' \ it 'does not keep added headers on redirect when ' \
'permanent is no_redirect' do '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') @session.visit('/poltergeist/redirect_to_headers')
expect(@driver.body).not_to include('X_CUSTOM_HEADER: 1') 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 it 'keeps temporary headers local to the current window' do
@session.open_new_window @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.switch_to_window @session.windows.last
@session.visit('/poltergeist/headers') @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 it 'does not mix temporary headers with permanent ones when propagating to other windows' do
@session.open_new_window @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') @driver.add_header('Host', 'foo.com')
@session.switch_to_window @session.windows.last @session.switch_to_window @session.windows.last
@ -505,7 +505,7 @@ module Capybara::Poltergeist
it 'does not propagate temporary headers to new windows' do it 'does not propagate temporary headers to new windows' do
@session.visit '/' @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.open_new_window
@session.switch_to_window @session.windows.last @session.switch_to_window @session.windows.last
@ -562,8 +562,8 @@ module Capybara::Poltergeist
@extended_driver = Capybara::Poltergeist::Driver.new( @extended_driver = Capybara::Poltergeist::Driver.new(
@session.app, @session.app,
logger: TestSessions.logger, logger: TestSessions.logger,
inspector: ENV['DEBUG'] != nil, inspector: !ENV['DEBUG'].nil?,
extensions: %W% #{File.expand_path '../../support/geolocation.js', __FILE__ } % extensions: %W[#{File.expand_path '../support/geolocation.js', __dir__}]
) )
end end
@ -573,8 +573,9 @@ module Capybara::Poltergeist
it 'supports extending the phantomjs world' do it 'supports extending the phantomjs world' do
@extended_driver.visit session_url('/poltergeist/requiring_custom_extension') @extended_driver.visit session_url('/poltergeist/requiring_custom_extension')
expect(@extended_driver.body). expect(
to include(%Q%Location: <span id="location">1,-1</span>%) @extended_driver.body
).to include(%(Location: <span id="location">1,-1</span>))
expect( expect(
@extended_driver.evaluate_script("document.getElementById('location').innerHTML") @extended_driver.evaluate_script("document.getElementById('location').innerHTML")
).to eq('1,-1') ).to eq('1,-1')
@ -588,8 +589,8 @@ module Capybara::Poltergeist
@failing_driver = Capybara::Poltergeist::Driver.new( @failing_driver = Capybara::Poltergeist::Driver.new(
@session.app, @session.app,
logger: TestSessions.logger, logger: TestSessions.logger,
inspector: ENV['DEBUG'] != nil, inspector: !ENV['DEBUG'].nil?,
extensions: %W% #{File.expand_path '../../support/non_existent.js', __FILE__} % 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/) expect { @failing_driver.visit '/' }.to raise_error(Capybara::Poltergeist::BrowserError, /Unable to load extension: .*non_existent\.js/)
ensure ensure
@ -600,9 +601,9 @@ module Capybara::Poltergeist
context 'javascript errors' do context 'javascript errors' do
it 'propagates a Javascript error inside Poltergeist to a ruby exception' do it 'propagates a Javascript error inside Poltergeist to a ruby exception' do
expect { expect do
@driver.browser.command 'browser_error' @driver.browser.command 'browser_error'
}.to raise_error(BrowserError) { |e| end.to raise_error(BrowserError) { |e|
expect(e.message).to include('Error: zomg') expect(e.message).to include('Error: zomg')
# PhantomJS 2.1 refers to files as being in code subdirectory # PhantomJS 2.1 refers to files as being in code subdirectory
expect(e.message).to include('compiled/browser.js').or include('code/browser.js') expect(e.message).to include('compiled/browser.js').or include('code/browser.js')
@ -610,25 +611,25 @@ module Capybara::Poltergeist
end end
it 'propagates an asynchronous Javascript error on the page to a ruby exception' do it 'propagates an asynchronous Javascript error on the page to a ruby exception' do
expect { expect do
@driver.execute_script 'setTimeout(function() { omg }, 0)' @driver.execute_script 'setTimeout(function() { omg }, 0)'
sleep 0.01 sleep 0.01
@driver.execute_script '' @driver.execute_script ''
}.to raise_error(JavascriptError, /ReferenceError.*omg/) end.to raise_error(JavascriptError, /ReferenceError.*omg/)
end end
it 'propagates a synchronous Javascript error on the page to a ruby exception' do it 'propagates a synchronous Javascript error on the page to a ruby exception' do
expect { expect do
@driver.execute_script 'omg' @driver.execute_script 'omg'
}.to raise_error(JavascriptError, /ReferenceError.*omg/) end.to raise_error(JavascriptError, /ReferenceError.*omg/)
end end
it 'does not re-raise a Javascript error if it is rescued' do it 'does not re-raise a Javascript error if it is rescued' do
expect { expect do
@driver.execute_script 'setTimeout(function() { omg }, 0)' @driver.execute_script 'setTimeout(function() { omg }, 0)'
sleep 0.01 sleep 0.01
@driver.execute_script '' @driver.execute_script ''
}.to raise_error(JavascriptError) end.to raise_error(JavascriptError)
# should not raise again # should not raise again
expect(@driver.evaluate_script('1+1')).to eq(2) expect(@driver.evaluate_script('1+1')).to eq(2)
@ -646,7 +647,7 @@ module Capybara::Poltergeist
sleep 0.1 sleep 0.1
expect(driver.body).to include('hello') expect(driver.body).to include('hello')
ensure ensure
driver.quit if driver driver&.quit
end end
end end
@ -659,7 +660,7 @@ module Capybara::Poltergeist
sleep 0.1 sleep 0.1
expect(driver.body).to include('hello') expect(driver.body).to include('hello')
ensure ensure
driver.quit if driver driver&.quit
end end
end end
@ -670,7 +671,7 @@ module Capybara::Poltergeist
driver.visit session_url('/poltergeist/headers') driver.visit session_url('/poltergeist/headers')
expect(driver.body).to include('USER_AGENT: PageSettingsOverride') expect(driver.body).to include('USER_AGENT: PageSettingsOverride')
ensure ensure
driver.quit if driver driver&.quit
end end
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 # 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 = Capybara::Poltergeist::Driver.new(@session.app, page_settings: { resourceTimeout: 1000 }, logger: TestSessions.logger)
driver.timeout = 3 driver.timeout = 3
start = Time.now expect do
expect{
driver.visit session_url('/poltergeist/visit_timeout') driver.visit session_url('/poltergeist/visit_timeout')
}.not_to raise_error end.not_to raise_error
ensure ensure
driver.quit if driver driver&.quit
end end
end end
end end
@ -703,18 +703,18 @@ module Capybara::Poltergeist
it 'has a descriptive message when DNS incorrect' do it 'has a descriptive message when DNS incorrect' do
url = "http://nope:#{@port}/" url = "http://nope:#{@port}/"
expect { expect do
@session.visit(url) @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 end
it 'reports open resource requests' do it 'reports open resource requests' do
old_timeout = @session.driver.timeout old_timeout = @session.driver.timeout
begin begin
@session.driver.timeout = 2 @session.driver.timeout = 2
expect{ expect do
@session.visit('/poltergeist/visit_timeout') @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 ensure
@session.driver.timeout = old_timeout @session.driver.timeout = old_timeout
end end
@ -724,9 +724,9 @@ module Capybara::Poltergeist
old_timeout = @session.driver.timeout old_timeout = @session.driver.timeout
begin begin
@session.driver.timeout = 2 @session.driver.timeout = 2
expect{ expect do
@session.visit('/poltergeist/really_slow') @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') expect(error.message).not_to include('resources still waiting')
} }
ensure ensure
@ -814,14 +814,13 @@ module Capybara::Poltergeist
end end
end end
context "memory cache clearing" do context 'memory cache clearing' do
before do before do
@driver.restart @driver.restart
end end
it "can clear memory cache when supported (phantomjs >=2.0.0)" do 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 skip 'clear_memory_cache is not supported by tested PhantomJS' unless phantom_version_is? '>= 2.0.0', @driver
@driver.clear_memory_cache @driver.clear_memory_cache
@ -841,15 +840,15 @@ module Capybara::Poltergeist
expect(another_request.response_parts.last.status).to eq(200) expect(another_request.response_parts.last.status).to eq(200)
end end
it "raises error when it is unsupported (phantomjs <2.0.0)" do 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 skip 'clear_memory_cache is supported by tested PhantomJS' if phantom_version_is? '>= 2.0.0', @driver
@session.visit('/poltergeist/cacheable') @session.visit('/poltergeist/cacheable')
first_request = @driver.network_traffic.last first_request = @driver.network_traffic.last
expect(@driver.network_traffic.length).to eq(1) expect(@driver.network_traffic.length).to eq(1)
expect(first_request.response_parts.last.status).to eq(200) 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') @session.visit('/poltergeist/cacheable')
expect(@driver.network_traffic.length).to eq(2) expect(@driver.network_traffic.length).to eq(2)
@ -996,14 +995,14 @@ module Capybara::Poltergeist
# If var is unspecified, skip test # If var is unspecified, skip test
host = ENV['POLTERGEIST_TEST_HOST'] 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 = Capybara::Poltergeist::Driver.new(@driver.app, host: host, port: 12345)
driver.visit session_url('/') driver.visit session_url('/')
expect { TCPServer.new(host, 12345) }.to raise_error(Errno::EADDRINUSE) expect { TCPServer.new(host, 12345) }.to raise_error(Errno::EADDRINUSE)
ensure ensure
driver.quit if driver driver&.quit
end end
end end
@ -1014,7 +1013,7 @@ module Capybara::Poltergeist
window.open('/poltergeist/simple', 'popup') window.open('/poltergeist/simple', 'popup')
JS JS
expect(@driver.window_handles).to eq(['0', '1']) expect(@driver.window_handles).to eq(%w[0 1])
popup2 = @session.window_opened_by do popup2 = @session.window_opened_by do
@session.execute_script <<-JS @session.execute_script <<-JS
@ -1022,24 +1021,24 @@ module Capybara::Poltergeist
JS JS
end 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 @session.within_window(popup2) do
expect(@session.html).to include('Test') expect(@session.html).to include('Test')
@session.execute_script('window.close()') @session.execute_script('window.close()')
end 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 end
context 'a new window inherits settings' do context 'a new window inherits settings' do
it 'inherits size' do it 'inherits size' do
@session.visit '/' @session.visit '/'
@session.current_window.resize_to(1200,800) @session.current_window.resize_to(1200, 800)
new_tab = @session.open_new_window new_tab = @session.open_new_window
expect(new_tab.size).to eq [1200,800] expect(new_tab.size).to eq [1200, 800]
end end
it 'inherits url_blacklist' do it 'inherits url_blacklist' do
@ -1067,14 +1066,13 @@ module Capybara::Poltergeist
expect(@session).to have_content('We should see this.') expect(@session).to have_content('We should see this.')
end end
@session.within_frame 'unwantedframe' do @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.") expect(@session).not_to have_content("We shouldn't see this.")
end end
end end
end end
end end
it 'resizes windows' do it 'resizes windows' do
@session.visit '/' @session.visit '/'
@ -1090,11 +1088,11 @@ module Capybara::Poltergeist
JS JS
end end
popup1.resize_to(100,200) popup1.resize_to(100, 200)
popup2.resize_to(200,100) popup2.resize_to(200, 100)
expect(popup1.size).to eq([100,200]) expect(popup1.size).to eq([100, 200])
expect(popup2.size).to eq([200,100]) expect(popup2.size).to eq([200, 100])
end end
it 'clears local storage between tests' do it 'clears local storage between tests' do
@ -1282,7 +1280,7 @@ module Capybara::Poltergeist
end end
session.within_frame 'unwantedframe' do 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.") expect(session).not_to have_content("We shouldn't see this.")
end end
@ -1294,13 +1292,12 @@ module Capybara::Poltergeist
expect(session).to have_content('We should see this.') expect(session).to have_content('We should see this.')
end end
session.within_frame 'unwantedframe' do 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.") expect(session).not_to have_content("We shouldn't see this.")
end end
end end
end end
context 'has ability to send keys' do context 'has ability to send keys' do
before { @session.visit('/poltergeist/send_keys') } before { @session.visit('/poltergeist/send_keys') }
@ -1389,7 +1386,7 @@ module Capybara::Poltergeist
it 'sends sequences with modifiers and symbols' do it 'sends sequences with modifiers and symbols' do
input = @session.find(:css, '#empty_input') 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') expect(input.value).to eq('string')
end end
@ -1397,7 +1394,7 @@ module Capybara::Poltergeist
it 'sends sequences with multiple modifiers and symbols' do it 'sends sequences with multiple modifiers and symbols' do
input = @session.find(:css, '#empty_input') 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') expect(input.value).to eq('s')
end end
@ -1413,7 +1410,7 @@ module Capybara::Poltergeist
it 'sends modifiers with multiple keys' do it 'sends modifiers with multiple keys' do
input = @session.find(:css, '#empty_input') 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') expect(input.value).to eq('poltergeist')
end end
@ -1431,38 +1428,38 @@ module Capybara::Poltergeist
input.send_keys([:shift, '.'], [:shift, 't']) 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 end
it 'suuports snake_case sepcified keys (Capybara standard)' do it 'suuports snake_case sepcified keys (Capybara standard)' do
input = @session.find(:css, '#empty_input') input = @session.find(:css, '#empty_input')
input.send_keys(:PageUp, :page_up) 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 end
it 'supports :control alias for :Ctrl' do it 'supports :control alias for :Ctrl' do
input = @session.find(:css, '#empty_input') input = @session.find(:css, '#empty_input')
input.send_keys([:Ctrl, 'a'], [:control, 'a']) 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 end
it 'supports :command alias for :Meta' do it 'supports :command alias for :Meta' do
input = @session.find(:css, '#empty_input') input = @session.find(:css, '#empty_input')
input.send_keys([:Meta, 'z'], [:command, 'z']) 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 end
it 'supports Capybara specified numpad keys' do it 'supports Capybara specified numpad keys' do
input = @session.find(:css, '#empty_input') input = @session.find(:css, '#empty_input')
input.send_keys(:numpad2, :numpad8, :divide, :decimal) 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 end
it 'raises error for unknown keys' do it 'raises error for unknown keys' do
input = @session.find(:css, '#empty_input') input = @session.find(:css, '#empty_input')
expect { expect do
input.send_keys('abc', :blah) 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
end end
@ -1487,10 +1484,10 @@ module Capybara::Poltergeist
expect(input.text).to eq('replacement text') expect(input.text).to eq('replacement text')
end end
it "sets a content editable childs content" do it 'sets a content editable childs content' do
@session.visit('/with_js') @session.visit('/with_js')
@session.find(:css,'#existing_content_editable_child').set('WYSIWYG') @session.find(:css, '#existing_content_editable_child').set('WYSIWYG')
expect(@session.find(:css,'#existing_content_editable_child').text).to eq('WYSIWYG') expect(@session.find(:css, '#existing_content_editable_child').text).to eq('WYSIWYG')
end end
end end
@ -1512,22 +1509,22 @@ module Capybara::Poltergeist
end end
end end
context 'evaluate_script'do context 'evaluate_script' do
it 'can return an element' do it 'can return an element' do
@session.visit('/poltergeist/send_keys') @session.visit('/poltergeist/send_keys')
element = @session.driver.evaluate_script('document.getElementById("empty_input")') element = @session.driver.evaluate_script('document.getElementById("empty_input")')
expect(element).to eq(@session.find(:id, 'empty_input').native) expect(element).to eq(@session.find(:id, 'empty_input').native)
end end
it 'can return structures with elements' do it 'can return structures with elements' do
@session.visit('/poltergeist/send_keys') @session.visit('/poltergeist/send_keys')
result = @session.driver.evaluate_script('{ a: document.getElementById("empty_input"), b: { c: document.querySelectorAll("#empty_textarea, #filled_textarea") } }') 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, 'a' => @session.driver.find_css('#empty_input').first,
'b' => { 'b' => {
'c' => @session.driver.find_css('#empty_textarea, #filled_textarea') 'c' => @session.driver.find_css('#empty_textarea, #filled_textarea')
} }
}) )
end end
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](null)')).to be_nil
expect(@session.driver.evaluate_async_script('arguments[0](false)')).to be false 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](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
end end
it 'will timeout' do it 'will timeout' do
@session.using_wait_time(1) do @session.using_wait_time(1) do
expect { expect do
@session.driver.evaluate_async_script('var callback=arguments[0]; setTimeout(function(){callback(true)}, 4000)') @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 end
end end

View File

@ -1,4 +1,3 @@
# coding: utf-8
# frozen_string_literal: true # frozen_string_literal: true
require 'spec_helper' require 'spec_helper'
@ -57,11 +56,11 @@ describe Capybara::Session do
context 'when someone (*cough* prototype *cough*) messes with Array#toJSON' do context 'when someone (*cough* prototype *cough*) messes with Array#toJSON' do
before do before do
@session.visit('/poltergeist/index') @session.visit('/poltergeist/index')
array_munge = <<-EOS array_munge = <<-JS
Array.prototype.toJSON = function() { Array.prototype.toJSON = function() {
return "ohai"; return "ohai";
} }
EOS JS
@session.execute_script array_munge @session.execute_script array_munge
end end
@ -193,7 +192,7 @@ describe Capybara::Session do
it 'accepts negatives in a number field' do it 'accepts negatives in a number field' do
element = @session.find(:css, '#change_me_number') element = @session.find(:css, '#change_me_number')
element.set -100 element.set(-100)
expect(element.value).to eq('-100') expect(element.value).to eq('-100')
end end
@ -290,13 +289,13 @@ describe Capybara::Session do
end end
it 'gets innerHTML' do it 'gets innerHTML' do
expect(@session.find(:css,'.some_other_class')['innerHTML']).to eq '<p>foobar</p>' expect(@session.find(:css, '.some_other_class')['innerHTML']).to eq '<p>foobar</p>'
end end
it 'gets attribute' do it 'gets attribute' do
link = @session.find(:link, 'Loop') link = @session.find(:link, 'Loop')
expect(link['data-random']).to eq '42' expect(link['data-random']).to eq '42'
expect(link['onclick']).to eq "return false;" expect(link['onclick']).to eq 'return false;'
end end
it 'gets boolean attributes as booleans' do 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('null')).to be_nil
expect(@session.evaluate_script('false')).to be false expect(@session.evaluate_script('false')).to be false
expect(@session.evaluate_script('true')).to be true 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 end
it 'can evaluate a statement ending with a semicolon' do it 'can evaluate a statement ending with a semicolon' do
@ -382,8 +381,8 @@ describe Capybara::Session do
@session.driver.resize(200, 200) @session.driver.resize(200, 200)
log = @session.find(:css, '#log') log = @session.find(:css, '#log')
instructions = %w(one four one two three) instructions = %w[one four one two three]
instructions.each do |instruction, i| instructions.each do |instruction|
@session.find(:css, "##{instruction}").click @session.find(:css, "##{instruction}").click
expect(log.text).to eq(instruction) expect(log.text).to eq(instruction)
end end
@ -411,18 +410,18 @@ describe Capybara::Session do
end end
it 'detects if an element is obscured when clicking' do it 'detects if an element is obscured when clicking' do
expect { expect do
@session.find(:css, '#one').click @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.selector).to eq('html body div#two.box')
expect(error.message).to include('[200, 200]') expect(error.message).to include('[200, 200]')
} }
end end
it 'clicks in the centre of an element' do it 'clicks in the centre of an element' do
expect { expect do
@session.find(:css, '#one').click @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]) expect(error.position).to eq([200, 200])
} }
end 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 it 'clicks in the centre of an element within the viewport, if part is outside the viewport' do
@session.driver.resize(200, 200) @session.driver.resize(200, 200)
expect { expect do
@session.find(:css, '#one').click @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) expect(error.position.first).to eq(150)
} }
end end
@ -449,16 +448,16 @@ describe Capybara::Session do
end end
it 'detects if an element is obscured when clicking' do it 'detects if an element is obscured when clicking' do
expect { expect do
@session.find(:css, '#one').click @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.selector).to eq('html body svg#svg.box')
expect(error.message).to include('[200, 200]') expect(error.message).to include('[200, 200]')
} }
end end
end end
context "with image maps" do context 'with image maps' do
before do before do
@session.visit('/poltergeist/image_map') @session.visit('/poltergeist/image_map')
end end
@ -471,12 +470,12 @@ describe Capybara::Session do
end end
it "doesn't click if the associated img is hidden" do it "doesn't click if the associated img is hidden" do
expect { expect do
@session.find(:css, 'map[name=testmap2] area[shape=circle]').click @session.find(:css, 'map[name=testmap2] area[shape=circle]').click
}.to raise_error(Capybara::ElementNotFound) end.to raise_error(Capybara::ElementNotFound)
expect { expect do
@session.find(:css, 'map[name=testmap2] area[shape=circle]', visible: false).click @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 end
end end
@ -490,8 +489,8 @@ describe Capybara::Session do
@session.driver.resize(200, 200) @session.driver.resize(200, 200)
log = @session.find(:css, '#log') log = @session.find(:css, '#log')
instructions = %w(one four one two three) instructions = %w[one four one two three]
instructions.each do |instruction, i| instructions.each do |instruction|
@session.find(:css, "##{instruction}").base.double_click @session.find(:css, "##{instruction}").base.double_click
expect(log.text).to eq(instruction) expect(log.text).to eq(instruction)
end end
@ -531,7 +530,7 @@ describe Capybara::Session do
return a; return a;
})() })()
JS 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 end
if Capybara::VERSION.to_f < 3.0 if Capybara::VERSION.to_f < 3.0
@ -548,12 +547,12 @@ describe Capybara::Session do
it 'handles hash changes' do it 'handles hash changes' do
@session.visit '/#omg' @session.visit '/#omg'
expect(@session.current_url).to match(/\/#omg$/) expect(@session.current_url).to match(%r{/#omg$})
@session.execute_script <<-JS @session.execute_script <<-JS
window.onhashchange = function() { window.last_hashchange = window.location.hash } window.onhashchange = function() { window.last_hashchange = window.location.hash }
JS JS
@session.visit '/#foo' @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') expect(@session.evaluate_script('window.last_hashchange')).to eq('#foo')
end end
@ -571,12 +570,12 @@ describe Capybara::Session do
end end
it 'supports url in parameter' do 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') expect(request_uri).to eq('/poltergeist/arbitrary_path/200/foo%20asd?a=http://example.com/asd%20asd')
end end
it 'supports restricted characters " []:/+&="' do 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') expect(request_uri).to eq('/poltergeist/arbitrary_path/200/foo?a=%20%5B%5D%3A%2F%2B%26%3D')
end end
@ -596,7 +595,7 @@ describe Capybara::Session do
droppable = @session.find(:css, '#drag_to #droppable') droppable = @session.find(:css, '#drag_to #droppable')
draggable.drag_to(droppable) draggable.drag_to(droppable)
expect( droppable ).to have_content( "Dropped" ) expect(droppable).to have_content('Dropped')
end end
it 'supports drag_by on native element' do 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') top_after = @session.evaluate_script('$("#drag_by .draggable").position().top')
left_after = @session.evaluate_script('$("#drag_by .draggable").position().left') left_after = @session.evaluate_script('$("#drag_by .draggable").position().left')
expect( top_after ).to eq( top_before + 15 ) expect(top_after).to eq(top_before + 15)
expect( left_after ).to eq( left_before + 15 ) expect(left_after).to eq(left_before + 15)
end end
end end
context 'window switching support' do context 'window switching support' do
@ -721,7 +719,7 @@ describe Capybara::Session do
expect(@session.driver.frame_url).to end_with('/poltergeist/frames') expect(@session.driver.frame_url).to end_with('/poltergeist/frames')
end end
context "with src == about:blank" do context 'with src == about:blank' do
it "doesn't hang if no document created" do it "doesn't hang if no document created" do
@session.visit '/' @session.visit '/'
@session.execute_script <<-JS @session.execute_script <<-JS
@ -749,9 +747,9 @@ describe Capybara::Session do
end end
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 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.visit '/'
@session.execute_script <<-JS @session.execute_script <<-JS
document.body.innerHTML += '<iframe srcdoc="<p>Hello Frame</p>" name="frame">' document.body.innerHTML += '<iframe srcdoc="<p>Hello Frame</p>" name="frame">'
@ -833,11 +831,11 @@ describe Capybara::Session do
it 'does not wait forever for the frame to load' do it 'does not wait forever for the frame to load' do
@session.visit '/' @session.visit '/'
expect { expect do
@session.within_frame('omg') { } @session.within_frame('omg') {}
}.to raise_error { |e| end.to(raise_error do |e|
expect(e).to be_a(Capybara::Poltergeist::FrameNotFound).or be_a(Capybara::ElementNotFound) expect(e).to be_a(Capybara::Poltergeist::FrameNotFound).or be_a(Capybara::ElementNotFound)
} end)
end end
end end
@ -851,7 +849,7 @@ describe Capybara::Session do
@session.visit('/') @session.visit('/')
@session.find(:css, 'a').click @session.find(:css, 'a').click
position = JSON.load(TestSessions.logger.messages.last)['response']['position'] position = JSON.parse(TestSessions.logger.messages.last)['response']['position']
expect(position['x']).to_not be_nil expect(position['x']).to_not be_nil
expect(position['y']).to_not be_nil expect(position['y']).to_not be_nil
end end
@ -910,21 +908,21 @@ describe Capybara::Session do
end end
it 'gets property innerHTML' do it 'gets property innerHTML' do
expect(@session.find(:css,'.some_other_class').native.property('innerHTML')).to eq '<p>foobar</p>' expect(@session.find(:css, '.some_other_class').native.property('innerHTML')).to eq '<p>foobar</p>'
end end
it 'gets property outerHTML' do it 'gets property outerHTML' do
expect(@session.find(:css,'.some_other_class').native.property('outerHTML')).to eq '<div class="some_other_class"><p>foobar</p></div>' expect(@session.find(:css, '.some_other_class').native.property('outerHTML')).to eq '<div class="some_other_class"><p>foobar</p></div>'
end end
it 'gets non existent property' do it 'gets non existent property' do
expect(@session.find(:css,'.some_other_class').native.property('does_not_exist')).to eq nil expect(@session.find(:css, '.some_other_class').native.property('does_not_exist')).to eq nil
end end
end end
it 'allows access to element attributes' do it 'allows access to element attributes' do
@session.visit '/poltergeist/attributes_properties' @session.visit '/poltergeist/attributes_properties'
expect(@session.find(:css,'#my_link').native.attributes).to eq( expect(@session.find(:css, '#my_link').native.attributes).to eq(
'href' => '#', 'id' => 'my_link', 'class' => 'some_class', 'data' => 'rah!' 'href' => '#', 'id' => 'my_link', 'class' => 'some_class', 'data' => 'rah!'
) )
end end
@ -932,7 +930,7 @@ describe Capybara::Session do
it 'knows about its parents' do it 'knows about its parents' do
@session.visit '/poltergeist/simple' @session.visit '/poltergeist/simple'
parents = @session.find(:css, '#nav').native.parents parents = @session.find(:css, '#nav').native.parents
expect(parents.map(&:tag_name)).to eq ['li','ul','body','html'] expect(parents.map(&:tag_name)).to eq %w[li ul body html]
end end
context 'SVG tests' do context 'SVG tests' do
@ -948,33 +946,33 @@ describe Capybara::Session do
context 'modals' do context 'modals' do
it 'matches on partial strings' do it 'matches on partial strings' do
@session.visit '/poltergeist/with_js' @session.visit '/poltergeist/with_js'
expect { expect do
@session.accept_confirm '[reg.exp] (chara©+er$)' do @session.accept_confirm '[reg.exp] (chara©+er$)' do
@session.click_link('Open for match') @session.click_link('Open for match')
end end
}.not_to raise_error end.not_to raise_error
expect(@session).to have_xpath("//a[@id='open-match' and @confirmed='true']") expect(@session).to have_xpath("//a[@id='open-match' and @confirmed='true']")
end end
it 'matches on regular expressions' do it 'matches on regular expressions' do
@session.visit '/poltergeist/with_js' @session.visit '/poltergeist/with_js'
expect { expect do
@session.accept_confirm(/^.t.ext.*\[\w{3}\.\w{3}\]/i) do @session.accept_confirm(/^.t.ext.*\[\w{3}\.\w{3}\]/i) do
@session.click_link('Open for match') @session.click_link('Open for match')
end end
}.not_to raise_error end.not_to raise_error
expect(@session).to have_xpath("//a[@id='open-match' and @confirmed='true']") expect(@session).to have_xpath("//a[@id='open-match' and @confirmed='true']")
end end
it 'works with nested modals' do it 'works with nested modals' do
@session.visit '/poltergeist/with_js' @session.visit '/poltergeist/with_js'
expect { expect do
@session.dismiss_confirm 'Are you really sure?' do @session.dismiss_confirm 'Are you really sure?' do
@session.accept_confirm 'Are you sure?' do @session.accept_confirm 'Are you sure?' do
@session.click_link('Open check twice') @session.click_link('Open check twice')
end end
end end
}.not_to raise_error end.not_to raise_error
expect(@session).to have_xpath("//a[@id='open-twice' and @confirmed='false']") expect(@session).to have_xpath("//a[@id='open-twice' and @confirmed='false']")
end end
@ -988,39 +986,39 @@ describe Capybara::Session do
end end
@session.within_window(popup) do @session.within_window(popup) do
expect { expect do
@session.accept_confirm do @session.accept_confirm do
@session.click_link('Open for match') @session.click_link('Open for match')
end end
expect(@session).to have_xpath("//a[@id='open-match' and @confirmed='true']") expect(@session).to have_xpath("//a[@id='open-match' and @confirmed='true']")
}.not_to raise_error end.not_to raise_error
end end
popup.close popup.close
end end
end end
it "can go back when history state has been pushed" do it 'can go back when history state has been pushed' do
@session.visit('/') @session.visit('/')
@session.execute_script('window.history.pushState({foo: "bar"}, "title", "bar2.html");') @session.execute_script('window.history.pushState({foo: "bar"}, "title", "bar2.html");')
expect(@session).to have_current_path('/bar2.html') expect(@session).to have_current_path('/bar2.html')
expect{@session.go_back}.not_to raise_error expect { @session.go_back }.not_to raise_error
expect(@session).to have_current_path('/') expect(@session).to have_current_path('/')
end end
it "can go forward when history state is used" do it 'can go forward when history state is used' do
@session.visit('/') @session.visit('/')
@session.execute_script('window.history.pushState({foo: "bar"}, "title", "bar2.html");') @session.execute_script('window.history.pushState({foo: "bar"}, "title", "bar2.html");')
expect(@session).to have_current_path('/bar2.html') expect(@session).to have_current_path('/bar2.html')
#don't use #go_back here to isolate the test # don't use #go_back here to isolate the test
@session.execute_script('window.history.go(-1);') @session.execute_script('window.history.go(-1);')
expect(@session).to have_current_path('/') expect(@session).to have_current_path('/')
expect{@session.go_forward}.not_to raise_error expect { @session.go_forward }.not_to raise_error
expect(@session).to have_current_path('/bar2.html') expect(@session).to have_current_path('/bar2.html')
end end
context "in threadsafe mode" do context 'in threadsafe mode' do
before do before do
skip "No threadsafe mode in this version" unless Capybara.respond_to?(:threadsafe) skip 'No threadsafe mode in this version' unless Capybara.respond_to?(:threadsafe)
Capybara::SpecHelper.reset_threadsafe(true, @session) if Capybara.respond_to?(:threadsafe) Capybara::SpecHelper.reset_threadsafe(true, @session) if Capybara.respond_to?(:threadsafe)
end end
@ -1028,7 +1026,7 @@ describe Capybara::Session do
Capybara::SpecHelper.reset_threadsafe(false, @session) if Capybara.respond_to?(:threadsafe) Capybara::SpecHelper.reset_threadsafe(false, @session) if Capybara.respond_to?(:threadsafe)
end end
it "uses per session wait setting" do it 'uses per session wait setting' do
Capybara.default_max_wait_time = 1 Capybara.default_max_wait_time = 1
@session.config.default_max_wait_time = 2 @session.config.default_max_wait_time = 2
expect(@session.driver.send(:session_wait_time)).to eq 2 expect(@session.driver.send(:session_wait_time)).to eq 2
@ -1041,7 +1039,7 @@ describe Capybara::Session do
context 'with pty' do context 'with pty' do
before do before do
Tempfile.open(%w(test rb)) do |file| Tempfile.open(%w[test rb]) do |file|
file.print(script) file.print(script)
file.flush file.flush
@ -1049,14 +1047,14 @@ describe Capybara::Session do
PTY.spawn("bundle exec ruby #{file.path}") do |read, write, pid| PTY.spawn("bundle exec ruby #{file.path}") do |read, write, pid|
sleep 0.1 until read.readline.chomp == 'Please type enter' sleep 0.1 until read.readline.chomp == 'Please type enter'
write.puts write.puts
sleep 0.1 until status = PTY.check(pid) sleep 0.1 until (status = PTY.check(pid))
@status = status @status = status
end end
end end
end end
end end
let(:script) { let(:script) do
<<-RUBY <<-RUBY
require 'capybara/poltergeist' require 'capybara/poltergeist'
@ -1068,7 +1066,7 @@ describe Capybara::Session do
sleep 1 sleep 1
browser.current_url browser.current_url
RUBY RUBY
} end
it do it do
expect(@status).to be_success expect(@status).to be_success

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
POLTERGEIST_ROOT = File.expand_path('../..', __FILE__) POLTERGEIST_ROOT = File.expand_path('..', __dir__)
$:.unshift(POLTERGEIST_ROOT + '/lib') $:.unshift(POLTERGEIST_ROOT + '/lib')
require 'bundler/setup' require 'bundler/setup'
@ -40,7 +40,7 @@ module Poltergeist
class << self class << self
def set_capybara_wait_time(t) def set_capybara_wait_time(t)
Capybara.default_max_wait_time = t Capybara.default_max_wait_time = t
rescue rescue StandardError
Capybara.default_wait_time = t Capybara.default_wait_time = t
end end
end end
@ -64,7 +64,7 @@ RSpec.configure do |config|
Capybara::SpecHelper.configure(config) Capybara::SpecHelper.configure(config)
config.filter_run_excluding :full_description => lambda { |description, metadata| config.filter_run_excluding full_description: lambda { |description, _metadata|
[ [
# test is marked pending in Capybara but Poltergeist passes - disable here - have our own test in driver spec # test is marked pending in Capybara but Poltergeist passes - disable here - have our own test in driver spec
/Capybara::Session Poltergeist node #set should allow me to change the contents of a contenteditable elements child/, /Capybara::Session Poltergeist node #set should allow me to change the contents of a contenteditable elements child/,
@ -77,8 +77,8 @@ RSpec.configure do |config|
Poltergeist::SpecHelper.set_capybara_wait_time(0) Poltergeist::SpecHelper.set_capybara_wait_time(0)
end end
[:js, :modals, :windows].each do |cond| %i[js modals windows].each do |cond|
config.before(:each, :requires => cond) do config.before(:each, requires: cond) do
Poltergeist::SpecHelper.set_capybara_wait_time(1) Poltergeist::SpecHelper.set_capybara_wait_time(1)
end end
end end
@ -87,4 +87,3 @@ end
def phantom_version_is?(ver_spec, driver) def phantom_version_is?(ver_spec, driver)
Cliver.detect(driver.options[:phantomjs] || Capybara::Poltergeist::Client::PHANTOMJS_NAME, ver_spec) Cliver.detect(driver.options[:phantomjs] || Capybara::Poltergeist::Client::PHANTOMJS_NAME, ver_spec)
end end

View File

@ -4,10 +4,10 @@ require 'capybara/spec/test_app'
class TestApp class TestApp
configure do configure do
set :protection, :except => :frame_options set :protection, except: :frame_options
end end
POLTERGEIST_VIEWS = File.dirname(__FILE__) + "/views" POLTERGEIST_VIEWS = File.dirname(__FILE__) + '/views'
POLTERGEIST_PUBLIC = File.dirname(__FILE__) + "/public" POLTERGEIST_PUBLIC = File.dirname(__FILE__) + '/public'
helpers do helpers do
def requires_credentials(login, password) def requires_credentials(login, password)
@ -17,8 +17,8 @@ class TestApp
end end
def authorized?(login, password) def authorized?(login, password)
@auth ||= Rack::Auth::Basic::Request.new(request.env) @auth ||= Rack::Auth::Basic::Request.new(request.env)
@auth.provided? and @auth.basic? and @auth.credentials and @auth.credentials == [login, password] @auth.provided? && @auth.basic? && @auth.credentials && (@auth.credentials == [login, password])
end end
end end
@ -57,12 +57,12 @@ class TestApp
get '/poltergeist/slow' do get '/poltergeist/slow' do
sleep 0.2 sleep 0.2
"slow page" 'slow page'
end end
get '/poltergeist/really_slow' do get '/poltergeist/really_slow' do
sleep 3 sleep 3
"really slow page" 'really slow page'
end end
get '/poltergeist/basic_auth' do get '/poltergeist/basic_auth' do
@ -77,7 +77,7 @@ class TestApp
get '/poltergeist/cacheable' do get '/poltergeist/cacheable' do
cache_control :public, max_age: 60 cache_control :public, max_age: 60
etag "deadbeef" etag 'deadbeef'
'Cacheable request' 'Cacheable request'
end end

View File

@ -19,7 +19,7 @@ module Capybara::Poltergeist
subject.command('where is', 'the love?') subject.command('where is', 'the love?')
expect(logger.string).to include('"name":"where is","args":["the love?"]') expect(logger.string).to include('"name":"where is","args":["the love?"]')
expect(logger.string).to include("#{response}") expect(logger.string).to include(response)
end end
end end
end end

View File

@ -4,7 +4,7 @@ require 'spec_helper'
module Capybara::Poltergeist module Capybara::Poltergeist
describe Client do describe Client do
let(:server) { double(port: 6000, host: "127.0.0.1") } let(:server) { double(port: 6000, host: '127.0.0.1') }
let(:client_params) { {} } let(:client_params) { {} }
subject { Client.new(server, client_params) } subject { Client.new(server, client_params) }

View File

@ -23,22 +23,22 @@ module Capybara::Poltergeist
end end
context 'with a phantomjs_options option' do context 'with a phantomjs_options option' do
subject { Driver.new(nil, phantomjs_options: %w{--hello})} subject { Driver.new(nil, phantomjs_options: %w[--hello]) }
it "is a combination of ssl settings and the provided options" do it 'is a combination of ssl settings and the provided options' do
expect(subject.phantomjs_options).to eq(%w{--hello --ignore-ssl-errors=yes --ssl-protocol=TLSv1}) expect(subject.phantomjs_options).to eq(%w[--hello --ignore-ssl-errors=yes --ssl-protocol=TLSv1])
end end
end end
context 'with phantomjs_options containing ssl-protocol settings' do context 'with phantomjs_options containing ssl-protocol settings' do
subject { Driver.new(nil, phantomjs_options: %w{--ssl-protocol=any --ignore-ssl-errors=no})} subject { Driver.new(nil, phantomjs_options: %w[--ssl-protocol=any --ignore-ssl-errors=no]) }
it "uses the provided ssl-protocol" do it 'uses the provided ssl-protocol' do
expect(subject.phantomjs_options).to include('--ssl-protocol=any') expect(subject.phantomjs_options).to include('--ssl-protocol=any')
expect(subject.phantomjs_options).not_to include('--ssl-protocol=TLSv1') expect(subject.phantomjs_options).not_to include('--ssl-protocol=TLSv1')
end end
it "uses the provided ssl-errors" do it 'uses the provided ssl-errors' do
expect(subject.phantomjs_options).to include('--ignore-ssl-errors=no') expect(subject.phantomjs_options).to include('--ignore-ssl-errors=no')
expect(subject.phantomjs_options).not_to include('--ignore-ssl-errors=yes') expect(subject.phantomjs_options).not_to include('--ignore-ssl-errors=yes')
end end
@ -78,11 +78,11 @@ module Capybara::Poltergeist
end end
it 'can pause indefinitely' do it 'can pause indefinitely' do
expect { expect do
Timeout::timeout(3) do Timeout.timeout(3) do
subject.pause subject.pause
end end
}.to raise_error(Timeout::Error) end.to raise_error(Timeout::Error)
end end
it 'can pause and resume with keyboard input' do it 'can pause and resume with keyboard input' do
@ -91,7 +91,7 @@ module Capybara::Poltergeist
write_io.write "\n" write_io.write "\n"
begin begin
Timeout::timeout(3) do Timeout.timeout(3) do
subject.pause subject.pause
end end
ensure ensure
@ -102,11 +102,10 @@ module Capybara::Poltergeist
it 'can pause and resume with signal' do it 'can pause and resume with signal' do
Thread.new { sleep(2); Process.kill('CONT', Process.pid); } Thread.new { sleep(2); Process.kill('CONT', Process.pid); }
Timeout::timeout(4) do Timeout.timeout(4) do
subject.pause subject.pause
end end
end end
end end
context 'with a :timeout option' do context 'with a :timeout option' do