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.
Files changed (86) hide show
  1. data/.gitignore +3 -1
  2. data/Gemfile.lock +5 -4
  3. data/NEWS.md +11 -0
  4. data/README.md +42 -0
  5. data/lib/capybara/driver/webkit.rb +7 -2
  6. data/lib/capybara/driver/webkit/browser.rb +22 -96
  7. data/lib/capybara/driver/webkit/connection.rb +120 -0
  8. data/lib/capybara/driver/webkit/version.rb +1 -1
  9. data/lib/capybara/webkit/matchers.rb +2 -4
  10. data/lib/capybara_webkit_builder.rb +22 -4
  11. data/spec/browser_spec.rb +19 -29
  12. data/spec/connection_spec.rb +54 -0
  13. data/spec/driver_resize_window_spec.rb +59 -0
  14. data/spec/driver_spec.rb +175 -27
  15. data/spec/spec_helper.rb +9 -2
  16. data/src/Body.h +2 -2
  17. data/src/ClearCookies.cpp +2 -5
  18. data/src/ClearCookies.h +2 -2
  19. data/src/Command.cpp +7 -3
  20. data/src/Command.h +4 -2
  21. data/src/CommandFactory.cpp +7 -2
  22. data/src/CommandFactory.h +1 -1
  23. data/src/CommandParser.cpp +13 -5
  24. data/src/CommandParser.h +6 -2
  25. data/src/Connection.cpp +18 -47
  26. data/src/Connection.h +5 -7
  27. data/src/ConsoleMessages.cpp +2 -3
  28. data/src/ConsoleMessages.h +2 -2
  29. data/src/CurrentUrl.cpp +3 -6
  30. data/src/CurrentUrl.h +2 -2
  31. data/src/Evaluate.cpp +3 -3
  32. data/src/Evaluate.h +2 -2
  33. data/src/Execute.cpp +4 -4
  34. data/src/Execute.h +2 -2
  35. data/src/Find.cpp +4 -4
  36. data/src/Find.h +2 -2
  37. data/src/FrameFocus.cpp +7 -7
  38. data/src/FrameFocus.h +2 -2
  39. data/src/GetCookies.cpp +2 -4
  40. data/src/GetCookies.h +2 -2
  41. data/src/Header.cpp +4 -4
  42. data/src/Header.h +2 -2
  43. data/src/Headers.cpp +2 -3
  44. data/src/Headers.h +2 -2
  45. data/src/IgnoreSslErrors.cpp +12 -0
  46. data/src/IgnoreSslErrors.h +12 -0
  47. data/src/NetworkAccessManager.cpp +4 -0
  48. data/src/NetworkAccessManager.h +2 -1
  49. data/src/Node.cpp +3 -3
  50. data/src/Node.h +2 -2
  51. data/src/NullCommand.cpp +10 -0
  52. data/src/NullCommand.h +11 -0
  53. data/src/PageLoadingCommand.cpp +46 -0
  54. data/src/PageLoadingCommand.h +40 -0
  55. data/src/Render.cpp +5 -6
  56. data/src/Render.h +2 -2
  57. data/src/RequestedUrl.cpp +3 -6
  58. data/src/RequestedUrl.h +2 -2
  59. data/src/Reset.cpp +8 -7
  60. data/src/Reset.h +2 -2
  61. data/src/ResizeWindow.cpp +16 -0
  62. data/src/ResizeWindow.h +12 -0
  63. data/src/Response.cpp +6 -1
  64. data/src/Response.h +4 -2
  65. data/src/Server.cpp +2 -3
  66. data/src/Server.h +1 -1
  67. data/src/SetCookie.cpp +3 -5
  68. data/src/SetCookie.h +2 -2
  69. data/src/SetProxy.cpp +7 -9
  70. data/src/SetProxy.h +2 -2
  71. data/src/Source.cpp +2 -4
  72. data/src/Source.h +2 -2
  73. data/src/Status.cpp +2 -3
  74. data/src/Status.h +2 -2
  75. data/src/Url.cpp +3 -6
  76. data/src/Url.h +2 -2
  77. data/src/Visit.cpp +4 -13
  78. data/src/Visit.h +2 -5
  79. data/src/WebPage.cpp +11 -9
  80. data/src/WebPage.h +3 -3
  81. data/src/body.cpp +2 -3
  82. data/src/capybara.js +58 -3
  83. data/src/find_command.h +3 -1
  84. data/src/main.cpp +1 -2
  85. data/src/webkit_server.pro +8 -0
  86. metadata +29 -16
data/.gitignore CHANGED
@@ -1,5 +1,5 @@
1
1
  *.swp
2
- bin/webkit_server
2
+ bin/webkit_server*
3
3
  *.swo
4
4
  *~
5
5
  *.o
@@ -12,6 +12,8 @@ moc_*.cpp
12
12
  .bundle
13
13
  pkg
14
14
  src/webkit_server
15
+ src/webkit_server.exe
15
16
  .DS_Store
16
17
  tmp
17
18
  .rvmrc
19
+ src/debug
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capybara-webkit (0.10.1)
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.6.5)
26
- mime-types (1.17.2)
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.6.1)
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
- :ignore_ssl_errors => options[:ignore_ssl_errors])
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
- attr :server_port
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
- @socket.puts name
89
- @socket.puts args.size
81
+ @connection.puts name
82
+ @connection.puts args.size
90
83
  args.each do |arg|
91
- @socket.puts arg.to_s.bytesize
92
- @socket.print arg.to_s
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
- private
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
- def forward_stdout(pipe)
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 = @socket.gets
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 = @socket.gets.to_i
224
- response = @socket.read(response_length)
225
- response.force_encoding("UTF-8") if response.respond_to?(:force_encoding)
226
- response
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,7 +1,7 @@
1
1
  module Capybara
2
2
  module Driver
3
3
  class Webkit
4
- VERSION = '0.11.0'.freeze
4
+ VERSION = '0.12.0'.freeze
5
5
  end
6
6
  end
7
7
  end
@@ -1,9 +1,7 @@
1
1
  module Capybara
2
2
  module Webkit
3
3
  module RspecMatchers
4
- extend RSpec::Matchers::DSL
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