capybara-webkit 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -12,3 +12,6 @@ moc_*.cpp
12
12
  .bundle
13
13
  pkg
14
14
  src/webkit_server
15
+ .DS_Store
16
+ tmp
17
+ .rvmrc
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
@@ -1,5 +1,6 @@
1
1
  source "http://rubygems.org"
2
- gem "rspec", :require => false
2
+ gem "rspec", '~> 2.6.0', :require => false
3
3
  gem "capybara"
4
4
  gem "sinatra", :require => false
5
-
5
+ gem "mini_magick", :require => false
6
+ gem 'rake'
data/Gemfile.lock CHANGED
@@ -1,48 +1,46 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- capybara (0.4.1.2)
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 (>= 0.0.27)
12
- xpath (~> 0.1.3)
13
- celerity (0.8.8)
14
- childprocess (0.1.7)
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.6.3)
19
- rake (>= 0.8.7)
20
- json_pure (1.5.1)
14
+ ffi (1.0.9)
15
+ json_pure (1.5.3)
21
16
  mime-types (1.16)
22
- nokogiri (1.4.4)
23
- rack (1.2.1)
24
- rack-test (0.5.7)
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.8.7)
27
- rspec (2.5.0)
28
- rspec-core (~> 2.5.0)
29
- rspec-expectations (~> 2.5.0)
30
- rspec-mocks (~> 2.5.0)
31
- rspec-core (2.5.1)
32
- rspec-expectations (2.5.0)
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.5.0)
31
+ rspec-mocks (2.6.0)
35
32
  rubyzip (0.9.4)
36
- selenium-webdriver (0.1.3)
37
- childprocess (~> 0.1.5)
38
- ffi (~> 0.6.3)
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.3)
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
- rspec
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
- Dependencies
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
- If you're on OS X, [download the non-debug Cocoa package](http://qt.nokia.com/downloads/qt-for-open-source-cpp-development-on-mac-os-x). Note that installing Qt via homebrew takes more than an hour, so we don't recommend it.
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
- If you're on Ubuntu, you can install the libqt4-dev package. For other Linux distributions, [download this package](http://qt.nokia.com/downloads/linux-x11-cpp).
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
  ![thoughtbot](http://thoughtbot.com/images/tm/logo.png)
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
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "capybara-webkit"
3
- s.version = "0.5.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.4.1"
16
+ s.add_runtime_dependency "capybara", "~> 1.0.0"
17
17
  s.extensions = "extconf.rb"
18
18
  end
19
19
 
@@ -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 WebkitError < StandardError
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
- source
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
- @pid = fork { exec(server_path) }
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", 9200)
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.strip
117
+ result = @socket.gets
118
+ result.strip! if result
85
119
 
86
- unless result == 'ok'
87
- raise WebkitError, read_response
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
- invoke "unselectOption"
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