capybara-webkit 0.12.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/.gitignore +2 -1
  2. data/GOALS +9 -0
  3. data/Gemfile.lock +15 -12
  4. data/LICENSE +1 -1
  5. data/NEWS.md +18 -0
  6. data/README.md +81 -2
  7. data/capybara-webkit.gemspec +1 -1
  8. data/lib/capybara/webkit.rb +11 -6
  9. data/lib/capybara/{driver/webkit → webkit}/browser.rb +90 -4
  10. data/lib/capybara/{driver/webkit → webkit}/connection.rb +48 -47
  11. data/lib/capybara/{driver/webkit → webkit}/cookie_jar.rb +1 -1
  12. data/lib/capybara/webkit/driver.rb +186 -0
  13. data/lib/capybara/webkit/errors.rb +10 -0
  14. data/lib/capybara/{driver/webkit → webkit}/node.rb +12 -4
  15. data/lib/capybara/{driver/webkit → webkit}/socket_debugger.rb +4 -1
  16. data/lib/capybara/{driver/webkit → webkit}/version.rb +1 -1
  17. data/lib/capybara_webkit_builder.rb +17 -3
  18. data/spec/browser_spec.rb +95 -7
  19. data/spec/connection_spec.rb +16 -5
  20. data/spec/cookie_jar_spec.rb +3 -3
  21. data/spec/driver_rendering_spec.rb +19 -26
  22. data/spec/driver_resize_window_spec.rb +3 -3
  23. data/spec/driver_spec.rb +1200 -822
  24. data/spec/integration/driver_spec.rb +4 -3
  25. data/spec/selenium_compatibility_spec.rb +49 -0
  26. data/spec/spec_helper.rb +14 -6
  27. data/spec/support/app_runner.rb +94 -0
  28. data/src/Authenticate.cpp +18 -0
  29. data/src/Authenticate.h +12 -0
  30. data/src/Body.h +3 -5
  31. data/src/ClearCookies.cpp +3 -5
  32. data/src/ClearCookies.h +3 -5
  33. data/src/ClearPromptText.cpp +11 -0
  34. data/src/ClearPromptText.h +9 -0
  35. data/src/Command.cpp +4 -15
  36. data/src/Command.h +3 -14
  37. data/src/CommandFactory.cpp +20 -6
  38. data/src/CommandFactory.h +3 -2
  39. data/src/CommandParser.cpp +1 -1
  40. data/src/Connection.cpp +22 -21
  41. data/src/Connection.h +5 -6
  42. data/src/ConsoleMessages.cpp +2 -1
  43. data/src/ConsoleMessages.h +3 -5
  44. data/src/CurrentUrl.cpp +9 -48
  45. data/src/CurrentUrl.h +8 -8
  46. data/src/EnableLogging.cpp +10 -0
  47. data/src/EnableLogging.h +12 -0
  48. data/src/Evaluate.cpp +2 -1
  49. data/src/Evaluate.h +3 -5
  50. data/src/Execute.cpp +2 -1
  51. data/src/Execute.h +3 -5
  52. data/src/Find.cpp +3 -2
  53. data/src/Find.h +3 -5
  54. data/src/FrameFocus.cpp +3 -2
  55. data/src/FrameFocus.h +3 -4
  56. data/src/GetCookies.cpp +3 -4
  57. data/src/GetCookies.h +3 -5
  58. data/src/GetTimeout.cpp +9 -0
  59. data/src/GetTimeout.h +11 -0
  60. data/src/GetWindowHandle.cpp +11 -0
  61. data/src/GetWindowHandle.h +10 -0
  62. data/src/GetWindowHandles.cpp +20 -0
  63. data/src/GetWindowHandles.h +10 -0
  64. data/src/Header.cpp +2 -1
  65. data/src/Header.h +3 -5
  66. data/src/Headers.cpp +8 -2
  67. data/src/Headers.h +3 -5
  68. data/src/IgnoreSslErrors.cpp +4 -3
  69. data/src/IgnoreSslErrors.h +3 -5
  70. data/src/JavascriptAlertMessages.cpp +10 -0
  71. data/src/JavascriptAlertMessages.h +9 -0
  72. data/src/JavascriptConfirmMessages.cpp +10 -0
  73. data/src/JavascriptConfirmMessages.h +9 -0
  74. data/src/JavascriptInvocation.cpp +1 -1
  75. data/src/JavascriptInvocation.h +1 -1
  76. data/src/JavascriptPromptMessages.cpp +10 -0
  77. data/src/JavascriptPromptMessages.h +9 -0
  78. data/src/NetworkAccessManager.cpp +38 -5
  79. data/src/NetworkAccessManager.h +20 -0
  80. data/src/Node.cpp +6 -1
  81. data/src/Node.h +4 -5
  82. data/src/NullCommand.cpp +5 -2
  83. data/src/NullCommand.h +4 -3
  84. data/src/PageLoadingCommand.cpp +12 -7
  85. data/src/PageLoadingCommand.h +6 -9
  86. data/src/Render.cpp +2 -1
  87. data/src/Render.h +3 -5
  88. data/src/RequestedUrl.cpp +2 -1
  89. data/src/RequestedUrl.h +3 -5
  90. data/src/Reset.cpp +3 -17
  91. data/src/Reset.h +3 -8
  92. data/src/ResizeWindow.cpp +2 -1
  93. data/src/ResizeWindow.h +3 -5
  94. data/src/Response.cpp +4 -0
  95. data/src/Response.h +1 -0
  96. data/src/Server.cpp +2 -3
  97. data/src/Server.h +0 -2
  98. data/src/SetConfirmAction.cpp +11 -0
  99. data/src/SetConfirmAction.h +9 -0
  100. data/src/SetCookie.cpp +3 -4
  101. data/src/SetCookie.h +3 -5
  102. data/src/SetPromptAction.cpp +11 -0
  103. data/src/SetPromptAction.h +9 -0
  104. data/src/SetPromptText.cpp +11 -0
  105. data/src/SetPromptText.h +9 -0
  106. data/src/SetProxy.cpp +2 -1
  107. data/src/SetProxy.h +3 -5
  108. data/src/SetSkipImageLoading.cpp +12 -0
  109. data/src/SetSkipImageLoading.h +9 -0
  110. data/src/SetTimeout.cpp +19 -0
  111. data/src/SetTimeout.h +9 -0
  112. data/src/SocketCommand.cpp +21 -0
  113. data/src/SocketCommand.h +29 -0
  114. data/src/Source.cpp +3 -2
  115. data/src/Source.h +3 -4
  116. data/src/Status.cpp +2 -1
  117. data/src/Status.h +3 -5
  118. data/src/TimeoutCommand.cpp +69 -0
  119. data/src/TimeoutCommand.h +41 -0
  120. data/src/UnsupportedContentHandler.cpp +11 -17
  121. data/src/UnsupportedContentHandler.h +5 -3
  122. data/src/Url.cpp +2 -1
  123. data/src/Url.h +3 -5
  124. data/src/Visit.cpp +3 -2
  125. data/src/Visit.h +3 -5
  126. data/src/WebPage.cpp +129 -44
  127. data/src/WebPage.h +37 -11
  128. data/src/WebPageManager.cpp +127 -0
  129. data/src/WebPageManager.h +59 -0
  130. data/src/WindowFocus.cpp +32 -0
  131. data/src/WindowFocus.h +15 -0
  132. data/src/body.cpp +2 -1
  133. data/src/capybara.js +38 -10
  134. data/src/find_command.h +17 -2
  135. data/src/main.cpp +0 -2
  136. data/src/webkit_server.pro +36 -0
  137. data/templates/Command.cpp +2 -4
  138. data/templates/Command.h +3 -3
  139. metadata +106 -27
  140. data/ChangeLog +0 -70
  141. data/lib/capybara/driver/webkit.rb +0 -136
