capybara-webkit 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -1
- data/Gemfile.lock +5 -4
- data/NEWS.md +11 -0
- data/README.md +42 -0
- data/lib/capybara/driver/webkit.rb +7 -2
- data/lib/capybara/driver/webkit/browser.rb +22 -96
- data/lib/capybara/driver/webkit/connection.rb +120 -0
- data/lib/capybara/driver/webkit/version.rb +1 -1
- data/lib/capybara/webkit/matchers.rb +2 -4
- data/lib/capybara_webkit_builder.rb +22 -4
- data/spec/browser_spec.rb +19 -29
- data/spec/connection_spec.rb +54 -0
- data/spec/driver_resize_window_spec.rb +59 -0
- data/spec/driver_spec.rb +175 -27
- data/spec/spec_helper.rb +9 -2
- data/src/Body.h +2 -2
- data/src/ClearCookies.cpp +2 -5
- data/src/ClearCookies.h +2 -2
- data/src/Command.cpp +7 -3
- data/src/Command.h +4 -2
- data/src/CommandFactory.cpp +7 -2
- data/src/CommandFactory.h +1 -1
- data/src/CommandParser.cpp +13 -5
- data/src/CommandParser.h +6 -2
- data/src/Connection.cpp +18 -47
- data/src/Connection.h +5 -7
- data/src/ConsoleMessages.cpp +2 -3
- data/src/ConsoleMessages.h +2 -2
- data/src/CurrentUrl.cpp +3 -6
- data/src/CurrentUrl.h +2 -2
- data/src/Evaluate.cpp +3 -3
- data/src/Evaluate.h +2 -2
- data/src/Execute.cpp +4 -4
- data/src/Execute.h +2 -2
- data/src/Find.cpp +4 -4
- data/src/Find.h +2 -2
- data/src/FrameFocus.cpp +7 -7
- data/src/FrameFocus.h +2 -2
- data/src/GetCookies.cpp +2 -4
- data/src/GetCookies.h +2 -2
- data/src/Header.cpp +4 -4
- data/src/Header.h +2 -2
- data/src/Headers.cpp +2 -3
- data/src/Headers.h +2 -2
- data/src/IgnoreSslErrors.cpp +12 -0
- data/src/IgnoreSslErrors.h +12 -0
- data/src/NetworkAccessManager.cpp +4 -0
- data/src/NetworkAccessManager.h +2 -1
- data/src/Node.cpp +3 -3
- data/src/Node.h +2 -2
- data/src/NullCommand.cpp +10 -0
- data/src/NullCommand.h +11 -0
- data/src/PageLoadingCommand.cpp +46 -0
- data/src/PageLoadingCommand.h +40 -0
- data/src/Render.cpp +5 -6
- data/src/Render.h +2 -2
- data/src/RequestedUrl.cpp +3 -6
- data/src/RequestedUrl.h +2 -2
- data/src/Reset.cpp +8 -7
- data/src/Reset.h +2 -2
- data/src/ResizeWindow.cpp +16 -0
- data/src/ResizeWindow.h +12 -0
- data/src/Response.cpp +6 -1
- data/src/Response.h +4 -2
- data/src/Server.cpp +2 -3
- data/src/Server.h +1 -1
- data/src/SetCookie.cpp +3 -5
- data/src/SetCookie.h +2 -2
- data/src/SetProxy.cpp +7 -9
- data/src/SetProxy.h +2 -2
- data/src/Source.cpp +2 -4
- data/src/Source.h +2 -2
- data/src/Status.cpp +2 -3
- data/src/Status.h +2 -2
- data/src/Url.cpp +3 -6
- data/src/Url.h +2 -2
- data/src/Visit.cpp +4 -13
- data/src/Visit.h +2 -5
- data/src/WebPage.cpp +11 -9
- data/src/WebPage.h +3 -3
- data/src/body.cpp +2 -3
- data/src/capybara.js +58 -3
- data/src/find_command.h +3 -1
- data/src/main.cpp +1 -2
- data/src/webkit_server.pro +8 -0
- metadata +29 -16
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
capybara-webkit (0.
|
4
|
+
capybara-webkit (0.12.0)
|
5
5
|
capybara (>= 1.0.0, < 1.2)
|
6
6
|
json
|
7
7
|
|
@@ -22,8 +22,8 @@ GEM
|
|
22
22
|
ffi (~> 1.0.6)
|
23
23
|
diff-lcs (1.1.2)
|
24
24
|
ffi (1.0.11)
|
25
|
-
json (1.
|
26
|
-
mime-types (1.
|
25
|
+
json (1.7.1)
|
26
|
+
mime-types (1.18)
|
27
27
|
mini_magick (3.2.1)
|
28
28
|
subexec (~> 0.0.4)
|
29
29
|
multi_json (1.0.4)
|
@@ -40,7 +40,7 @@ GEM
|
|
40
40
|
rspec-expectations (2.6.0)
|
41
41
|
diff-lcs (~> 1.1.2)
|
42
42
|
rspec-mocks (2.6.0)
|
43
|
-
rubyzip (0.9.
|
43
|
+
rubyzip (0.9.7)
|
44
44
|
selenium-webdriver (2.19.0)
|
45
45
|
childprocess (>= 0.2.5)
|
46
46
|
ffi (~> 1.0.9)
|
@@ -56,6 +56,7 @@ GEM
|
|
56
56
|
|
57
57
|
PLATFORMS
|
58
58
|
ruby
|
59
|
+
x86-mingw32
|
59
60
|
|
60
61
|
DEPENDENCIES
|
61
62
|
appraisal (~> 0.4.0)
|
data/NEWS.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
New for 0.12.0:
|
2
|
+
* Better windows support
|
3
|
+
* Support for localStorage
|
4
|
+
* Added support for oninput event
|
5
|
+
* Added resize_window method
|
6
|
+
* Server binds on LocalHost to prevent having to add firewall exceptions
|
7
|
+
* Reuse NetworkAccessManager to prevent "too many open files" errors
|
8
|
+
* Response messages are stored as QByteArray to prevent truncating content
|
9
|
+
* Browser no longer tries to read empty responses (Fixes jruby issues).
|
10
|
+
* Server will timeout if it can not start
|
11
|
+
|
1
12
|
New for 0.11.0:
|
2
13
|
|
3
14
|
* Allow interaction with invisible elements
|
data/README.md
CHANGED
@@ -11,6 +11,11 @@ development toolkit. You'll need to download the Qt libraries to build and
|
|
11
11
|
install the gem. You can find instructions for downloading and installing QT on
|
12
12
|
the [capybara-webkit wiki](https://github.com/thoughtbot/capybara-webkit/wiki/Installing-Qt-and-compiling-capybara-webkit)
|
13
13
|
|
14
|
+
Windows Support
|
15
|
+
---------------
|
16
|
+
|
17
|
+
Currently 32bit Windows will compile Capybara-webkit. Support for Windows is provided by the open source community and Windows related issues should be posted to the [mailing list](http://groups.google.com/group/capybara-webkit)
|
18
|
+
|
14
19
|
Reporting Issues
|
15
20
|
----------------
|
16
21
|
|
@@ -50,6 +55,43 @@ In RSpec, use the :js => true flag.
|
|
50
55
|
|
51
56
|
Take note of the transactional fixtures section of the [capybara README](https://github.com/jnicklas/capybara/blob/master/README.md).
|
52
57
|
|
58
|
+
If you're using capybara-webkit with Sinatra, don't forget to set
|
59
|
+
|
60
|
+
Capybara.app = MySinatraApp.new
|
61
|
+
|
62
|
+
Non-Standard Driver Methods
|
63
|
+
---------------------------
|
64
|
+
|
65
|
+
capybara-webkit supports a few methods that are not part of the standard capybara API. You can access these by calling `driver` on the capybara session. When using the DSL, that will look like `page.driver.method_name`.
|
66
|
+
|
67
|
+
**console_messages**: returns an array of messages printed using console.log
|
68
|
+
|
69
|
+
# In Javascript:
|
70
|
+
console.log("hello")
|
71
|
+
# In Ruby:
|
72
|
+
page.driver.console_messages
|
73
|
+
=> {:source=>"http://example.com", :line_number=>1, :message=>"hello"}
|
74
|
+
|
75
|
+
**error_messages**: returns an array of Javascript errors that occurred
|
76
|
+
|
77
|
+
page.driver.error_messages
|
78
|
+
=> {:source=>"http://example.com", :line_number=>1, :message=>"SyntaxError: Parse error"}
|
79
|
+
|
80
|
+
**resize_window**: change the viewport size to the given width and height
|
81
|
+
|
82
|
+
page.driver.resize_window(500, 300)
|
83
|
+
page.driver.evaluate_script("window.innerWidth")
|
84
|
+
=> 500
|
85
|
+
|
86
|
+
**render**: render a screenshot of the current view (requires [mini_magick](https://github.com/probablycorey/mini_magick) and [ImageMagick](http://www.imagemagick.org))
|
87
|
+
|
88
|
+
page.driver.render "tmp/screenshot.png"
|
89
|
+
|
90
|
+
**cookies**: allows read-only access of cookies for the current session
|
91
|
+
|
92
|
+
page.driver.cookies["alpha"]
|
93
|
+
=> "abc"
|
94
|
+
|
53
95
|
Contributing
|
54
96
|
------------
|
55
97
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "capybara"
|
2
2
|
require "capybara/driver/webkit/version"
|
3
3
|
require "capybara/driver/webkit/node"
|
4
|
+
require "capybara/driver/webkit/connection"
|
4
5
|
require "capybara/driver/webkit/browser"
|
5
6
|
require "capybara/driver/webkit/socket_debugger"
|
6
7
|
require "capybara/driver/webkit/cookie_jar"
|
@@ -22,8 +23,8 @@ class Capybara::Driver::Webkit
|
|
22
23
|
@options = options
|
23
24
|
@rack_server = Capybara::Server.new(@app)
|
24
25
|
@rack_server.boot if Capybara.run_server
|
25
|
-
@browser = options[:browser] || Browser.new(
|
26
|
-
|
26
|
+
@browser = options[:browser] || Browser.new(Connection.new(options))
|
27
|
+
@browser.ignore_ssl_errors if options[:ignore_ssl_errors]
|
27
28
|
end
|
28
29
|
|
29
30
|
def current_url
|
@@ -79,6 +80,10 @@ class Capybara::Driver::Webkit
|
|
79
80
|
browser.status_code
|
80
81
|
end
|
81
82
|
|
83
|
+
def resize_window(width, height)
|
84
|
+
browser.resize_window(width, height)
|
85
|
+
end
|
86
|
+
|
82
87
|
def within_frame(frame_id_or_index)
|
83
88
|
browser.frame_focus(frame_id_or_index)
|
84
89
|
begin
|
@@ -1,20 +1,9 @@
|
|
1
|
-
require 'socket'
|
2
|
-
require 'thread'
|
3
|
-
require 'timeout'
|
4
1
|
require 'json'
|
5
2
|
|
6
3
|
class Capybara::Driver::Webkit
|
7
4
|
class Browser
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(options = {})
|
11
|
-
@socket_class = options[:socket_class] || TCPSocket
|
12
|
-
@stdout = options.has_key?(:stdout) ?
|
13
|
-
options[:stdout] :
|
14
|
-
$stdout
|
15
|
-
@ignore_ssl_errors = options[:ignore_ssl_errors]
|
16
|
-
start_server
|
17
|
-
connect
|
5
|
+
def initialize(connection)
|
6
|
+
@connection = connection
|
18
7
|
end
|
19
8
|
|
20
9
|
def visit(url)
|
@@ -84,12 +73,16 @@ class Capybara::Driver::Webkit
|
|
84
73
|
end
|
85
74
|
end
|
86
75
|
|
76
|
+
def ignore_ssl_errors
|
77
|
+
command("IgnoreSslErrors")
|
78
|
+
end
|
79
|
+
|
87
80
|
def command(name, *args)
|
88
|
-
@
|
89
|
-
@
|
81
|
+
@connection.puts name
|
82
|
+
@connection.puts args.size
|
90
83
|
args.each do |arg|
|
91
|
-
@
|
92
|
-
@
|
84
|
+
@connection.puts arg.to_s.bytesize
|
85
|
+
@connection.print arg.to_s
|
93
86
|
end
|
94
87
|
check
|
95
88
|
read_response
|
@@ -129,85 +122,14 @@ class Capybara::Driver::Webkit
|
|
129
122
|
command("SetProxy")
|
130
123
|
end
|
131
124
|
|
132
|
-
|
133
|
-
|
134
|
-
def start_server
|
135
|
-
pipe = fork_server
|
136
|
-
@server_port = discover_server_port(pipe)
|
137
|
-
@stdout_thread = Thread.new do
|
138
|
-
Thread.current.abort_on_exception = true
|
139
|
-
forward_stdout(pipe)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def fork_server
|
144
|
-
server_path = File.expand_path("../../../../../bin/webkit_server", __FILE__)
|
145
|
-
pipe, @pid = server_pipe_and_pid(server_path)
|
146
|
-
register_shutdown_hook
|
147
|
-
pipe
|
148
|
-
end
|
149
|
-
|
150
|
-
def register_shutdown_hook
|
151
|
-
@owner_pid = Process.pid
|
152
|
-
at_exit do
|
153
|
-
if Process.pid == @owner_pid
|
154
|
-
Process.kill("INT", @pid)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
def server_pipe_and_pid(server_path)
|
160
|
-
cmdline = [server_path]
|
161
|
-
cmdline << "--ignore-ssl-errors" if @ignore_ssl_errors
|
162
|
-
pipe = IO.popen(cmdline.join(" "))
|
163
|
-
[pipe, pipe.pid]
|
164
|
-
end
|
165
|
-
|
166
|
-
def discover_server_port(read_pipe)
|
167
|
-
return unless IO.select([read_pipe], nil, nil, 10)
|
168
|
-
((read_pipe.first || '').match(/listening on port: (\d+)/) || [])[1].to_i
|
125
|
+
def resize_window(width, height)
|
126
|
+
command("ResizeWindow", width.to_i, height.to_i)
|
169
127
|
end
|
170
128
|
|
171
|
-
|
172
|
-
while pipe_readable?(pipe)
|
173
|
-
line = pipe.readline
|
174
|
-
if @stdout
|
175
|
-
@stdout.write(line)
|
176
|
-
@stdout.flush
|
177
|
-
end
|
178
|
-
end
|
179
|
-
rescue EOFError
|
180
|
-
end
|
181
|
-
|
182
|
-
if !defined?(RUBY_ENGINE) || (RUBY_ENGINE == "ruby" && RUBY_VERSION <= "1.8")
|
183
|
-
# please note the use of IO::select() here, as it is used specifically to
|
184
|
-
# preserve correct signal handling behavior in ruby 1.8.
|
185
|
-
# https://github.com/thibaudgg/rb-fsevent/commit/d1a868bf8dc72dbca102bedbadff76c7e6c2dc21
|
186
|
-
# https://github.com/thibaudgg/rb-fsevent/blob/1ca42b987596f350ee7b19d8f8210b7b6ae8766b/ext/fsevent/fsevent_watch.c#L171
|
187
|
-
def pipe_readable?(pipe)
|
188
|
-
IO.select([pipe])
|
189
|
-
end
|
190
|
-
else
|
191
|
-
def pipe_readable?(pipe)
|
192
|
-
!pipe.eof?
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
def connect
|
197
|
-
Timeout.timeout(5) do
|
198
|
-
while @socket.nil?
|
199
|
-
attempt_connect
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
def attempt_connect
|
205
|
-
@socket = @socket_class.open("127.0.0.1", @server_port)
|
206
|
-
rescue Errno::ECONNREFUSED
|
207
|
-
end
|
129
|
+
private
|
208
130
|
|
209
131
|
def check
|
210
|
-
result = @
|
132
|
+
result = @connection.gets
|
211
133
|
result.strip! if result
|
212
134
|
|
213
135
|
if result.nil?
|
@@ -220,10 +142,14 @@ class Capybara::Driver::Webkit
|
|
220
142
|
end
|
221
143
|
|
222
144
|
def read_response
|
223
|
-
response_length = @
|
224
|
-
|
225
|
-
|
226
|
-
|
145
|
+
response_length = @connection.gets.to_i
|
146
|
+
if response_length > 0
|
147
|
+
response = @connection.read(response_length)
|
148
|
+
response.force_encoding("UTF-8") if response.respond_to?(:force_encoding)
|
149
|
+
response
|
150
|
+
else
|
151
|
+
""
|
152
|
+
end
|
227
153
|
end
|
228
154
|
|
229
155
|
def default_proxy_options
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'timeout'
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
class Capybara::Driver::Webkit
|
6
|
+
class Connection
|
7
|
+
WEBKIT_SERVER_START_TIMEOUT = 15
|
8
|
+
|
9
|
+
attr_reader :port
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
@socket_class = options[:socket_class] || TCPSocket
|
13
|
+
@stdout = options.has_key?(:stdout) ?
|
14
|
+
options[:stdout] :
|
15
|
+
$stdout
|
16
|
+
start_server
|
17
|
+
connect
|
18
|
+
end
|
19
|
+
|
20
|
+
def puts(string)
|
21
|
+
@socket.puts string
|
22
|
+
end
|
23
|
+
|
24
|
+
def print(string)
|
25
|
+
@socket.print string
|
26
|
+
end
|
27
|
+
|
28
|
+
def gets
|
29
|
+
@socket.gets
|
30
|
+
end
|
31
|
+
|
32
|
+
def read(length)
|
33
|
+
@socket.read(length)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def start_server
|
39
|
+
pipe = fork_server
|
40
|
+
@port = discover_port(pipe)
|
41
|
+
@stdout_thread = Thread.new do
|
42
|
+
Thread.current.abort_on_exception = true
|
43
|
+
forward_stdout(pipe)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def fork_server
|
48
|
+
server_path = File.expand_path("../../../../../bin/webkit_server", __FILE__)
|
49
|
+
pipe, @pid = server_pipe_and_pid(server_path)
|
50
|
+
register_shutdown_hook
|
51
|
+
pipe
|
52
|
+
end
|
53
|
+
|
54
|
+
def kill_process(pid)
|
55
|
+
if RUBY_PLATFORM =~ /mingw32/
|
56
|
+
Process.kill(9, pid)
|
57
|
+
else
|
58
|
+
Process.kill("INT", pid)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def register_shutdown_hook
|
63
|
+
@owner_pid = Process.pid
|
64
|
+
at_exit do
|
65
|
+
if Process.pid == @owner_pid
|
66
|
+
kill_process(@pid)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def server_pipe_and_pid(server_path)
|
72
|
+
cmdline = [server_path]
|
73
|
+
pipe = IO.popen(cmdline.join(" "))
|
74
|
+
[pipe, pipe.pid]
|
75
|
+
end
|
76
|
+
|
77
|
+
def discover_port(read_pipe)
|
78
|
+
return unless IO.select([read_pipe], nil, nil, WEBKIT_SERVER_START_TIMEOUT)
|
79
|
+
((read_pipe.first || '').match(/listening on port: (\d+)/) || [])[1].to_i
|
80
|
+
end
|
81
|
+
|
82
|
+
def forward_stdout(pipe)
|
83
|
+
while pipe_readable?(pipe)
|
84
|
+
line = pipe.readline
|
85
|
+
if @stdout
|
86
|
+
@stdout.write(line)
|
87
|
+
@stdout.flush
|
88
|
+
end
|
89
|
+
end
|
90
|
+
rescue EOFError
|
91
|
+
end
|
92
|
+
|
93
|
+
def connect
|
94
|
+
Timeout.timeout(5) do
|
95
|
+
while @socket.nil?
|
96
|
+
attempt_connect
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def attempt_connect
|
102
|
+
@socket = @socket_class.open("127.0.0.1", @port)
|
103
|
+
rescue Errno::ECONNREFUSED
|
104
|
+
end
|
105
|
+
|
106
|
+
if !defined?(RUBY_ENGINE) || (RUBY_ENGINE == "ruby" && RUBY_VERSION <= "1.8")
|
107
|
+
# please note the use of IO::select() here, as it is used specifically to
|
108
|
+
# preserve correct signal handling behavior in ruby 1.8.
|
109
|
+
# https://github.com/thibaudgg/rb-fsevent/commit/d1a868bf8dc72dbca102bedbadff76c7e6c2dc21
|
110
|
+
# https://github.com/thibaudgg/rb-fsevent/blob/1ca42b987596f350ee7b19d8f8210b7b6ae8766b/ext/fsevent/fsevent_watch.c#L171
|
111
|
+
def pipe_readable?(pipe)
|
112
|
+
IO.select([pipe])
|
113
|
+
end
|
114
|
+
else
|
115
|
+
def pipe_readable?(pipe)
|
116
|
+
!pipe.eof?
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -1,9 +1,7 @@
|
|
1
1
|
module Capybara
|
2
2
|
module Webkit
|
3
3
|
module RspecMatchers
|
4
|
-
|
5
|
-
|
6
|
-
matcher :have_errors do |expected|
|
4
|
+
RSpec::Matchers.define :have_errors do |expected|
|
7
5
|
match do |actual|
|
8
6
|
actual = resolve(actual)
|
9
7
|
actual.error_messages.any?
|
@@ -12,6 +10,7 @@ module Capybara
|
|
12
10
|
failure_message_for_should do |actual|
|
13
11
|
"Expected Javascript errors, but there were none."
|
14
12
|
end
|
13
|
+
|
15
14
|
failure_message_for_should_not do |actual|
|
16
15
|
actual = resolve(actual)
|
17
16
|
"Expected no Javascript errors, got:\n#{error_messages_for(actual)}"
|
@@ -33,7 +32,6 @@ module Capybara
|
|
33
32
|
end
|
34
33
|
end
|
35
34
|
end
|
36
|
-
|
37
35
|
end
|
38
36
|
end
|
39
37
|
end
|