2011-02-18 22:53:06 -05:00
|
|
|
require 'socket'
|
2011-08-15 12:17:14 -04:00
|
|
|
require 'thread'
|
2011-02-25 23:47:55 -05:00
|
|
|
require 'capybara/util/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
|
2011-07-06 08:30:52 -04:00
|
|
|
attr :server_port
|
|
|
|
|
2011-03-11 11:19:59 -05:00
|
|
|
def initialize(options = {})
|
|
|
|
@socket_class = options[:socket_class] || TCPSocket
|
2011-08-15 12:17:14 -04:00
|
|
|
@stdout = options.has_key?(:stdout) ?
|
|
|
|
options[:stdout] :
|
|
|
|
$stdout
|
2011-02-18 22:53:06 -05:00
|
|
|
start_server
|
|
|
|
connect
|
|
|
|
end
|
|
|
|
|
|
|
|
def visit(url)
|
2011-02-24 23:48:18 -05:00
|
|
|
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)
|
2011-02-24 23:48:18 -05:00
|
|
|
command("Find", query).split(",")
|
2011-02-18 22:53:06 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def reset!
|
2011-02-24 23:48:18 -05:00
|
|
|
command("Reset")
|
2011-02-18 22:53:06 -05:00
|
|
|
end
|
|
|
|
|
2011-07-29 15:00:13 -04:00
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
2011-04-20 01:42:20 -04:00
|
|
|
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
|
2011-04-19 03:16:25 -04:00
|
|
|
end
|
|
|
|
|
2011-02-25 00:15:08 -05:00
|
|
|
def command(name, *args)
|
|
|
|
@socket.puts name
|
2011-02-26 13:38:10 -05:00
|
|
|
@socket.puts args.size
|
|
|
|
args.each do |arg|
|
2011-02-26 17:02:00 -05:00
|
|
|
@socket.puts arg.to_s.bytesize
|
2011-06-25 16:35:18 -04:00
|
|
|
@socket.print arg.to_s
|
2011-02-26 13:38:10 -05:00
|
|
|
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
|
|
|
|
|
2011-05-26 15:05:16 -04:00
|
|
|
def render(path, width, height)
|
|
|
|
command "Render", path, width, height
|
|
|
|
end
|
|
|
|
|
2011-02-18 22:53:06 -05:00
|
|
|
private
|
|
|
|
|
|
|
|
def start_server
|
2011-08-18 20:54:54 -04:00
|
|
|
pipe = fork_server
|
|
|
|
@server_port = discover_server_port(pipe)
|
2011-08-15 12:17:14 -04:00
|
|
|
@stdout_thread = Thread.new do
|
|
|
|
Thread.current.abort_on_exception = true
|
2011-08-18 20:54:54 -04:00
|
|
|
forward_stdout(pipe)
|
2011-08-15 12:17:14 -04:00
|
|
|
end
|
2011-07-05 08:54:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def fork_server
|
2011-02-26 18:28:42 -05:00
|
|
|
server_path = File.expand_path("../../../../../bin/webkit_server", __FILE__)
|
2011-05-30 00:59:16 -04:00
|
|
|
|
2011-08-19 09:07:05 -04:00
|
|
|
pipe, @pid = server_pipe_and_pid(server_path)
|
|
|
|
|
2011-02-18 22:53:06 -05:00
|
|
|
at_exit { Process.kill("INT", @pid) }
|
2011-05-30 01:08:57 -04:00
|
|
|
|
2011-08-18 20:54:54 -04:00
|
|
|
pipe
|
2011-07-05 08:54:49 -04:00
|
|
|
end
|
|
|
|
|
2011-08-19 09:07:05 -04:00
|
|
|
def server_pipe_and_pid(server_path)
|
|
|
|
pipe = IO.popen(server_path)
|
2011-08-19 18:56:01 -04:00
|
|
|
[pipe, pipe.pid]
|
2011-07-05 08:54:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def discover_server_port(read_pipe)
|
2011-05-30 01:08:57 -04:00
|
|
|
return unless IO.select([read_pipe], nil, nil, 10)
|
2011-07-06 08:30:52 -04:00
|
|
|
((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
|
|
|
|
2011-08-15 12:17:14 -04:00
|
|
|
def forward_stdout(pipe)
|
2011-08-22 03:32:08 -04:00
|
|
|
while pipe_readable?(pipe)
|
2011-08-15 12:17:14 -04:00
|
|
|
line = pipe.readline
|
|
|
|
if @stdout
|
|
|
|
@stdout.write(line)
|
|
|
|
@stdout.flush
|
|
|
|
end
|
|
|
|
end
|
|
|
|
rescue EOFError
|
|
|
|
end
|
2011-02-18 22:53:06 -05:00
|
|
|
|
2011-08-22 03:32:08 -04: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
|
|
|
|
Capybara.timeout(5) do
|
|
|
|
attempt_connect
|
|
|
|
!@socket.nil?
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def attempt_connect
|
2011-05-30 00:59:16 -04:00
|
|
|
@socket = @socket_class.open("localhost", @server_port)
|
2011-02-18 22:53:06 -05:00
|
|
|
rescue Errno::ECONNREFUSED
|
|
|
|
end
|
|
|
|
|
|
|
|
def check
|
2011-07-12 15:31:10 -04:00
|
|
|
result = @socket.gets
|
|
|
|
result.strip! if result
|
2011-02-25 17:44:16 -05:00
|
|
|
|
2011-07-12 15:31:10 -04: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
|
2011-07-12 15:31:10 -04:00
|
|
|
|
|
|
|
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
|
|
|
|
end
|
|
|
|
end
|