@@ -3,7 +3,7 @@ require 'webrick'
3
3
  # A simple cookie jar implementation.
4
4
  # Does not take special cookie attributes
5
5
  # into account like expire, max-age, httponly, secure
6
- class Capybara::Driver::Webkit::CookieJar
6
+ class Capybara::Webkit::CookieJar
7
7
  attr_reader :browser
8
8
 
9
9
  def initialize(browser)
@@ -0,0 +1,186 @@
1
+ require "capybara"
2
+ require "capybara/webkit/version"
3
+ require "capybara/webkit/node"
4
+ require "capybara/webkit/connection"
5
+ require "capybara/webkit/browser"
6
+ require "capybara/webkit/socket_debugger"
7
+ require "capybara/webkit/cookie_jar"
8
+ require "capybara/webkit/errors"
9
+
10
+ module Capybara::Webkit
11
+ class Driver
12
+ attr_reader :browser
13
+
14
+ def initialize(app, options={})
15
+ @app = app
16
+ @options = options
17
+ @rack_server = Capybara::Server.new(@app)
18
+ @rack_server.boot if Capybara.run_server
19
+ @browser = options[:browser] || Browser.new(Connection.new(options))
20
+ end
21
+
22
+ def enable_logging
23
+ browser.enable_logging
24
+ end
25
+
26
+ def current_url
27
+ browser.current_url
28
+ end
29
+
30
+ def requested_url
31
+ browser.requested_url
32
+ end
33
+
34
+ def visit(path)
35
+ browser.visit(url(path))
36
+ end
37
+
38
+ def find(query)
39
+ browser.find(query).map { |native| Node.new(self, native) }
40
+ end
41
+
42
+ def source
43
+ browser.source
44
+ end
45
+
46
+ def body
47
+ browser.body
48
+ end
49
+
50
+ def header(key, value)
51
+ browser.header(key, value)
52
+ end
53
+
54
+ def execute_script(script)
55
+ value = browser.execute_script script
56
+ value.empty? ? nil : value
57
+ end
58
+
59
+ def evaluate_script(script)
60
+ browser.evaluate_script script
61
+ end
62
+
63
+ def console_messages
64
+ browser.console_messages
65
+ end
66
+
67
+ def error_messages
68
+ browser.error_messages
69
+ end
70
+
71
+ def alert_messages
72
+ browser.alert_messages
73
+ end
74
+
75
+ def confirm_messages
76
+ browser.confirm_messages
77
+ end
78
+
79
+ def prompt_messages
80
+ browser.prompt_messages
81
+ end
82
+
83
+ def response_headers
84
+ browser.response_headers
85
+ end
86
+
87
+ def status_code
88
+ browser.status_code
89
+ end
90
+
91
+ def resize_window(width, height)
92
+ browser.resize_window(width, height)
93
+ end
94
+
95
+ def within_frame(frame_id_or_index)
96
+ browser.frame_focus(frame_id_or_index)
97
+ begin
98
+ yield
99
+ ensure
100
+ browser.frame_focus
101
+ end
102
+ end
103
+
104
+ def within_window(selector)
105
+ current_window = window_handle
106
+ browser.window_focus(selector)
107
+ begin
108
+ yield
109
+ ensure
110
+ browser.window_focus(current_window)
111
+ end
112
+ end
113
+
114
+ def window_handles
115
+ browser.get_window_handles
116
+ end
117
+
118
+ def window_handle
119
+ browser.get_window_handle
120
+ end
121
+
122
+ def accept_js_confirms!
123
+ browser.accept_js_confirms
124
+ end
125
+
126
+ def dismiss_js_confirms!
127
+ browser.reject_js_confirms
128
+ end
129
+
130
+ def accept_js_prompts!
131
+ browser.accept_js_prompts
132
+ end
133
+
134
+ def dismiss_js_prompts!
135
+ browser.reject_js_prompts
136
+ end
137
+
138
+ def js_prompt_input=(value)
139
+ if value.nil?
140
+ browser.clear_prompt_text
141
+ else
142
+ browser.set_prompt_text_to(value)
143
+ end
144
+ end
145
+
146
+ def wait?
147
+ true
148
+ end
149
+
150
+ def wait_until(*args)
151
+ end
152
+
153
+ def reset!
154
+ browser.reset!
155
+ end
156
+
157
+ def has_shortcircuit_timeout?
158
+ false
159
+ end
160
+
161
+ def render(path, options={})
162
+ options[:width] ||= 1000
163
+ options[:height] ||= 10
164
+
165
+ browser.render path, options[:width], options[:height]
166
+ end
167
+
168
+ def server_port
169
+ @rack_server.port
170
+ end
171
+
172
+ def cookies
173
+ @cookie_jar ||= CookieJar.new(browser)
174
+ end
175
+
176
+ def invalid_element_errors
177
+ []
178
+ end
179
+
180
+ private
181
+
182
+ def url(path)
183
+ @rack_server.url(path)
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,10 @@
1
+ module Capybara::Webkit
2
+ class InvalidResponseError < StandardError
3
+ end
4
+
5
+ class NoResponseError < StandardError
6
+ end
7
+
8
+ class NodeNotAttachedError < Capybara::ElementNotFound
9
+ end
10
+ end
@@ -1,4 +1,4 @@
1
- class Capybara::Driver::Webkit
1
+ module Capybara::Webkit
2
2
  class Node < Capybara::Driver::Node
