capybara-webkit 0.5.0 → 0.6.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 -0
- data/CONTRIBUTING.md +38 -0
- data/Gemfile +3 -2
- data/Gemfile.lock +28 -28
- data/README.md +39 -4
- data/capybara-webkit.gemspec +2 -2
- data/lib/capybara-webkit.rb +4 -0
- data/lib/capybara/driver/webkit.rb +23 -3
- data/lib/capybara/driver/webkit/browser.rb +44 -6
- data/lib/capybara/driver/webkit/node.rb +15 -4
- data/lib/capybara/driver/webkit/socket_debugger.rb +43 -0
- data/lib/capybara_webkit_builder.rb +9 -2
- data/spec/browser_spec.rb +26 -0
- data/spec/driver_rendering_spec.rb +80 -0
- data/spec/driver_spec.rb +186 -15
- data/spec/integration/driver_spec.rb +4 -0
- data/spec/integration/session_spec.rb +2 -2
- data/src/Body.h +12 -0
- data/src/Connection.cpp +5 -2
- data/src/Header.cpp +18 -0
- data/src/Header.h +11 -0
- data/src/NetworkAccessManager.cpp +22 -0
- data/src/NetworkAccessManager.h +18 -0
- data/src/Render.cpp +19 -0
- data/src/Render.h +12 -0
- data/src/Reset.cpp +3 -0
- data/src/Server.cpp +5 -2
- data/src/Server.h +1 -0
- data/src/Source.cpp +9 -2
- data/src/Source.h +7 -0
- data/src/WebPage.cpp +79 -5
- data/src/WebPage.h +9 -0
- data/src/body.cpp +11 -0
- data/src/capybara.js +19 -4
- data/src/find_command.h +3 -0
- data/src/main.cpp +2 -1
- data/src/webkit_server.pro +2 -2
- metadata +34 -9
- data/spec/support/socket_debugger.rb +0 -42
data/.gitignore
CHANGED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
We love pull requests. Here's a quick guide:
|
2
|
+
|
3
|
+
1. Fork the repo.
|
4
|
+
|
5
|
+
2. Run the tests. We only take pull requests with passing tests, and it's great
|
6
|
+
to know that you have a clean slate: `bundle && rake`
|
7
|
+
|
8
|
+
3. Add a test for your change. Only refactoring and documentation changes
|
9
|
+
require no new tests. If you are adding functionality or fixing a bug, we need
|
10
|
+
a test!
|
11
|
+
|
12
|
+
4. Make the test pass.
|
13
|
+
|
14
|
+
5. Push to your fork and submit a pull request.
|
15
|
+
|
16
|
+
|
17
|
+
At this point you're waiting on us. We like to at least comment on, if not
|
18
|
+
accept, pull requests within three business days (and, typically, one business
|
19
|
+
day). We may suggest some changes or improvements or alternatives.
|
20
|
+
|
21
|
+
Some things that will increase the chance that your pull request is accepted,
|
22
|
+
taken straight from the Ruby on Rails guide:
|
23
|
+
|
24
|
+
* Use Rails idioms and helpers
|
25
|
+
* Include tests that fail without your code, and pass with it
|
26
|
+
* Update the documentation, the surrounding one, examples elsewhere, guides,
|
27
|
+
whatever is affected by your contribution
|
28
|
+
|
29
|
+
Syntax:
|
30
|
+
|
31
|
+
* Two spaces, no tabs.
|
32
|
+
* No trailing whitespace. Blank lines should not have any space.
|
33
|
+
* Prefer &&/|| over and/or.
|
34
|
+
* MyClass.my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
|
35
|
+
* a = b and not a=b.
|
36
|
+
* Follow the conventions you see used in the source already.
|
37
|
+
|
38
|
+
And in case we didn't emphasize it enough: we love tests!
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,48 +1,46 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
capybara (0.
|
5
|
-
celerity (>= 0.7.9)
|
6
|
-
culerity (>= 0.2.4)
|
4
|
+
capybara (1.0.0)
|
7
5
|
mime-types (>= 1.16)
|
8
6
|
nokogiri (>= 1.3.3)
|
9
7
|
rack (>= 1.0.0)
|
10
8
|
rack-test (>= 0.5.4)
|
11
|
-
selenium-webdriver (
|
12
|
-
xpath (~> 0.1.
|
13
|
-
|
14
|
-
|
15
|
-
ffi (~> 0.6.3)
|
16
|
-
culerity (0.2.15)
|
9
|
+
selenium-webdriver (~> 0.2.0)
|
10
|
+
xpath (~> 0.1.4)
|
11
|
+
childprocess (0.1.9)
|
12
|
+
ffi (~> 1.0.6)
|
17
13
|
diff-lcs (1.1.2)
|
18
|
-
ffi (0.
|
19
|
-
|
20
|
-
json_pure (1.5.1)
|
14
|
+
ffi (1.0.9)
|
15
|
+
json_pure (1.5.3)
|
21
16
|
mime-types (1.16)
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
mini_magick (3.2.1)
|
18
|
+
subexec (~> 0.0.4)
|
19
|
+
nokogiri (1.5.0)
|
20
|
+
rack (1.3.0)
|
21
|
+
rack-test (0.6.0)
|
25
22
|
rack (>= 1.0)
|
26
|
-
rake (0.
|
27
|
-
rspec (2.
|
28
|
-
rspec-core (~> 2.
|
29
|
-
rspec-expectations (~> 2.
|
30
|
-
rspec-mocks (~> 2.
|
31
|
-
rspec-core (2.
|
32
|
-
rspec-expectations (2.
|
23
|
+
rake (0.9.2)
|
24
|
+
rspec (2.6.0)
|
25
|
+
rspec-core (~> 2.6.0)
|
26
|
+
rspec-expectations (~> 2.6.0)
|
27
|
+
rspec-mocks (~> 2.6.0)
|
28
|
+
rspec-core (2.6.4)
|
29
|
+
rspec-expectations (2.6.0)
|
33
30
|
diff-lcs (~> 1.1.2)
|
34
|
-
rspec-mocks (2.
|
31
|
+
rspec-mocks (2.6.0)
|
35
32
|
rubyzip (0.9.4)
|
36
|
-
selenium-webdriver (0.
|
37
|
-
childprocess (
|
38
|
-
ffi (
|
33
|
+
selenium-webdriver (0.2.2)
|
34
|
+
childprocess (>= 0.1.9)
|
35
|
+
ffi (>= 1.0.7)
|
39
36
|
json_pure
|
40
37
|
rubyzip
|
41
38
|
sinatra (1.1.2)
|
42
39
|
rack (~> 1.1)
|
43
40
|
tilt (~> 1.2)
|
41
|
+
subexec (0.0.4)
|
44
42
|
tilt (1.2.2)
|
45
|
-
xpath (0.1.
|
43
|
+
xpath (0.1.4)
|
46
44
|
nokogiri (~> 1.3)
|
47
45
|
|
48
46
|
PLATFORMS
|
@@ -50,5 +48,7 @@ PLATFORMS
|
|
50
48
|
|
51
49
|
DEPENDENCIES
|
52
50
|
capybara
|
53
|
-
|
51
|
+
mini_magick
|
52
|
+
rake
|
53
|
+
rspec (~> 2.6.0)
|
54
54
|
sinatra
|
data/README.md
CHANGED
@@ -3,14 +3,36 @@ capybara-webkit
|
|
3
3
|
|
4
4
|
A [capybara](https://github.com/jnicklas/capybara) driver that uses [WebKit](http://webkit.org) via [QtWebKit](http://doc.qt.nokia.com/4.7/qtwebkit.html).
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
Dependent on Qt
|
7
|
+
---------------
|
8
8
|
|
9
9
|
capybara-webkit depends on a WebKit implementation from Qt, a cross-platform development toolkit. You'll need to download the Qt libraries to build and install the gem.
|
10
10
|
|
11
|
-
|
11
|
+
OS X Lion 10.7:
|
12
|
+
|
13
|
+
Install Qt via [homebrew](http://mxcl.github.com/homebrew/)(can take more than an hour) using:
|
14
|
+
|
15
|
+
brew install qt --build-from-source
|
16
|
+
|
17
|
+
OS X < 10.7:
|
18
|
+
|
19
|
+
[Download the non-debug Cocoa package](http://qt.nokia.com/downloads/qt-for-open-source-cpp-development-on-mac-os-x).
|
20
|
+
|
21
|
+
Ubuntu:
|
22
|
+
|
23
|
+
apt-get install libqt4-dev
|
24
|
+
|
25
|
+
Fedora:
|
26
|
+
|
27
|
+
yum install qt-webkit-devel
|
28
|
+
|
29
|
+
Gentoo Linux:
|
12
30
|
|
13
|
-
|
31
|
+
emerge x11-libs/qt-webkit
|
32
|
+
|
33
|
+
Other Linux distributions:
|
34
|
+
|
35
|
+
[Download this package](http://qt.nokia.com/downloads/linux-x11-cpp).
|
14
36
|
|
15
37
|
CI
|
16
38
|
--
|
@@ -32,15 +54,28 @@ Set your Capybara Javascript driver to webkit:
|
|
32
54
|
|
33
55
|
Tag scenarios with @javascript to run them using a headless WebKit browser.
|
34
56
|
|
57
|
+
Contributing
|
58
|
+
------------
|
59
|
+
|
60
|
+
See the CONTRIBUTING document.
|
61
|
+
|
35
62
|
About
|
36
63
|
-----
|
37
64
|
|
38
65
|
The capybara WebKit driver was written by Joe Ferris, Tristan Dunn, and Jason Morrison from [thoughtbot, inc](http://thoughtbot.com/community).
|
39
66
|
|
67
|
+
Code for rendering the current webpage to a PNG is borrowed from Phantom.js' implementation.
|
68
|
+
|
40
69
|

|
41
70
|
|
42
71
|
The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
43
72
|
|
73
|
+
Notes
|
74
|
+
-----
|
75
|
+
|
76
|
+
This capybara WebKit driver will listen on port 8200, this may conflict
|
77
|
+
with other services.
|
78
|
+
|
44
79
|
License
|
45
80
|
-------
|
46
81
|
|
data/capybara-webkit.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "capybara-webkit"
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "0.6.0"
|
4
4
|
s.authors = ["thoughtbot", "Joe Ferris", "Jason Morrison", "Tristan Dunn",
|
5
5
|
"Joshua Clayton", "Yuichi Tateno", "Aaron Gibralter",
|
6
6
|
"Vasily Reys", "petrushka", "John Bintz", "Chad Pytel",
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.require_path = "lib"
|
14
14
|
s.rubygems_version = "1.3.5"
|
15
15
|
s.summary = "Headless Webkit driver for Capybara"
|
16
|
-
s.add_runtime_dependency "capybara", "~> 0.
|
16
|
+
s.add_runtime_dependency "capybara", "~> 1.0.0"
|
17
17
|
s.extensions = "extconf.rb"
|
18
18
|
end
|
19
19
|
|
data/lib/capybara-webkit.rb
CHANGED
@@ -5,3 +5,7 @@ Capybara.register_driver :webkit do |app|
|
|
5
5
|
Capybara::Driver::Webkit.new(app)
|
6
6
|
end
|
7
7
|
|
8
|
+
Capybara.register_driver :webkit_debug do |app|
|
9
|
+
browser = Capybara::Driver::Webkit::Browser.new(:socket_class => Capybara::Driver::Webkit::SocketDebugger)
|
10
|
+
Capybara::Driver::Webkit.new(app, :browser => browser)
|
11
|
+
end
|
@@ -1,9 +1,13 @@
|
|
1
1
|
require "capybara"
|
2
2
|
require "capybara/driver/webkit/node"
|
3
3
|
require "capybara/driver/webkit/browser"
|
4
|
+
require "capybara/driver/webkit/socket_debugger"
|
4
5
|
|
5
6
|
class Capybara::Driver::Webkit
|
6
|
-
class
|
7
|
+
class WebkitInvalidResponseError < StandardError
|
8
|
+
end
|
9
|
+
|
10
|
+
class WebkitNoResponseError < StandardError
|
7
11
|
end
|
8
12
|
|
9
13
|
attr_reader :browser
|
@@ -33,11 +37,16 @@ class Capybara::Driver::Webkit
|
|
33
37
|
end
|
34
38
|
|
35
39
|
def body
|
36
|
-
|
40
|
+
browser.body
|
41
|
+
end
|
42
|
+
|
43
|
+
def header(key, value)
|
44
|
+
browser.header(key, value)
|
37
45
|
end
|
38
46
|
|
39
47
|
def execute_script(script)
|
40
|
-
browser.execute_script script
|
48
|
+
value = browser.execute_script script
|
49
|
+
value.empty? ? nil : value
|
41
50
|
end
|
42
51
|
|
43
52
|
def evaluate_script(script)
|
@@ -80,6 +89,17 @@ class Capybara::Driver::Webkit
|
|
80
89
|
false
|
81
90
|
end
|
82
91
|
|
92
|
+
def render(path, options={})
|
93
|
+
options[:width] ||= 1000
|
94
|
+
options[:height] ||= 10
|
95
|
+
|
96
|
+
browser.render path, options[:width], options[:height]
|
97
|
+
end
|
98
|
+
|
99
|
+
def server_port
|
100
|
+
@rack_server.port
|
101
|
+
end
|
102
|
+
|
83
103
|
private
|
84
104
|
|
85
105
|
def url(path)
|
@@ -4,6 +4,8 @@ require 'json'
|
|
4
4
|
|
5
5
|
class Capybara::Driver::Webkit
|
6
6
|
class Browser
|
7
|
+
attr :server_port
|
8
|
+
|
7
9
|
def initialize(options = {})
|
8
10
|
@socket_class = options[:socket_class] || TCPSocket
|
9
11
|
start_server
|
@@ -14,6 +16,10 @@ class Capybara::Driver::Webkit
|
|
14
16
|
command "Visit", url
|
15
17
|
end
|
16
18
|
|
19
|
+
def header(key, value)
|
20
|
+
command("Header", key, value)
|
21
|
+
end
|
22
|
+
|
17
23
|
def find(query)
|
18
24
|
command("Find", query).split(",")
|
19
25
|
end
|
@@ -22,6 +28,10 @@ class Capybara::Driver::Webkit
|
|
22
28
|
command("Reset")
|
23
29
|
end
|
24
30
|
|
31
|
+
def body
|
32
|
+
command("Body")
|
33
|
+
end
|
34
|
+
|
25
35
|
def source
|
26
36
|
command("Source")
|
27
37
|
end
|
@@ -45,7 +55,7 @@ class Capybara::Driver::Webkit
|
|
45
55
|
@socket.puts args.size
|
46
56
|
args.each do |arg|
|
47
57
|
@socket.puts arg.to_s.bytesize
|
48
|
-
@socket.print arg
|
58
|
+
@socket.print arg.to_s
|
49
59
|
end
|
50
60
|
check
|
51
61
|
read_response
|
@@ -60,12 +70,35 @@ class Capybara::Driver::Webkit
|
|
60
70
|
command('Execute', script)
|
61
71
|
end
|
62
72
|
|
73
|
+
def render(path, width, height)
|
74
|
+
command "Render", path, width, height
|
75
|
+
end
|
76
|
+
|
63
77
|
private
|
64
78
|
|
65
79
|
def start_server
|
80
|
+
read_pipe, write_pipe = fork_server
|
81
|
+
@server_port = discover_server_port(read_pipe)
|
82
|
+
end
|
83
|
+
|
84
|
+
def fork_server
|
66
85
|
server_path = File.expand_path("../../../../../bin/webkit_server", __FILE__)
|
67
|
-
|
86
|
+
|
87
|
+
read_pipe, write_pipe = IO.pipe
|
88
|
+
@pid = fork do
|
89
|
+
$stdout.reopen write_pipe
|
90
|
+
read_pipe.close
|
91
|
+
exec(server_path)
|
92
|
+
end
|
68
93
|
at_exit { Process.kill("INT", @pid) }
|
94
|
+
|
95
|
+
write_pipe.close
|
96
|
+
[read_pipe, write_pipe]
|
97
|
+
end
|
98
|
+
|
99
|
+
def discover_server_port(read_pipe)
|
100
|
+
return unless IO.select([read_pipe], nil, nil, 10)
|
101
|
+
((read_pipe.first || '').match(/listening on port: (\d+)/) || [])[1].to_i
|
69
102
|
end
|
70
103
|
|
71
104
|
def connect
|
@@ -76,16 +109,21 @@ class Capybara::Driver::Webkit
|
|
76
109
|
end
|
77
110
|
|
78
111
|
def attempt_connect
|
79
|
-
@socket = @socket_class.open("localhost",
|
112
|
+
@socket = @socket_class.open("localhost", @server_port)
|
80
113
|
rescue Errno::ECONNREFUSED
|
81
114
|
end
|
82
115
|
|
83
116
|
def check
|
84
|
-
result = @socket.gets
|
117
|
+
result = @socket.gets
|
118
|
+
result.strip! if result
|
85
119
|
|
86
|
-
|
87
|
-
raise
|
120
|
+
if result.nil?
|
121
|
+
raise WebkitNoResponseError, "No response received from the server."
|
122
|
+
elsif result != 'ok'
|
123
|
+
raise WebkitInvalidResponseError, read_response
|
88
124
|
end
|
125
|
+
|
126
|
+
result
|
89
127
|
end
|
90
128
|
|
91
129
|
def read_response
|
@@ -34,7 +34,12 @@ class Capybara::Driver::Webkit
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def unselect_option
|
37
|
-
|
37
|
+
select = find("ancestor::select").first
|
38
|
+
if select.multiple_select?
|
39
|
+
invoke "unselectOption"
|
40
|
+
else
|
41
|
+
raise Capybara::UnselectNotAllowed
|
42
|
+
end
|
38
43
|
end
|
39
44
|
|
40
45
|
def click
|
@@ -53,10 +58,18 @@ class Capybara::Driver::Webkit
|
|
53
58
|
invoke("visible") == "true"
|
54
59
|
end
|
55
60
|
|
61
|
+
def selected?
|
62
|
+
invoke("selected") == "true"
|
63
|
+
end
|
64
|
+
|
65
|
+
def checked?
|
66
|
+
self['checked']
|
67
|
+
end
|
68
|
+
|
56
69
|
def disabled?
|
57
70
|
self['disabled']
|
58
71
|
end
|
59
|
-
|
72
|
+
|
60
73
|
def path
|
61
74
|
raise Capybara::NotSupportedByDriverError
|
62
75
|
end
|
@@ -79,8 +92,6 @@ class Capybara::Driver::Webkit
|
|
79
92
|
driver.browser
|
80
93
|
end
|
81
94
|
|
82
|
-
private
|
83
|
-
|
84
95
|
def multiple_select?
|
85
96
|
self.tag_name == "select" && self["multiple"] == "multiple"
|
86
97
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Wraps the TCP socket and prints data sent and received. Used for debugging
|
2
|
+
# the wire protocol. You can use this by passing a :socket_class to Browser.
|
3
|
+
class Capybara::Driver::Webkit
|
4
|
+
class SocketDebugger
|
5
|
+
def self.open(host, port)
|
6
|
+
real_socket = TCPSocket.open(host, port)
|
7
|
+
new(real_socket)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(socket)
|
11
|
+
@socket = socket
|
12
|
+
end
|
13
|
+
|
14
|
+
def read(length)
|
15
|
+
received @socket.read(length)
|
16
|
+
end
|
17
|
+
|
18
|
+
def puts(line)
|
19
|
+
sent line
|
20
|
+
@socket.puts(line)
|
21
|
+
end
|
22
|
+
|
23
|
+
def print(content)
|
24
|
+
sent content
|
25
|
+
@socket.print(content)
|
26
|
+
end
|
27
|
+
|
28
|
+
def gets
|
29
|
+
received @socket.gets
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def sent(content)
|
35
|
+
Kernel.puts " >> " + content.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def received(content)
|
39
|
+
Kernel.puts " << " + content.to_s
|
40
|
+
content
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|