otherinbox-capybara-webkit 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 (123) hide show
  1. data/.gitignore +19 -0
  2. data/.rspec +2 -0
  3. data/Appraisals +7 -0
  4. data/CONTRIBUTING.md +47 -0
  5. data/ChangeLog +70 -0
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +68 -0
  8. data/LICENSE +19 -0
  9. data/NEWS.md +36 -0
  10. data/README.md +114 -0
  11. data/Rakefile +65 -0
  12. data/bin/Info.plist +22 -0
  13. data/capybara-webkit.gemspec +28 -0
  14. data/extconf.rb +2 -0
  15. data/gemfiles/1.0.gemfile +7 -0
  16. data/gemfiles/1.0.gemfile.lock +70 -0
  17. data/gemfiles/1.1.gemfile +7 -0
  18. data/gemfiles/1.1.gemfile.lock +70 -0
  19. data/lib/capybara-webkit.rb +1 -0
  20. data/lib/capybara/driver/webkit.rb +135 -0
  21. data/lib/capybara/driver/webkit/browser.rb +168 -0
  22. data/lib/capybara/driver/webkit/connection.rb +120 -0
  23. data/lib/capybara/driver/webkit/cookie_jar.rb +55 -0
  24. data/lib/capybara/driver/webkit/node.rb +118 -0
  25. data/lib/capybara/driver/webkit/socket_debugger.rb +43 -0
  26. data/lib/capybara/driver/webkit/version.rb +7 -0
  27. data/lib/capybara/webkit.rb +11 -0
  28. data/lib/capybara/webkit/matchers.rb +37 -0
  29. data/lib/capybara_webkit_builder.rb +68 -0
  30. data/spec/browser_spec.rb +248 -0
  31. data/spec/capybara_webkit_builder_spec.rb +37 -0
  32. data/spec/connection_spec.rb +54 -0
  33. data/spec/cookie_jar_spec.rb +48 -0
  34. data/spec/driver_rendering_spec.rb +80 -0
  35. data/spec/driver_resize_window_spec.rb +59 -0
  36. data/spec/driver_spec.rb +1552 -0
  37. data/spec/integration/driver_spec.rb +20 -0
  38. data/spec/integration/session_spec.rb +137 -0
  39. data/spec/self_signed_ssl_cert.rb +42 -0
  40. data/spec/spec_helper.rb +46 -0
  41. data/src/Body.h +12 -0
  42. data/src/ClearCookies.cpp +15 -0
  43. data/src/ClearCookies.h +11 -0
  44. data/src/Command.cpp +19 -0
  45. data/src/Command.h +31 -0
  46. data/src/CommandFactory.cpp +38 -0
  47. data/src/CommandFactory.h +16 -0
  48. data/src/CommandParser.cpp +76 -0
  49. data/src/CommandParser.h +33 -0
  50. data/src/Connection.cpp +71 -0
  51. data/src/Connection.h +37 -0
  52. data/src/ConsoleMessages.cpp +10 -0
  53. data/src/ConsoleMessages.h +12 -0
  54. data/src/CurrentUrl.cpp +68 -0
  55. data/src/CurrentUrl.h +16 -0
  56. data/src/Evaluate.cpp +84 -0
  57. data/src/Evaluate.h +22 -0
  58. data/src/Execute.cpp +16 -0
  59. data/src/Execute.h +12 -0
  60. data/src/Find.cpp +19 -0
  61. data/src/Find.h +13 -0
  62. data/src/FrameFocus.cpp +66 -0
  63. data/src/FrameFocus.h +28 -0
  64. data/src/GetCookies.cpp +20 -0
  65. data/src/GetCookies.h +14 -0
  66. data/src/Header.cpp +18 -0
  67. data/src/Header.h +11 -0
  68. data/src/Headers.cpp +10 -0
  69. data/src/Headers.h +12 -0
  70. data/src/IgnoreSslErrors.cpp +12 -0
  71. data/src/IgnoreSslErrors.h +12 -0
  72. data/src/JavascriptInvocation.cpp +14 -0
  73. data/src/JavascriptInvocation.h +19 -0
  74. data/src/NetworkAccessManager.cpp +29 -0
  75. data/src/NetworkAccessManager.h +19 -0
  76. data/src/NetworkCookieJar.cpp +101 -0
  77. data/src/NetworkCookieJar.h +15 -0
  78. data/src/Node.cpp +14 -0
  79. data/src/Node.h +13 -0
  80. data/src/NullCommand.cpp +10 -0
  81. data/src/NullCommand.h +11 -0
  82. data/src/PageLoadingCommand.cpp +46 -0
  83. data/src/PageLoadingCommand.h +40 -0
  84. data/src/Render.cpp +18 -0
  85. data/src/Render.h +12 -0
  86. data/src/RequestedUrl.cpp +12 -0
  87. data/src/RequestedUrl.h +12 -0
  88. data/src/Reset.cpp +29 -0
  89. data/src/Reset.h +15 -0
  90. data/src/ResizeWindow.cpp +16 -0
  91. data/src/ResizeWindow.h +12 -0
  92. data/src/Response.cpp +24 -0
  93. data/src/Response.h +15 -0
  94. data/src/Server.cpp +24 -0
  95. data/src/Server.h +21 -0
  96. data/src/SetCookie.cpp +16 -0
  97. data/src/SetCookie.h +11 -0
  98. data/src/SetProxy.cpp +22 -0
  99. data/src/SetProxy.h +11 -0
  100. data/src/SetSkipImageLoading.cpp +11 -0
  101. data/src/SetSkipImageLoading.h +11 -0
  102. data/src/Source.cpp +18 -0
  103. data/src/Source.h +19 -0
  104. data/src/Status.cpp +12 -0
  105. data/src/Status.h +12 -0
  106. data/src/UnsupportedContentHandler.cpp +32 -0
  107. data/src/UnsupportedContentHandler.h +18 -0
  108. data/src/Url.cpp +12 -0
  109. data/src/Url.h +12 -0
  110. data/src/Visit.cpp +12 -0
  111. data/src/Visit.h +12 -0
  112. data/src/WebPage.cpp +246 -0
  113. data/src/WebPage.h +58 -0
  114. data/src/body.cpp +10 -0
  115. data/src/capybara.js +315 -0
  116. data/src/find_command.h +30 -0
  117. data/src/main.cpp +31 -0
  118. data/src/webkit_server.pro +87 -0
  119. data/src/webkit_server.qrc +5 -0
  120. data/templates/Command.cpp +10 -0
  121. data/templates/Command.h +12 -0
  122. data/webkit_server.pro +4 -0
  123. metadata +300 -0