3
3
  NBSP = "\xC2\xA0"
4
4
  NBSP.force_encoding("UTF-8") if NBSP.respond_to?(:force_encoding)
@@ -9,7 +9,7 @@ class Capybara::Driver::Webkit
9
9
 
10
10
  def [](name)
11
11
  value = invoke("attribute", name)
12
- if name == 'checked' || name == 'disabled'
12
+ if name == 'checked' || name == 'disabled' || name == 'multiple'
13
13
  value == 'true'
14
14
  else
15
15
  value
@@ -24,6 +24,14 @@ class Capybara::Driver::Webkit
24
24
  end
25
25
  end
26
26
 
27
+ def inner_html
28
+ invoke 'getInnerHTML'
29
+ end
30
+
31
+ def inner_html=(value)
32
+ invoke 'setInnerHTML', value
33
+ end
34
+
27
35
  def set(value)
28
36
  invoke "set", value
29
37
  end
@@ -91,7 +99,7 @@ class Capybara::Driver::Webkit
91
99
  if allow_unattached_nodes? || attached?
92
100
  browser.command "Node", name, native, *args
93
101
  else
94
- raise Capybara::Driver::Webkit::NodeNotAttachedError
102
+ raise Capybara::Webkit::NodeNotAttachedError
95
103
  end
