forked from thoughtbot/capybara-webkit
/
browser.rb
136 lines (110 loc) · 2.8 KB
/
browser.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
require 'socket'
require 'capybara/util/timeout'
require 'json'
class Capybara::Driver::Webkit
class Browser
attr :server_port
def initialize(options = {})
@socket_class = options[:socket_class] || TCPSocket
start_server
connect
end
def visit(url)
command "Visit", url
end
def header(key, value)
command("Header", key, value)
end
def find(query)
command("Find", query).split(",")
end
def reset!
command("Reset")
end
def body
command("Body")
end
def source
command("Source")
end
def url
command("Url")
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
def command(name, *args)
@socket.puts name
@socket.puts args.size
args.each do |arg|
@socket.puts arg.to_s.bytesize
@socket.print arg.to_s
end
check
read_response
end
def evaluate_script(script)
json = command('Evaluate', script)
JSON.parse("[#{json}]").first
end
def execute_script(script)
command('Execute', script)
end
def render(path, width, height)
command "Render", path, width, height
end
private
def start_server
read_pipe, write_pipe = fork_server
@server_port = discover_server_port(read_pipe)
end
def fork_server
server_path = File.expand_path("../../../../../bin/webkit_server", __FILE__)
read_pipe, write_pipe = IO.pipe
@pid = fork do
$stdout.reopen write_pipe
read_pipe.close
exec(server_path)
end
at_exit { Process.kill("INT", @pid) }
write_pipe.close
[read_pipe, write_pipe]
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
end
def connect
Capybara.timeout(5) do
attempt_connect
!@socket.nil?
end
end
def attempt_connect
@socket = @socket_class.open("localhost", @server_port)
rescue Errno::ECONNREFUSED
end
def check
result = @socket.gets
result.strip! if result
if result.nil?
raise WebkitNoResponseError, "No response received from the server."
elsif result != 'ok'
raise WebkitInvalidResponseError, read_response
end
result
end
def read_response
response_length = @socket.gets.to_i
response = @socket.read(response_length)
response.force_encoding("UTF-8") if response.respond_to?(:force_encoding)
response
end
end
end