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 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