96
104
  end
97
105
 
@@ -112,7 +120,7 @@ class Capybara::Driver::Webkit
112
120
  end
113
121
 
114
122
  def multiple_select?
115
- self.tag_name == "select" && self["multiple"] == "multiple"
123
+ self.tag_name == "select" && self["multiple"]
116
124
  end
117
125
  end
118
126
  end
@@ -1,6 +1,6 @@
1
1
  # Wraps the TCP socket and prints data sent and received. Used for debugging
2
2
  # the wire protocol. You can use this by passing a :socket_class to Browser.
3
- class Capybara::Driver::Webkit
3
+ module Capybara::Webkit
4
4
  class SocketDebugger
5
5
  def self.open(host, port)
6
6
  real_socket = TCPSocket.open(host, port)
@@ -29,6 +29,9 @@ class Capybara::Driver::Webkit
29
29
  received @socket.gets
30
30
  end
31
31
 
32
+ def setsockopt(level, name, value)
33
+ end
34
+
32
35
  private
33
36
 
34
37
  def sent(content)
@@ -1,7 +1,7 @@
1
1
  module Capybara
2
2
  module Driver
3
3
  class Webkit
4
- VERSION = '0.12.1'.freeze
4
+ VERSION = '0.13.0'.freeze
5
5
  end