@@ -0,0 +1,248 @@
1
+ require 'spec_helper'
2
+ require 'self_signed_ssl_cert'
3
+ require 'stringio'
4
+ require 'capybara/driver/webkit/browser'
5
+ require 'capybara/driver/webkit/connection'
6
+ require 'socket'
7
+ require 'base64'
8
+
9
+ describe Capybara::Driver::Webkit::Browser do
10
+
11
+ let(:browser) { Capybara::Driver::Webkit::Browser.new(Capybara::Driver::Webkit::Connection.new) }
12
+ let(:browser_ignore_ssl_err) do
13
+ Capybara::Driver::Webkit::Browser.new(Capybara::Driver::Webkit::Connection.new).tap do |browser|
14
+ browser.ignore_ssl_errors
15
+ end
16
+ end
17
+ let(:browser_skip_images) do
18
+ Capybara::Driver::Webkit::Browser.new(Capybara::Driver::Webkit::Connection.new).tap do |browser|
19
+ browser.set_skip_image_loading(true)
20
+ end
21
+ end
22
+
23
+ context 'handling of SSL validation errors' do
24
+ before do
25
+ # set up minimal HTTPS server
26
+ @host = "127.0.0.1"
27
+ @server = TCPServer.new(@host, 0)
28
+ @port = @server.addr[1]
29
+
30
+ # set up SSL layer
31
+ ssl_serv = OpenSSL::SSL::SSLServer.new(@server, $openssl_self_signed_ctx)
32
+
33
+ @server_thread = Thread.new(ssl_serv) do |serv|
34
+ while conn = serv.accept do
35
+ # read request
36
+ request = []
37
+ until (line = conn.readline.strip).empty?
38
+ request << line
39
+ end
40
+
41
+ # write response
42
+ html = "<html><body>D'oh!</body></html>"
43
+ conn.write "HTTP/1.1 200 OK\r\n"
44
+ conn.write "Content-Type:text/html\r\n"
45
+ conn.write "Content-Length: %i\r\n" % html.size
46
+ conn.write "\r\n"
47
+ conn.write html
48
+ conn.close
49
+ end
50
+ end
51
+ end
52
+
53
+ after do
54
+ @server_thread.kill
55
+ @server.close
56
+ end
57
+
58
+ it "doesn't accept a self-signed certificate by default" do
59
+ lambda { browser.visit "https://#{@host}:#{@port}/" }.should raise_error
60
+ end
61
+
62
+ it 'accepts a self-signed certificate if configured to do so' do
63
+ browser_ignore_ssl_err.visit "https://#{@host}:#{@port}/"
64
+ end
65
+ end
66
+
67
+ context "skip image loading" do
68
+ before(:each) do
69
+ # set up minimal HTTP server
70
+ @host = "127.0.0.1"
71
+ @server = TCPServer.new(@host, 0)
72
+ @port = @server.addr[1]
73
+ @received_requests = []
74
+
75
+ @server_thread = Thread.new(@server) do |serv|
76
+ while conn = serv.accept do
77
+ # read request
78
+ request = []
79
+ until (line = conn.readline.strip).empty?
80
+ request << line
81
+ end
82
+
83
+ @received_requests << request.join("\n")
84
+
85
+ # write response
86
+ html = <<-HTML
87
+ <html>
88
+ <head>
89
+ <style>
90
+ body {
91
+ background-image: url(/path/to/bgimage);
92
+ }
93
+ </style>
94
+ </head>
95
+ <body>
96
+ <img src="/path/to/image"/>
97
+ </body>
98
+ </html>
99
+ HTML
100
+ conn.write "HTTP/1.1 200 OK\r\n"
101
+ conn.write "Content-Type:text/html\r\n"
102
+ conn.write "Content-Length: %i\r\n" % html.size
103
+ conn.write "\r\n"
104
+ conn.write html
105
+ conn.write("\r\n\r\n")
106
+ conn.close
107
+ end
108
+ end
109
+ end
110
+
111
+ after(:each) do
112
+ @server_thread.kill
113
+ @server.close
114
+ end
115
+
116
+ it "should load images in image tags by default" do
117
+ browser.visit("http://#{@host}:#{@port}/")
118
+ @received_requests.find {|r| r =~ %r{/path/to/image} }.should_not be_nil
119
+ end
120
+
121
+ it "should load images in css by default" do
122
+ browser.visit("http://#{@host}:#{@port}/")
123
+ @received_requests.find {|r| r =~ %r{/path/to/image} }.should_not be_nil
124
+ end
125
+
126
+ it "should not load images in image tags when skip_image_loading is true" do
127
+ browser_skip_images.visit("http://#{@host}:#{@port}/")
128
+ @received_requests.find {|r| r =~ %r{/path/to/image} }.should be_nil
129
+ end
130
+
131
+ it "should not load images in css when skip_image_loading is true" do
132
+ browser_skip_images.visit("http://#{@host}:#{@port}/")
133
+ @received_requests.find {|r| r =~ %r{/path/to/bgimage} }.should be_nil
134
+ end
135
+ end
136
+
137
+ describe "forking", :skip_on_windows => true do
138
+ it "only shuts down the server from the main process" do
139
+ browser.reset!
140
+ pid = fork {}
141
+ Process.wait(pid)
142
+ expect { browser.reset! }.not_to raise_error
143
+ end
144
+ end
145
+
146
+ describe '#set_proxy' do
147
+ before do
148
+ @host = '127.0.0.1'
149
+ @user = 'user'
150
+ @pass = 'secret'
151
+ @url = "http://example.org/"
152
+
153
+ @server = TCPServer.new(@host, 0)
154
+ @port = @server.addr[1]
155
+
156
+ @proxy_requests = []
157
+ @proxy = Thread.new(@server, @proxy_requests) do |serv, proxy_requests|
158
+ while conn = serv.accept do
159
+ # read request
160
+ request = []
161
+ until (line = conn.readline.strip).empty?
162
+ request << line
163
+ end
164
+
165
+ # send response
166
+ auth_header = request.find { |h| h =~ /Authorization:/i }
167
+ if auth_header || request[0].split(/\s+/)[1] =~ /^\//
168
+ html = "<html><body>D'oh!</body></html>"
169
+ conn.write "HTTP/1.1 200 OK\r\n"
170
+ conn.write "Content-Type:text/html\r\n"
171
+ conn.write "Content-Length: %i\r\n" % html.size
172
+ conn.write "\r\n"
173
+ conn.write html
174
+ conn.close
175
+ proxy_requests << request if auth_header
176
+ else
177
+ conn.write "HTTP/1.1 407 Proxy Auth Required\r\n"
178
+ conn.write "Proxy-Authenticate: Basic realm=\"Proxy\"\r\n"
179
+ conn.write "\r\n"
180
+ conn.close
181
+ proxy_requests << request
182
+ end
183
+ end
184
+ end
185
+
186
+ browser.set_proxy(:host => @host,
187
+ :port => @port,
188
+ :user => @user,
189
+ :pass => @pass)
190
+ browser.visit @url
191
+ @proxy_requests.size.should == 2
192
+ @request = @proxy_requests[-1]
193
+ end
194
+
195
+ after do
196
+ @proxy.kill
197
+ @server.close
198
+ end
199
+
200
+ it 'uses the HTTP proxy correctly' do
201
+ @request[0].should match /^GET\s+http:\/\/example.org\/\s+HTTP/i
202
+ @request.find { |header|
203
+ header =~ /^Host:\s+example.org$/i }.should_not be nil
204
+ end
205
+
206
+ it 'sends correct proxy authentication' do
207
+ auth_header = @request.find { |header|
208
+ header =~ /^Proxy-Authorization:\s+/i }
209
+ auth_header.should_not be nil
210
+
211
+ user, pass = Base64.decode64(auth_header.split(/\s+/)[-1]).split(":")
212
+ user.should == @user
213
+ pass.should == @pass
214
+ end
215
+
216
+ it "uses the proxies' response" do
217
+ browser.body.should include "D'oh!"
218
+ end
219
+
220
+ it 'uses original URL' do
221
+ browser.url.should == @url
222
+ end
223
+
224
+ it 'uses URLs changed by javascript' do
225
+ browser.execute_script "window.history.pushState('', '', '/blah')"
226
+ browser.requested_url.should == 'http://example.org/blah'
227
+ end
228
+
229
+ it 'is possible to disable proxy again' do
230
+ @proxy_requests.clear
231
+ browser.clear_proxy
232
+ browser.visit "http://#{@host}:#{@port}/"
233
+ @proxy_requests.size.should == 0
234
+ end
235
+ end
236
+
237
+ it "doesn't try to read an empty response" do
238
+ connection = stub("connection")
239
+ connection.stub(:puts)
240
+ connection.stub(:print)
241
+ connection.stub(:gets).and_return("ok\n", "0\n")
242
+ connection.stub(:read).and_raise(StandardError.new("tried to read empty response"))
243
+
244
+ browser = Capybara::Driver::Webkit::Browser.new(connection)
245
+
246
+ expect { browser.visit("/") }.not_to raise_error(/empty response/)
247
+ end
248
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require 'capybara_webkit_builder'
3
+
4
+ describe CapybaraWebkitBuilder do
5
+ let(:builder) { CapybaraWebkitBuilder }
6
+
7
+ it "will use the env variable for #make_bin" do
8
+ with_env_vars("MAKE" => "fake_make") do
9
+ builder.make_bin.should == "fake_make"
10
+ end
11
+ end
12
+
13
+ it "will use the env variable for #qmake_bin" do
14
+ with_env_vars("QMAKE" => "fake_qmake") do
15
+ builder.qmake_bin.should == "fake_qmake"
16
+ end
17
+ end
18
+
19
+ it "will use the env variable for #os_spec" do
20
+ with_env_vars("SPEC" => "fake_os_spec") do
21
+ builder.spec.should == "fake_os_spec"
22
+ end
23
+ end
24
+
25
+ it "defaults the #make_bin" do
26
+ builder.make_bin.should == 'make'
27
+ end
28
+
29
+ it "defaults the #qmake_bin" do
30
+ builder.qmake_bin.should == 'qmake'
31
+ end
32
+
33
+ it "defaults #spec to the #os_specs" do
34
+ builder.spec.should == builder.os_spec
35
+ end
36
+ end
37
+
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'capybara/driver/webkit/connection'
3
+
4
+ describe Capybara::Driver::Webkit::Connection do
5
+ it "boots a server to talk to" do
6
+ url = @rack_server.url("/")
7
+ connection.puts "Visit"
8
+ connection.puts 1
9
+ connection.puts url.to_s.bytesize
10
+ connection.print url
11
+ connection.gets.should == "ok\n"
12
+ connection.gets.should == "0\n"
13
+ connection.puts "Body"
14
+ connection.puts 0
15
+ connection.gets.should == "ok\n"
16
+ response_length = connection.gets.to_i
17
+ response = connection.read(response_length)
18
+ response.should include("Hey there")
19
+ end
20
+
21
+ it 'forwards stdout to the given IO object' do
22
+ io = StringIO.new
23
+ redirected_connection = Capybara::Driver::Webkit::Connection.new(:stdout => io)
24
+ script = 'console.log("hello world")'
25
+ redirected_connection.puts "Execute"
26
+ redirected_connection.puts 1
27
+ redirected_connection.puts script.to_s.bytesize
28
+ redirected_connection.print script
29
+ sleep(0.5)
30
+ io.string.should include "hello world\n"
31
+ end
32
+
33
+ it "returns the server port" do
34
+ connection.port.should be_between 0x400, 0xffff
35
+ end
36
+
37
+ it "chooses a new port number for a new connection" do
38
+ new_connection = Capybara::Driver::Webkit::Connection.new
39
+ new_connection.port.should_not == connection.port
40
+ end
41
+
42
+ let(:connection) { Capybara::Driver::Webkit::Connection.new }
43
+
44
+ before(:all) do
45
+ @app = lambda do |env|
46
+ body = "<html><body>Hey there</body></html>"
47
+ [200,
48
+ { 'Content-Type' => 'text/html', 'Content-Length' => body.size.to_s },
49
+ [body]]
50
+ end
51
+ @rack_server = Capybara::Server.new(@app)
52
+ @rack_server.boot
53
+ end
54
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+ require 'capybara/driver/webkit/cookie_jar'
3
+
4
+ describe Capybara::Driver::Webkit::CookieJar do
5
+ let(:browser) {
6
+ browser = double("Browser")
7
+ browser.stub(:get_cookies) { [
8
+ "cookie1=1; domain=.example.org; path=/",
9
+ "cookie1=2; domain=.example.org; path=/dir1/",
10
+ "cookie1=3; domain=.facebook.com; path=/",
11
+ "cookie2=4; domain=.sub1.example.org; path=/",
12
+ ] }
13
+ browser
14
+ }
15
+
16
+ subject { Capybara::Driver::Webkit::CookieJar.new(browser) }
17
+
18
+ describe "#find" do
19
+ it "returns a cookie object" do
20
+ subject.find("cookie1", "www.facebook.com").domain.should == ".facebook.com"
21
+ end
22
+
23
+ it "returns the right cookie for every given domain/path" do
24
+ subject.find("cookie1", "example.org").value.should == "1"
25
+ subject.find("cookie1", "www.facebook.com").value.should == "3"
26
+ subject.find("cookie2", "sub1.example.org").value.should == "4"
27
+ end
28
+
29
+ it "does not return a cookie from other domain" do
30
+ subject.find("cookie2", "www.example.org").should == nil
31
+ end
32
+
33
+ it "respects path precedence rules" do
34
+ subject.find("cookie1", "www.example.org").value.should == "1"
35
+ subject.find("cookie1", "www.example.org", "/dir1/123").value.should == "2"
36
+ end
37
+ end
38
+
39
+ describe "#[]" do
40
+ it "returns the first matching cookie's value" do
41
+ subject["cookie1", "example.org"].should == "1"
42
+ end
43
+
44
+ it "returns nil if no cookie is found" do
45
+ subject["notexisting"].should == nil
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+ require 'capybara/driver/webkit'
3
+ require 'mini_magick'
4
+
5
+ describe Capybara::Driver::Webkit, "rendering an image" do
6
+
7
+ before(:all) do
8
+ # Set up the tmp directory and file name
9
+ tmp_dir = File.join(PROJECT_ROOT, 'tmp')
10
+ FileUtils.mkdir_p tmp_dir
11
+ @file_name = File.join(tmp_dir, 'render-test.png')
12
+
13
+ app = lambda do |env|
14
+ body = <<-HTML
15
+ <html>
16
+ <body>
17
+ <h1>Hello World</h1>
18
+ </body>
19
+ </html>
20
+ HTML
21
+ [200,
22
+ { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
23
+ [body]]
24
+ end
25
+
26
+ @driver = Capybara::Driver::Webkit.new(app, :browser => $webkit_browser)
27
+ @driver.visit("/hello/world?success=true")
28
+ end
29
+
30
+ after(:all) { @driver.reset! }
31
+
32
+ def render(options)
33
+ FileUtils.rm_f @file_name
34
+ @driver.render @file_name, options
35
+
36
+ @image = MiniMagick::Image.open @file_name
37
+ end
38
+
39
+ context "with default options" do
40
+ before(:all){ render({}) }
41
+
42
+ it "should be a PNG" do
43
+ @image[:format].should == "PNG"
44
+ end
45
+
46
+ it "width default to 1000px (with 15px less for the scrollbar)" do
47
+ @image[:width].should be < 1001
48
+ @image[:width].should be > 1000-17
49
+ end
50
+
51
+ it "height should be at least 10px" do
52
+ @image[:height].should >= 10
53
+ end
54
+ end
55
+
56
+ context "with dimensions set larger than necessary" do
57
+ before(:all){ render(:width => 500, :height => 400) }
58
+
59
+ it "width should match the width given" do
60
+ @image[:width].should == 500
61
+ end
62
+
63
+ it "height should match the height given" do
64
+ @image[:height].should > 10
65
+ end
66
+ end
67
+
68
+ context "with dimensions set smaller than the document's default" do
69
+ before(:all){ render(:width => 50, :height => 10) }
70
+
71
+ it "width should be greater than the width given" do
72
+ @image[:width].should > 50
73
+ end
74
+
75
+ it "height should be greater than the height given" do
76
+ @image[:height].should > 10
77
+ end
78
+ end
79
+
80
+ end