1
0
Fork 0
mirror of https://github.com/thoughtbot/capybara-webkit synced 2023-03-27 23:22:28 -04:00
capybara-webkit/lib/capybara/driver/webkit/browser.rb

247 lines
5.5 KiB
Ruby
Raw Normal View History

2011-02-18 22:53:06 -05:00
require 'socket'
require 'thread'
require 'timeout'
2011-02-26 13:02:43 -05:00
require 'json'
2011-02-18 22:53:06 -05:00
class Capybara::Driver::Webkit
class Browser
attr :server_port
def initialize(options = {})
@socket_class = options[:socket_class] || TCPSocket
@stdout = options.has_key?(:stdout) ?
options[:stdout] :
$stdout
@ignore_ssl_errors = options[:ignore_ssl_errors]
2011-02-18 22:53:06 -05:00
start_server
connect
end
def visit(url)
command "Visit", url
2011-02-18 22:53:06 -05:00
end
2011-06-08 05:36:45 -04:00
def header(key, value)
command("Header", key, value)
end
2011-02-18 22:53:06 -05:00
def find(query)
command("Find", query).split(",")
2011-02-18 22:53:06 -05:00
end
def reset!
command("Reset")
2011-02-18 22:53:06 -05:00
end
def body
command("Body")
end
2011-02-25 18:04:23 -05:00
def source
command("Source")
end
2011-08-12 16:50:43 -04:00
def status_code
command("Status").to_i
end
def console_messages
command("ConsoleMessages").split("\n").map do |messages|
parts = messages.split("|", 3)
{ :source => parts.first, :line_number => Integer(parts[1]), :message => parts.last }
end
end
def error_messages
console_messages.select do |message|
message[:message] =~ /Error:/
end
end
2011-08-19 11:57:39 -04:00
def response_headers
Hash[command("Headers").split("\n").map { |header| header.split(": ") }]
end
2011-02-25 17:53:36 -05:00
def url
command("Url")
end
def requested_url
command("RequestedUrl")
end
2012-02-05 11:43:48 -05:00
def current_url
command("CurrentUrl")
end
def frame_focus(frame_id_or_index=nil)
if frame_id_or_index.is_a? Fixnum
command("FrameFocus", "", frame_id_or_index.to_s)
elsif frame_id_or_index
command("FrameFocus", frame_id_or_index)
else
command("FrameFocus")
end
end
2011-02-25 00:15:08 -05:00
def command(name, *args)
@socket.puts name
@socket.puts args.size
args.each do |arg|
2011-02-26 17:02:00 -05:00
@socket.puts arg.to_s.bytesize
@socket.print arg.to_s
end
2011-02-25 00:15:08 -05:00
check
read_response
end
2011-02-26 13:02:43 -05:00
def evaluate_script(script)
json = command('Evaluate', script)
JSON.parse("[#{json}]").first
end
2011-02-26 14:03:30 -05:00
def execute_script(script)
command('Execute', script)
end
def render(path, width, height)
command "Render", path, width, height
end
def set_cookie(cookie)
command "SetCookie", cookie
end
def clear_cookies
command "ClearCookies"
end
def get_cookies
2011-09-30 11:41:59 -04:00
command("GetCookies").lines.map{ |line| line.strip }.select{ |line| !line.empty? }
end
2011-10-14 17:13:06 -04:00
def set_proxy(options = {})
options = default_proxy_options.merge(options)
command("SetProxy", options[:host], options[:port], options[:user], options[:pass])
end
2011-09-24 17:55:18 -04:00
2011-10-14 17:13:06 -04:00
def clear_proxy
command("SetProxy")
2011-09-24 17:55:18 -04:00
end
2011-02-18 22:53:06 -05:00
private
def start_server
pipe = fork_server
@server_port = discover_server_port(pipe)
@stdout_thread = Thread.new do
Thread.current.abort_on_exception = true
forward_stdout(pipe)
end
end
def fork_server
2011-02-26 18:28:42 -05:00
server_path = File.expand_path("../../../../../bin/webkit_server", __FILE__)
2011-08-19 09:07:05 -04:00
pipe, @pid = server_pipe_and_pid(server_path)
register_shutdown_hook
pipe
end
2011-10-06 11:07:20 -04:00
def kill_process(pid)
if RUBY_PLATFORM =~ /mingw32/
Process.kill(9, pid)
else
Process.kill("INT", pid)
end
end
def register_shutdown_hook
@owner_pid = Process.pid
at_exit do
if Process.pid == @owner_pid
2011-10-06 11:07:20 -04:00
kill_process(@pid)
end
end
end
2011-08-19 09:07:05 -04:00
def server_pipe_and_pid(server_path)
cmdline = [server_path]
cmdline << "--ignore-ssl-errors" if @ignore_ssl_errors
pipe = IO.popen(cmdline.join(" "))
[pipe, pipe.pid]
end
def discover_server_port(read_pipe)
return unless IO.select([read_pipe], nil, nil, 10)
((read_pipe.first || '').match(/listening on port: (\d+)/) || [])[1].to_i
2011-02-18 22:53:06 -05:00
end
2011-08-19 09:07:05 -04:00
def forward_stdout(pipe)
while pipe_readable?(pipe)
line = pipe.readline
if @stdout
@stdout.write(line)
@stdout.flush
end
end
rescue EOFError
end
2011-02-18 22:53:06 -05:00
if !defined?(RUBY_ENGINE) || (RUBY_ENGINE == "ruby" && RUBY_VERSION <= "1.8")
# please note the use of IO::select() here, as it is used specifically to
# preserve correct signal handling behavior in ruby 1.8.
# https://github.com/thibaudgg/rb-fsevent/commit/d1a868bf8dc72dbca102bedbadff76c7e6c2dc21
# https://github.com/thibaudgg/rb-fsevent/blob/1ca42b987596f350ee7b19d8f8210b7b6ae8766b/ext/fsevent/fsevent_watch.c#L171
def pipe_readable?(pipe)
IO.select([pipe])
end
else
def pipe_readable?(pipe)
!pipe.eof?
end
end
2011-02-18 22:53:06 -05:00
def connect
Timeout.timeout(5) do
while @socket.nil?
attempt_connect
end
2011-02-18 22:53:06 -05:00
end
end
def attempt_connect
2011-10-07 11:19:25 -04:00
@socket = @socket_class.open("127.0.0.1", @server_port)
2011-02-18 22:53:06 -05:00
rescue Errno::ECONNREFUSED
end
def check
result = @socket.gets
result.strip! if result
2011-02-25 17:44:16 -05:00
if result.nil?
raise WebkitNoResponseError, "No response received from the server."
elsif result != 'ok'
raise WebkitInvalidResponseError, read_response
2011-02-18 22:53:06 -05:00
end
result
2011-02-18 22:53:06 -05:00
end
def read_response
response_length = @socket.gets.to_i
2011-06-14 10:44:17 -04:00
response = @socket.read(response_length)
2011-06-14 10:45:05 -04:00
response.force_encoding("UTF-8") if response.respond_to?(:force_encoding)
2011-06-14 10:44:17 -04:00
response
2011-02-18 22:53:06 -05:00
end
2011-10-14 17:13:06 -04:00
def default_proxy_options
{
:host => "localhost",
:port => "0",
:user => "",
:pass => ""
}
end
2011-02-18 22:53:06 -05:00
end
end