6
6
  end
7
7
  end
@@ -4,6 +4,9 @@ require "rbconfig"
4
4
  module CapybaraWebkitBuilder
5
5
  extend self
6
6
 
7
+ SUCCESS_STATUS = 0
8
+ COMMAND_NOT_FOUND_STATUS = 127
9
+
7
10
  def make_bin
8
11
  ENV['MAKE'] || 'make'
9
12
  end
@@ -29,12 +32,23 @@ module CapybaraWebkitBuilder
29
32
  end
30
33
  end
31
34
 
35
+ def sh(command)
36
+ system(command)
37
+ success = $?.exitstatus == SUCCESS_STATUS
38
+ if $?.exitstatus == COMMAND_NOT_FOUND_STATUS
39
+ puts "Command '#{command}' not available"
40
+ elsif !success
41
+ puts "Command '#{command}' failed"
42
+ end
43
+ success
44
+ end
45
+
32
46
  def makefile
33
- system("#{qmake_bin} -spec #{spec}")
47
+ sh("#{qmake_bin} -spec #{spec}")
34
48
  end
35
49
 
36
50
  def qmake
37
- system("#{make_bin} qmake")
51
+ sh("#{make_bin} qmake")
38
52
  end
39
53
 
40
54
  def path_to_binary
@@ -47,7 +61,7 @@ module CapybaraWebkitBuilder
47
61
  end
48
62
 
49
63
  def build
50
- system(make_bin) or return false
64
+ sh(make_bin) or return false
51
65
 
52
66
  FileUtils.mkdir("bin") unless File.directory?("bin")
53
67
  FileUtils.cp(path_to_binary, "bin", :preserve => true)
@@ -1,19 +1,23 @@
1
1
  require 'spec_helper'
2
2
  require 'self_signed_ssl_cert'
3
3
  require 'stringio'
4
- require 'capybara/driver/webkit/browser'
5
- require 'capybara/driver/webkit/connection'
4
+ require 'capybara/webkit/driver'
6
5
  require 'socket'
7
6
  require 'base64'
8
7
 
9
- describe Capybara::Driver::Webkit::Browser do
8
+ describe Capybara::Webkit::Browser do
10
9
 
11
- let(:browser) { Capybara::Driver::Webkit::Browser.new(Capybara::Driver::Webkit::Connection.new) }
10
+ let(:browser) { Capybara::Webkit::Browser.new(Capybara::Webkit::Connection.new) }
12
11
  let(:browser_ignore_ssl_err) do
13
- Capybara::Driver::Webkit::Browser.new(Capybara::Driver::Webkit::Connection.new).tap do |browser|
12
+ Capybara::Webkit::Browser.new(Capybara::Webkit::Connection.new).tap do |browser|
14
13
  browser.ignore_ssl_errors
15
14
  end
16
15
  end
16
+ let(:browser_skip_images) do
17
+ Capybara::Webkit::Browser.new(Capybara::Webkit::Connection.new).tap do |browser|
18
+ browser.set_skip_image_loading(true)
19
+ end
20
+ end
17
21
 
18
22
  context 'handling of SSL validation errors' do
19
23
  before do
@@ -57,6 +61,90 @@ describe Capybara::Driver::Webkit::Browser do
57
61
  it 'accepts a self-signed certificate if configured to do so' do
58
62
  browser_ignore_ssl_err.visit "https://#{@host}:#{@port}/"
59
63
  end
