2012-10-06 22:56:51 +01:00
|
|
|
require 'uri'
|
|
|
|
|
2011-10-27 23:34:14 +01:00
|
|
|
module Capybara::Poltergeist
|
|
|
|
class Driver < Capybara::Driver::Base
|
2012-02-29 12:32:13 +00:00
|
|
|
DEFAULT_TIMEOUT = 30
|
|
|
|
|
2012-12-04 15:11:27 +01:00
|
|
|
attr_reader :app, :server, :client, :browser, :options
|
2011-10-27 23:34:14 +01:00
|
|
|
|
|
|
|
def initialize(app, options = {})
|
2012-02-29 12:32:13 +00:00
|
|
|
@app = app
|
|
|
|
@options = options
|
|
|
|
@browser = nil
|
|
|
|
@inspector = nil
|
|
|
|
@server = nil
|
|
|
|
@client = nil
|
2013-01-28 22:58:34 +00:00
|
|
|
@started = false
|
2012-12-04 15:11:27 +01:00
|
|
|
end
|
2011-10-27 23:34:14 +01:00
|
|
|
|
2012-12-04 15:11:27 +01:00
|
|
|
def needs_server?
|
|
|
|
true
|
2011-10-27 23:34:14 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def browser
|
2013-01-26 21:11:44 +00:00
|
|
|
@browser ||= begin
|
|
|
|
browser = Browser.new(server, client, logger)
|
2013-01-27 10:06:44 +00:00
|
|
|
browser.js_errors = options[:js_errors] if options.key?(:js_errors)
|
|
|
|
browser.extensions = options.fetch(:extensions, [])
|
2013-01-31 21:45:10 +00:00
|
|
|
browser.debug = true if options[:debug]
|
2013-01-26 21:11:44 +00:00
|
|
|
browser
|
|
|
|
end
|
2011-10-27 23:34:14 +01:00
|
|
|
end
|
|
|
|
|
2012-02-29 00:02:43 +00:00
|
|
|
def inspector
|
|
|
|
@inspector ||= options[:inspector] && Inspector.new(options[:inspector])
|
|
|
|
end
|
|
|
|
|
2012-02-29 12:32:13 +00:00
|
|
|
def server
|
2013-01-31 20:44:55 +00:00
|
|
|
@server ||= Server.new(options[:port], options.fetch(:timeout) { DEFAULT_TIMEOUT })
|
2012-02-29 12:32:13 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def client
|
2013-01-31 20:44:55 +00:00
|
|
|
@client ||= Client.start(server,
|
2012-07-11 20:25:17 +01:00
|
|
|
:path => options[:phantomjs],
|
|
|
|
:window_size => options[:window_size],
|
2013-01-07 23:25:32 -05:00
|
|
|
:phantomjs_options => phantomjs_options,
|
|
|
|
:phantomjs_logger => phantomjs_logger
|
2012-07-11 20:25:17 +01:00
|
|
|
)
|
2012-07-11 20:14:17 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def phantomjs_options
|
|
|
|
list = options[:phantomjs_options] || []
|
|
|
|
list += ["--remote-debugger-port=#{inspector.port}", "--remote-debugger-autorun=yes"] if inspector
|
|
|
|
list
|
2012-02-29 12:32:13 +00:00
|
|
|
end
|
|
|
|
|
2012-02-29 13:51:11 +00:00
|
|
|
def client_pid
|
|
|
|
client.pid
|
|
|
|
end
|
|
|
|
|
2012-02-29 12:32:13 +00:00
|
|
|
def timeout
|
|
|
|
server.timeout
|
|
|
|
end
|
|
|
|
|
|
|
|
def timeout=(sec)
|
|
|
|
server.timeout = sec
|
|
|
|
end
|
|
|
|
|
2011-10-27 23:34:14 +01:00
|
|
|
def restart
|
|
|
|
browser.restart
|
|
|
|
end
|
|
|
|
|
2012-02-29 13:51:11 +00:00
|
|
|
def quit
|
|
|
|
server.stop
|
|
|
|
client.stop
|
|
|
|
end
|
|
|
|
|
2011-10-27 23:34:14 +01:00
|
|
|
# logger should be an object that responds to puts, or nil
|
|
|
|
def logger
|
|
|
|
options[:logger] || (options[:debug] && STDERR)
|
|
|
|
end
|
|
|
|
|
2013-01-07 23:25:32 -05:00
|
|
|
# logger should be an object that behaves like IO or nil
|
|
|
|
def phantomjs_logger
|
|
|
|
options.fetch(:phantomjs_logger, nil)
|
|
|
|
end
|
|
|
|
|
2012-12-04 15:11:27 +01:00
|
|
|
def visit(url)
|
2013-01-28 22:58:34 +00:00
|
|
|
@started = true
|
2012-12-04 15:11:27 +01:00
|
|
|
browser.visit(url)
|
2011-10-27 23:34:14 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def current_url
|
|
|
|
browser.current_url
|
|
|
|
end
|
|
|
|
|
2012-06-04 08:58:27 +03:00
|
|
|
def status_code
|
|
|
|
browser.status_code
|
|
|
|
end
|
|
|
|
|
2012-12-04 15:11:27 +01:00
|
|
|
def html
|
2011-10-27 23:34:14 +01:00
|
|
|
browser.body
|
|
|
|
end
|
2012-12-04 15:11:27 +01:00
|
|
|
alias_method :body, :html
|
2011-10-27 23:34:14 +01:00
|
|
|
|
|
|
|
def source
|
2012-01-10 00:25:30 +00:00
|
|
|
browser.source.to_s
|
2011-10-27 23:34:14 +01:00
|
|
|
end
|
|
|
|
|
2013-03-03 14:21:12 +00:00
|
|
|
def title
|
|
|
|
browser.title
|
|
|
|
end
|
|
|
|
|
2013-03-02 14:05:48 +00:00
|
|
|
def find(method, selector)
|
|
|
|
browser.find(method, selector).map { |page_id, id| Capybara::Poltergeist::Node.new(self, page_id, id) }
|
|
|
|
end
|
|
|
|
|
|
|
|
def find_xpath(selector)
|
|
|
|
find :xpath, selector
|
2011-10-27 23:34:14 +01:00
|
|
|
end
|
|
|
|
|
2013-03-02 14:50:22 +00:00
|
|
|
def find_css(selector)
|
|
|
|
find :css, selector
|
|
|
|
end
|
|
|
|
|
2012-10-08 13:57:31 -07:00
|
|
|
def click(x, y)
|
|
|
|
browser.click_coordinates(x, y)
|
|
|
|
end
|
|
|
|
|
2011-10-27 23:34:14 +01:00
|
|
|
def evaluate_script(script)
|
|
|
|
browser.evaluate(script)
|
|
|
|
end
|
|
|
|
|
|
|
|
def execute_script(script)
|
|
|
|
browser.execute(script)
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
2012-10-07 00:19:52 +01:00
|
|
|
def within_frame(name, &block)
|
|
|
|
browser.within_frame(name, &block)
|
|
|
|
end
|
|
|
|
|
|
|
|
def within_window(name, &block)
|
|
|
|
browser.within_window(name, &block)
|
2011-10-27 23:34:14 +01:00
|
|
|
end
|
|
|
|
|
2013-06-25 14:21:52 -07:00
|
|
|
def window_handles
|
|
|
|
browser.window_handles
|
|
|
|
end
|
|
|
|
|
2011-10-27 23:34:14 +01:00
|
|
|
def reset!
|
|
|
|
browser.reset
|
2013-01-28 22:58:34 +00:00
|
|
|
@started = false
|
2011-10-27 23:34:14 +01:00
|
|
|
end
|
|
|
|
|
2012-12-04 15:11:27 +01:00
|
|
|
def save_screenshot(path, options = {})
|
2011-10-31 23:04:02 +00:00
|
|
|
browser.render(path, options)
|
2011-10-27 23:34:14 +01:00
|
|
|
end
|
2012-12-04 15:11:27 +01:00
|
|
|
alias_method :render, :save_screenshot
|
2011-10-27 23:34:14 +01:00
|
|
|
|
2013-08-25 20:49:32 -07:00
|
|
|
def render_base64(format = :png, options = {})
|
|
|
|
browser.render_base64(format, options)
|
|
|
|
end
|
|
|
|
|
2013-08-30 14:47:43 -04:00
|
|
|
def paper_size=(size = {})
|
|
|
|
browser.set_paper_size(size)
|
|
|
|
end
|
|
|
|
|
2011-10-31 22:23:52 +00:00
|
|
|
def resize(width, height)
|
|
|
|
browser.resize(width, height)
|
|
|
|
end
|
2012-09-22 19:54:48 -07:00
|
|
|
alias_method :resize_window, :resize
|
2011-10-31 22:23:52 +00:00
|
|
|
|
2013-08-01 14:07:37 -04:00
|
|
|
def scroll_to(left, top)
|
|
|
|
browser.scroll_to(left, top)
|
|
|
|
end
|
|
|
|
|
2012-06-14 11:50:26 -07:00
|
|
|
def network_traffic
|
|
|
|
browser.network_traffic
|
2012-06-06 10:57:49 -07:00
|
|
|
end
|
|
|
|
|
2013-07-17 15:53:51 +04:00
|
|
|
def headers
|
|
|
|
browser.get_headers
|
|
|
|
end
|
|
|
|
|
2012-10-06 18:49:22 +01:00
|
|
|
def headers=(headers)
|
|
|
|
browser.set_headers(headers)
|
|
|
|
end
|
|
|
|
|
2013-07-17 15:53:51 +04:00
|
|
|
def add_headers(headers)
|
|
|
|
browser.add_headers(headers)
|
|
|
|
end
|
|
|
|
|
2013-07-25 14:13:07 +04:00
|
|
|
def add_header(name, value, options = {})
|
|
|
|
permanent = options.fetch(:permanent, true)
|
|
|
|
browser.add_header({ name => value }, permanent)
|
|
|
|
end
|
|
|
|
|
2012-10-06 19:27:35 +01:00
|
|
|
def response_headers
|
|
|
|
browser.response_headers
|
|
|
|
end
|
|
|
|
|
2012-10-06 22:56:51 +01:00
|
|
|
def cookies
|
|
|
|
browser.cookies
|
|
|
|
end
|
|
|
|
|
|
|
|
def set_cookie(name, value, options = {})
|
2013-01-28 22:58:34 +00:00
|
|
|
options[:name] ||= name
|
|
|
|
options[:value] ||= value
|
2013-04-22 11:21:03 +04:00
|
|
|
options[:domain] ||= begin
|
|
|
|
if @started
|
2013-08-06 21:12:26 +04:00
|
|
|
URI.parse(browser.current_url).host
|
2013-04-22 11:21:03 +04:00
|
|
|
else
|
|
|
|
Capybara.app_host || "127.0.0.1"
|
|
|
|
end
|
2013-01-28 22:58:34 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
browser.set_cookie(options)
|
2012-10-06 22:56:51 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def remove_cookie(name)
|
|
|
|
browser.remove_cookie(name)
|
|
|
|
end
|
|
|
|
|
2013-04-15 17:02:41 -06:00
|
|
|
def cookies_enabled=(flag)
|
|
|
|
browser.cookies_enabled = flag
|
|
|
|
end
|
|
|
|
|
2013-10-10 15:37:28 +04:00
|
|
|
# * PhantomJS with set settings doesn't send `Authorize` on POST request
|
|
|
|
# * With manually set header PhantomJS makes next request with
|
|
|
|
# `Authorization: Basic Og==` header when settings are empty and the
|
|
|
|
# response was `401 Unauthorized` (which means Base64.encode64(':')).
|
|
|
|
# Combining both methods to reach proper behavior.
|
2013-10-09 23:51:13 +04:00
|
|
|
def basic_authorize(user, password)
|
2013-10-10 15:37:28 +04:00
|
|
|
browser.set_http_auth(user, password)
|
|
|
|
credentials = ["#{user}:#{password}"].pack('m*').strip
|
2013-10-09 23:51:13 +04:00
|
|
|
add_header('Authorization', "Basic #{credentials}")
|
|
|
|
end
|
|
|
|
|
2012-02-29 00:02:43 +00:00
|
|
|
def debug
|
2012-07-24 23:37:07 +03:00
|
|
|
if @options[:inspector]
|
|
|
|
inspector.open
|
|
|
|
pause
|
|
|
|
else
|
|
|
|
raise Error, "To use the remote debugging, you have to launch the driver " \
|
|
|
|
"with `:inspector => true` configuration option"
|
|
|
|
end
|
2012-02-29 00:02:43 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def pause
|
|
|
|
STDERR.puts "Poltergeist execution paused. Press enter to continue."
|
|
|
|
STDIN.gets
|
|
|
|
end
|
|
|
|
|
2011-10-27 23:34:14 +01:00
|
|
|
def wait?
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
def invalid_element_errors
|
2013-03-03 15:18:05 +00:00
|
|
|
[Capybara::Poltergeist::ObsoleteNode, Capybara::Poltergeist::MouseEventFailed]
|
2011-10-27 23:34:14 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|