capybara-webkit 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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