64
+
65
+ it "doesn't accept a self-signed certificate in a new window by default" do
66
+ browser.execute_script("window.open('about:blank')")
67
+ browser.window_focus(browser.get_window_handles.last)
68
+ lambda { browser.visit "https://#{@host}:#{@port}/" }.should raise_error
69
+ end
70
+
71
+ it 'accepts a self-signed certificate in a new window if configured to do so' do
72
+ browser_ignore_ssl_err.execute_script("window.open('about:blank')")
73
+ browser_ignore_ssl_err.window_focus(browser_ignore_ssl_err.get_window_handles.last)
74
+ browser_ignore_ssl_err.visit "https://#{@host}:#{@port}/"
75
+ end
76
+ end
77
+
78
+ context "skip image loading" do
79
+ before(:each) do
80
+ # set up minimal HTTP server
81
+ @host = "127.0.0.1"
82
+ @server = TCPServer.new(@host, 0)
83
+ @port = @server.addr[1]
84
+ @received_requests = []
85
+
86
+ @server_thread = Thread.new do
87
+ while conn = @server.accept
88
+ Thread.new(conn) do |conn|
89
+ # read request
90
+ request = []
91
+ until (line = conn.readline.strip).empty?
92
+ request << line
93
+ end
94
+
95
+ @received_requests << request.join("\n")
96
+
97
+ # write response
98
+ html = <<-HTML
99
+ <html>
100
+ <head>
101
+ <style>
102
+ body {
103
+ background-image: url(/path/to/bgimage);
104
+ }
105
+ </style>
106
+ </head>
107
+ <body>
108
+ <img src="/path/to/image"/>
109
+ </body>
110
+ </html>
111
+ HTML
112
+ conn.write "HTTP/1.1 200 OK\r\n"
113
+ conn.write "Content-Type:text/html\r\n"
114
+ conn.write "Content-Length: %i\r\n" % html.size
115
+ conn.write "\r\n"
116
+ conn.write html
117
+ conn.write("\r\n\r\n")
118
+ conn.close
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ after(:each) do
125
+ @server_thread.kill
126
+ @server.close
127
+ end
128
+
129
+ it "should load images in image tags by default" do
130
+ browser.visit("http://#{@host}:#{@port}/")
131
+ @received_requests.find {|r| r =~ %r{/path/to/image} }.should_not be_nil
132
+ end
133
+
134
+ it "should load images in css by default" do
135
+ browser.visit("http://#{@host}:#{@port}/")
136
+ @received_requests.find {|r| r =~ %r{/path/to/image} }.should_not be_nil
137
+ end
138
+
139
+ it "should not load images in image tags when skip_image_loading is true" do
140
+ browser_skip_images.visit("http://#{@host}:#{@port}/")
141
+ @received_requests.find {|r| r =~ %r{/path/to/image} }.should be_nil
142
+ end
143
+
144
+ it "should not load images in css when skip_image_loading is true" do
145
+ browser_skip_images.visit("http://#{@host}:#{@port}/")
146
+ @received_requests.find {|r| r =~ %r{/path/to/bgimage} }.should be_nil
147
+ end
60
148
  end
61
149
 
62
150
  describe "forking", :skip_on_windows => true do
@@ -148,7 +236,7 @@ describe Capybara::Driver::Webkit::Browser do
148
236
 
149
237
  it 'uses URLs changed by javascript' do
150
238
  browser.execute_script "window.history.pushState('', '', '/blah')"
151
- browser.requested_url.should == 'http://example.org/blah'
239
+ browser.current_url.should == 'http://example.org/blah'
152
240
  end
153
241
 
154
242
  it 'is possible to disable proxy again' do
@@ -166,7 +254,7 @@ describe Capybara::Driver::Webkit::Browser do
166
254
  connection.stub(:gets).and_return("ok\n", "0\n")
167
255
  connection.stub(:read).and_raise(StandardError.new("tried to read empty response"))
168
256
 
169
- browser = Capybara::Driver::Webkit::Browser.new(connection)
257
+ browser = Capybara::Webkit::Browser.new(connection)
170
258
 
171
259
  expect { browser.visit("/") }.not_to raise_error(/empty response/)
172
260
  end