otherinbox-capybara-webkit 0.12.0 → 0.12.0.1
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/GOALS +9 -0
- data/README.md +1 -1
- data/capybara-webkit.gemspec +1 -1
- data/lib/capybara/webkit.rb +11 -4
- data/lib/capybara/{driver/webkit → webkit}/browser.rb +27 -3
- data/lib/capybara/{driver/webkit → webkit}/connection.rb +45 -47
- data/lib/capybara/{driver/webkit → webkit}/cookie_jar.rb +1 -1
- data/lib/capybara/webkit/driver.rb +150 -0
- data/lib/capybara/webkit/errors.rb +10 -0
- data/lib/capybara/{driver/webkit → webkit}/node.rb +2 -2
- data/lib/capybara/{driver/webkit → webkit}/socket_debugger.rb +1 -1
- data/lib/capybara/{driver/webkit → webkit}/version.rb +1 -1
- data/lib/capybara_webkit_builder.rb +17 -3
- data/spec/browser_spec.rb +38 -25
- data/spec/connection_spec.rb +5 -5
- data/spec/cookie_jar_spec.rb +3 -3
- data/spec/driver_rendering_spec.rb +19 -26
- data/spec/driver_resize_window_spec.rb +3 -3
- data/spec/driver_spec.rb +907 -829
- data/spec/integration/driver_spec.rb +4 -3
- data/spec/spec_helper.rb +14 -6
- data/spec/support/app_runner.rb +91 -0
- data/src/Authenticate.cpp +18 -0
- data/src/Authenticate.h +12 -0
- data/src/Body.h +3 -5
- data/src/ClearCookies.cpp +3 -5
- data/src/ClearCookies.h +3 -5
- data/src/Command.cpp +4 -15
- data/src/Command.h +3 -14
- data/src/CommandFactory.cpp +10 -6
- data/src/CommandFactory.h +3 -2
- data/src/CommandParser.cpp +1 -1
- data/src/Connection.cpp +22 -11
- data/src/Connection.h +4 -2
- data/src/ConsoleMessages.cpp +2 -1
- data/src/ConsoleMessages.h +3 -5
- data/src/CurrentUrl.cpp +2 -1
- data/src/CurrentUrl.h +3 -5
- data/src/EnableLogging.cpp +10 -0
- data/src/EnableLogging.h +12 -0
- data/src/Evaluate.cpp +2 -1
- data/src/Evaluate.h +3 -5
- data/src/Execute.cpp +2 -1
- data/src/Execute.h +3 -5
- data/src/Find.cpp +3 -2
- data/src/Find.h +3 -5
- data/src/FrameFocus.cpp +3 -2
- data/src/FrameFocus.h +3 -4
- data/src/GetCookies.cpp +3 -4
- data/src/GetCookies.h +3 -5
- data/src/GetWindowHandle.cpp +11 -0
- data/src/GetWindowHandle.h +10 -0
- data/src/GetWindowHandles.cpp +20 -0
- data/src/GetWindowHandles.h +10 -0
- data/src/Header.cpp +2 -1
- data/src/Header.h +3 -5
- data/src/Headers.cpp +2 -1
- data/src/Headers.h +3 -5
- data/src/IgnoreSslErrors.cpp +4 -3
- data/src/IgnoreSslErrors.h +3 -5
- data/src/JavascriptInvocation.cpp +1 -1
- data/src/JavascriptInvocation.h +1 -1
- data/src/NetworkAccessManager.cpp +19 -1
- data/src/NetworkAccessManager.h +10 -0
- data/src/Node.cpp +6 -1
- data/src/Node.h +4 -5
- data/src/NullCommand.cpp +5 -2
- data/src/NullCommand.h +4 -3
- data/src/PageLoadingCommand.cpp +12 -7
- data/src/PageLoadingCommand.h +6 -9
- data/src/Render.cpp +2 -1
- data/src/Render.h +3 -5
- data/src/RequestedUrl.cpp +2 -1
- data/src/RequestedUrl.h +3 -5
- data/src/Reset.cpp +3 -17
- data/src/Reset.h +3 -8
- data/src/ResizeWindow.cpp +2 -1
- data/src/ResizeWindow.h +3 -5
- data/src/Server.cpp +2 -3
- data/src/Server.h +0 -2
- data/src/SetCookie.cpp +3 -4
- data/src/SetCookie.h +3 -5
- data/src/SetProxy.cpp +2 -1
- data/src/SetProxy.h +3 -5
- data/src/SetSkipImageLoading.cpp +3 -2
- data/src/SetSkipImageLoading.h +3 -5
- data/src/SocketCommand.cpp +21 -0
- data/src/SocketCommand.h +29 -0
- data/src/Source.cpp +2 -1
- data/src/Source.h +3 -4
- data/src/Status.cpp +2 -1
- data/src/Status.h +3 -5
- data/src/UnsupportedContentHandler.cpp +1 -1
- data/src/Url.cpp +2 -1
- data/src/Url.h +3 -5
- data/src/Visit.cpp +3 -2
- data/src/Visit.h +3 -5
- data/src/WebPage.cpp +86 -39
- data/src/WebPage.h +22 -8
- data/src/WebPageManager.cpp +117 -0
- data/src/WebPageManager.h +56 -0
- data/src/WindowFocus.cpp +32 -0
- data/src/WindowFocus.h +15 -0
- data/src/body.cpp +2 -1
- data/src/find_command.h +6 -2
- data/src/webkit_server.pro +14 -0
- data/templates/Command.cpp +2 -4
- data/templates/Command.h +3 -3
- metadata +29 -10
- data/lib/capybara/driver/webkit.rb +0 -135
@@ -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
|
-
|
47
|
+
sh("#{qmake_bin} -spec #{spec}")
|
34
48
|
end
|
35
49
|
|
36
50
|
def qmake
|
37
|
-
|
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
|
-
|
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)
|
data/spec/browser_spec.rb
CHANGED
@@ -1,21 +1,20 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'self_signed_ssl_cert'
|
3
3
|
require 'stringio'
|
4
|
-
require 'capybara/
|
5
|
-
require 'capybara/driver/webkit/connection'
|
4
|
+
require 'capybara/webkit/driver'
|
6
5
|
require 'socket'
|
7
6
|
require 'base64'
|
8
7
|
|
9
|
-
describe Capybara::
|
8
|
+
describe Capybara::Webkit::Browser do
|
10
9
|
|
11
|
-
let(:browser) { Capybara::
|
10
|
+
let(:browser) { Capybara::Webkit::Browser.new(Capybara::Webkit::Connection.new) }
|
12
11
|
let(:browser_ignore_ssl_err) do
|
13
|
-
Capybara::
|
12
|
+
Capybara::Webkit::Browser.new(Capybara::Webkit::Connection.new).tap do |browser|
|
14
13
|
browser.ignore_ssl_errors
|
15
14
|
end
|
16
15
|
end
|
17
16
|
let(:browser_skip_images) do
|
18
|
-
Capybara::
|
17
|
+
Capybara::Webkit::Browser.new(Capybara::Webkit::Connection.new).tap do |browser|
|
19
18
|
browser.set_skip_image_loading(true)
|
20
19
|
end
|
21
20
|
end
|
@@ -62,6 +61,18 @@ describe Capybara::Driver::Webkit::Browser do
|
|
62
61
|
it 'accepts a self-signed certificate if configured to do so' do
|
63
62
|
browser_ignore_ssl_err.visit "https://#{@host}:#{@port}/"
|
64
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
|
65
76
|
end
|
66
77
|
|
67
78
|
context "skip image loading" do
|
@@ -72,18 +83,19 @@ describe Capybara::Driver::Webkit::Browser do
|
|
72
83
|
@port = @server.addr[1]
|
73
84
|
@received_requests = []
|
74
85
|
|
75
|
-
@server_thread = Thread.new
|
76
|
-
while conn =
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
82
94
|
|
83
|
-
|
95
|
+
@received_requests << request.join("\n")
|
84
96
|
|
85
|
-
|
86
|
-
|
97
|
+
# write response
|
98
|
+
html = <<-HTML
|
87
99
|
<html>
|
88
100
|
<head>
|
89
101
|
<style>
|
@@ -96,14 +108,15 @@ describe Capybara::Driver::Webkit::Browser do
|
|
96
108
|
<img src="/path/to/image"/>
|
97
109
|
</body>
|
98
110
|
</html>
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
107
120
|
end
|
108
121
|
end
|
109
122
|
end
|
@@ -241,7 +254,7 @@ describe Capybara::Driver::Webkit::Browser do
|
|
241
254
|
connection.stub(:gets).and_return("ok\n", "0\n")
|
242
255
|
connection.stub(:read).and_raise(StandardError.new("tried to read empty response"))
|
243
256
|
|
244
|
-
browser = Capybara::
|
257
|
+
browser = Capybara::Webkit::Browser.new(connection)
|
245
258
|
|
246
259
|
expect { browser.visit("/") }.not_to raise_error(/empty response/)
|
247
260
|
end
|
data/spec/connection_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'capybara/
|
2
|
+
require 'capybara/webkit/connection'
|
3
3
|
|
4
|
-
describe Capybara::
|
4
|
+
describe Capybara::Webkit::Connection do
|
5
5
|
it "boots a server to talk to" do
|
6
6
|
url = @rack_server.url("/")
|
7
7
|
connection.puts "Visit"
|
@@ -20,7 +20,7 @@ describe Capybara::Driver::Webkit::Connection do
|
|
20
20
|
|
21
21
|
it 'forwards stdout to the given IO object' do
|
22
22
|
io = StringIO.new
|
23
|
-
redirected_connection = Capybara::
|
23
|
+
redirected_connection = Capybara::Webkit::Connection.new(:stdout => io)
|
24
24
|
script = 'console.log("hello world")'
|
25
25
|
redirected_connection.puts "Execute"
|
26
26
|
redirected_connection.puts 1
|
@@ -35,11 +35,11 @@ describe Capybara::Driver::Webkit::Connection do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
it "chooses a new port number for a new connection" do
|
38
|
-
new_connection = Capybara::
|
38
|
+
new_connection = Capybara::Webkit::Connection.new
|
39
39
|
new_connection.port.should_not == connection.port
|
40
40
|
end
|
41
41
|
|
42
|
-
let(:connection) { Capybara::
|
42
|
+
let(:connection) { Capybara::Webkit::Connection.new }
|
43
43
|
|
44
44
|
before(:all) do
|
45
45
|
@app = lambda do |env|
|
data/spec/cookie_jar_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'capybara/
|
2
|
+
require 'capybara/webkit/cookie_jar'
|
3
3
|
|
4
|
-
describe Capybara::
|
4
|
+
describe Capybara::Webkit::CookieJar do
|
5
5
|
let(:browser) {
|
6
6
|
browser = double("Browser")
|
7
7
|
browser.stub(:get_cookies) { [
|
@@ -13,7 +13,7 @@ describe Capybara::Driver::Webkit::CookieJar do
|
|
13
13
|
browser
|
14
14
|
}
|
15
15
|
|
16
|
-
subject { Capybara::
|
16
|
+
subject { Capybara::Webkit::CookieJar.new(browser) }
|
17
17
|
|
18
18
|
describe "#find" do
|
19
19
|
it "returns a cookie object" do
|
@@ -1,43 +1,37 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'capybara/driver
|
2
|
+
require 'capybara/webkit/driver'
|
3
3
|
require 'mini_magick'
|
4
4
|
|
5
|
-
describe Capybara::Driver
|
5
|
+
describe Capybara::Webkit::Driver, "rendering an image" do
|
6
|
+
include AppRunner
|
7
|
+
|
8
|
+
let(:driver) do
|
9
|
+
driver_for_html(<<-HTML)
|
10
|
+
<html>
|
11
|
+
<body>
|
12
|
+
<h1>Hello World</h1>
|
13
|
+
</body>
|
14
|
+
</html>
|
15
|
+
HTML
|
16
|
+
end
|
6
17
|
|
7
|
-
before(:
|
18
|
+
before(:each) do
|
8
19
|
# Set up the tmp directory and file name
|
9
20
|
tmp_dir = File.join(PROJECT_ROOT, 'tmp')
|
10
21
|
FileUtils.mkdir_p tmp_dir
|
11
22
|
@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")
|
23
|
+
driver.visit '/'
|
28
24
|
end
|
29
25
|
|
30
|
-
after(:all) { @driver.reset! }
|
31
|
-
|
32
26
|
def render(options)
|
33
27
|
FileUtils.rm_f @file_name
|
34
|
-
|
28
|
+
driver.render @file_name, options
|
35
29
|
|
36
30
|
@image = MiniMagick::Image.open @file_name
|
37
31
|
end
|
38
32
|
|
39
33
|
context "with default options" do
|
40
|
-
before
|
34
|
+
before { render({}) }
|
41
35
|
|
42
36
|
it "should be a PNG" do
|
43
37
|
@image[:format].should == "PNG"
|
@@ -54,7 +48,7 @@ describe Capybara::Driver::Webkit, "rendering an image" do
|
|
54
48
|
end
|
55
49
|
|
56
50
|
context "with dimensions set larger than necessary" do
|
57
|
-
before
|
51
|
+
before { render(:width => 500, :height => 400) }
|
58
52
|
|
59
53
|
it "width should match the width given" do
|
60
54
|
@image[:width].should == 500
|
@@ -66,7 +60,7 @@ describe Capybara::Driver::Webkit, "rendering an image" do
|
|
66
60
|
end
|
67
61
|
|
68
62
|
context "with dimensions set smaller than the document's default" do
|
69
|
-
before
|
63
|
+
before { render(:width => 50, :height => 10) }
|
70
64
|
|
71
65
|
it "width should be greater than the width given" do
|
72
66
|
@image[:width].should > 50
|
@@ -76,5 +70,4 @@ describe Capybara::Driver::Webkit, "rendering an image" do
|
|
76
70
|
@image[:height].should > 10
|
77
71
|
end
|
78
72
|
end
|
79
|
-
|
80
73
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'capybara/driver
|
2
|
+
require 'capybara/webkit/driver'
|
3
3
|
|
4
|
-
describe Capybara::Driver
|
4
|
+
describe Capybara::Webkit::Driver, "#resize_window(width, height)" do
|
5
5
|
|
6
6
|
before(:all) do
|
7
7
|
app = lambda do |env|
|
@@ -27,7 +27,7 @@ describe Capybara::Driver::Webkit, "#resize_window(width, height)" do
|
|
27
27
|
]
|
28
28
|
end
|
29
29
|
|
30
|
-
@driver = Capybara::Driver
|
30
|
+
@driver = Capybara::Webkit::Driver.new(app, :browser => $webkit_browser)
|
31
31
|
end
|
32
32
|
|
33
33
|
DEFAULT_DIMENTIONS = "[1680x1050]"
|
data/spec/driver_spec.rb
CHANGED
@@ -1,117 +1,144 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'capybara/driver
|
2
|
+
require 'capybara/webkit/driver'
|
3
|
+
require 'base64'
|
3
4
|
|
4
|
-
describe Capybara::Driver
|
5
|
-
|
6
|
-
before { subject.visit("/hello/world?success=true") }
|
7
|
-
after { subject.reset! }
|
5
|
+
describe Capybara::Webkit::Driver do
|
6
|
+
include AppRunner
|
8
7
|
|
9
8
|
context "iframe app" do
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
9
|
+
let(:driver) do
|
10
|
+
driver_for_app do
|
11
|
+
get "/" do
|
12
|
+
if in_iframe_request?
|
13
|
+
p_id = "farewell"
|
14
|
+
msg = "goodbye"
|
15
|
+
iframe = nil
|
16
|
+
else
|
17
|
+
p_id = "greeting"
|
18
|
+
msg = "hello"
|
19
|
+
iframe = "<iframe id=\"f\" src=\"/?iframe=true\"></iframe>"
|
20
|
+
end
|
21
|
+
<<-HTML
|
22
|
+
<html>
|
23
|
+
<head>
|
24
|
+
<style type="text/css">
|
25
|
+
#display_none { display: none }
|
26
|
+
</style>
|
27
|
+
</head>
|
28
|
+
<body>
|
29
|
+
#{iframe}
|
30
|
+
<script type="text/javascript">
|
31
|
+
document.write("<p id='#{p_id}'>#{msg}</p>");
|
32
|
+
</script>
|
33
|
+
</body>
|
34
|
+
</html>
|
35
|
+
HTML
|
36
|
+
end
|
37
|
+
|
38
|
+
def in_iframe_request?
|
39
|
+
params[:iframe] == "true"
|
23
40
|
end
|
24
|
-
body = <<-HTML
|
25
|
-
<html>
|
26
|
-
<head>
|
27
|
-
<style type="text/css">
|
28
|
-
#display_none { display: none }
|
29
|
-
</style>
|
30
|
-
</head>
|
31
|
-
<body>
|
32
|
-
#{iframe}
|
33
|
-
<script type="text/javascript">
|
34
|
-
document.write("<p id='#{p_id}'>#{msg}</p>");
|
35
|
-
</script>
|
36
|
-
</body>
|
37
|
-
</html>
|
38
|
-
HTML
|
39
|
-
[200,
|
40
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
41
|
-
[body]]
|
42
41
|
end
|
43
42
|
end
|
44
43
|
|
44
|
+
before do
|
45
|
+
driver.visit("/")
|
46
|
+
end
|
47
|
+
|
45
48
|
it "finds frames by index" do
|
46
|
-
|
47
|
-
|
49
|
+
driver.within_frame(0) do
|
50
|
+
driver.find("//*[contains(., 'goodbye')]").should_not be_empty
|
48
51
|
end
|
49
52
|
end
|
50
53
|
|
51
54
|
it "finds frames by id" do
|
52
|
-
|
53
|
-
|
55
|
+
driver.within_frame("f") do
|
56
|
+
driver.find("//*[contains(., 'goodbye')]").should_not be_empty
|
54
57
|
end
|
55
58
|
end
|
56
59
|
|
57
60
|
it "raises error for missing frame by index" do
|
58
|
-
expect {
|
59
|
-
to raise_error(Capybara::
|
61
|
+
expect { driver.within_frame(1) { } }.
|
62
|
+
to raise_error(Capybara::Webkit::InvalidResponseError)
|
60
63
|
end
|
61
64
|
|
62
65
|
it "raise_error for missing frame by id" do
|
63
|
-
expect {
|
64
|
-
to raise_error(Capybara::
|
66
|
+
expect { driver.within_frame("foo") { } }.
|
67
|
+
to raise_error(Capybara::Webkit::InvalidResponseError)
|
65
68
|
end
|
66
69
|
|
67
70
|
it "returns an attribute's value" do
|
68
|
-
|
69
|
-
|
71
|
+
driver.within_frame("f") do
|
72
|
+
driver.find("//p").first["id"].should == "farewell"
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
73
76
|
it "returns a node's text" do
|
74
|
-
|
75
|
-
|
77
|
+
driver.within_frame("f") do
|
78
|
+
driver.find("//p").first.text.should == "goodbye"
|
76
79
|
end
|
77
80
|
end
|
78
81
|
|
79
82
|
it "returns the current URL" do
|
80
|
-
|
81
|
-
|
82
|
-
subject.current_url.should == "http://127.0.0.1:#{port}/?iframe=true"
|
83
|
+
driver.within_frame("f") do
|
84
|
+
driver.current_url.should == driver_url(driver, "/?iframe=true")
|
83
85
|
end
|
84
86
|
end
|
85
87
|
|
86
88
|
it "returns the source code for the page" do
|
87
|
-
|
88
|
-
|
89
|
+
driver.within_frame("f") do
|
90
|
+
driver.source.should =~ %r{<html>.*farewell.*}m
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
92
94
|
it "evaluates Javascript" do
|
93
|
-
|
94
|
-
result =
|
95
|
+
driver.within_frame("f") do
|
96
|
+
result = driver.evaluate_script(%<document.getElementById('farewell').innerText>)
|
95
97
|
result.should == "goodbye"
|
96
98
|
end
|
97
99
|
end
|
98
100
|
|
99
101
|
it "executes Javascript" do
|
100
|
-
|
101
|
-
|
102
|
-
|
102
|
+
driver.within_frame("f") do
|
103
|
+
driver.execute_script(%<document.getElementById('farewell').innerHTML = 'yo'>)
|
104
|
+
driver.find("//p[contains(., 'yo')]").should_not be_empty
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "error iframe app" do
|
110
|
+
let(:driver) do
|
111
|
+
driver_for_app do
|
112
|
+
get "/inner-not-found" do
|
113
|
+
invalid_response
|
114
|
+
end
|
115
|
+
|
116
|
+
get "/" do
|
117
|
+
<<-HTML
|
118
|
+
<html>
|
119
|
+
<body>
|
120
|
+
<iframe src="/inner-not-found"></iframe>
|
121
|
+
</body>
|
122
|
+
</html>
|
123
|
+
HTML
|
124
|
+
end
|
103
125
|
end
|
104
126
|
end
|
127
|
+
|
128
|
+
it "raises error whose message references the actual missing url" do
|
129
|
+
expect { driver.visit("/") }.to raise_error(Capybara::Webkit::InvalidResponseError, /inner-not-found/)
|
130
|
+
end
|
105
131
|
end
|
106
132
|
|
107
133
|
context "redirect app" do
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
134
|
+
let(:driver) do
|
135
|
+
driver_for_app do
|
136
|
+
get '/target' do
|
137
|
+
"<p>#{env['CONTENT_TYPE']}</p>"
|
138
|
+
end
|
139
|
+
|
140
|
+
get '/form' do
|
141
|
+
<<-HTML
|
115
142
|
<html>
|
116
143
|
<body>
|
117
144
|
<form action="/redirect" method="POST" enctype="multipart/form-data">
|
@@ -120,369 +147,359 @@ describe Capybara::Driver::Webkit do
|
|
120
147
|
</body>
|
121
148
|
</html>
|
122
149
|
HTML
|
123
|
-
|
124
|
-
|
125
|
-
|
150
|
+
end
|
151
|
+
|
152
|
+
post '/redirect' do
|
153
|
+
redirect '/target'
|
126
154
|
end
|
127
155
|
end
|
128
156
|
end
|
129
157
|
|
130
158
|
it "should redirect without content type" do
|
131
|
-
|
132
|
-
|
133
|
-
|
159
|
+
driver.visit("/form")
|
160
|
+
driver.find("//input").first.click
|
161
|
+
driver.find("//p").first.text.should == ""
|
134
162
|
end
|
135
163
|
|
136
164
|
it "returns the current URL when changed by pushState after a redirect" do
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
subject.current_url.should == "http://127.0.0.1:#{port}/pushed-after-redirect"
|
165
|
+
driver.visit("/redirect-me")
|
166
|
+
driver.execute_script("window.history.pushState({}, '', '/pushed-after-redirect')")
|
167
|
+
driver.current_url.should == driver_url(driver, "/pushed-after-redirect")
|
141
168
|
end
|
142
169
|
|
143
170
|
it "returns the current URL when changed by replaceState after a redirect" do
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
subject.current_url.should == "http://127.0.0.1:#{port}/replaced-after-redirect"
|
171
|
+
driver.visit("/redirect-me")
|
172
|
+
driver.execute_script("window.history.replaceState({}, '', '/replaced-after-redirect')")
|
173
|
+
driver.current_url.should == driver_url(driver, "/replaced-after-redirect")
|
148
174
|
end
|
149
175
|
end
|
150
176
|
|
151
177
|
context "css app" do
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
178
|
+
let(:driver) do
|
179
|
+
driver_for_app do
|
180
|
+
get "/" do
|
181
|
+
headers "Content-Type" => "text/css"
|
182
|
+
"css"
|
183
|
+
end
|
156
184
|
end
|
157
|
-
subject.visit("/")
|
158
185
|
end
|
159
186
|
|
187
|
+
before { driver.visit("/") }
|
188
|
+
|
160
189
|
it "renders unsupported content types gracefully" do
|
161
|
-
|
190
|
+
driver.body.should =~ /css/
|
162
191
|
end
|
163
192
|
|
164
193
|
it "sets the response headers with respect to the unsupported request" do
|
165
|
-
|
194
|
+
driver.response_headers["Content-Type"].should == "text/css"
|
166
195
|
end
|
167
196
|
end
|
168
197
|
|
169
198
|
context "hello app" do
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
<
|
174
|
-
<
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
<
|
180
|
-
|
181
|
-
<div id="
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
<
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
HTML
|
192
|
-
[200,
|
193
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
194
|
-
[body]]
|
195
|
-
end
|
199
|
+
let(:driver) do
|
200
|
+
driver_for_html(<<-HTML)
|
201
|
+
<html>
|
202
|
+
<head>
|
203
|
+
<style type="text/css">
|
204
|
+
#display_none { display: none }
|
205
|
+
</style>
|
206
|
+
</head>
|
207
|
+
<body>
|
208
|
+
<div class='normalize'>Spaces not normalized </div>
|
209
|
+
<div id="display_none">
|
210
|
+
<div id="invisible">Can't see me</div>
|
211
|
+
</div>
|
212
|
+
<input type="text" disabled="disabled"/>
|
213
|
+
<input id="checktest" type="checkbox" checked="checked"/>
|
214
|
+
<script type="text/javascript">
|
215
|
+
document.write("<p id='greeting'>he" + "llo</p>");
|
216
|
+
</script>
|
217
|
+
</body>
|
218
|
+
</html>
|
219
|
+
HTML
|
196
220
|
end
|
197
221
|
|
222
|
+
before { driver.visit("/") }
|
223
|
+
|
198
224
|
it "handles anchor tags" do
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
225
|
+
driver.visit("#test")
|
226
|
+
driver.find("//*[contains(., 'hello')]").should_not be_empty
|
227
|
+
driver.visit("#test")
|
228
|
+
driver.find("//*[contains(., 'hello')]").should_not be_empty
|
203
229
|
end
|
204
230
|
|
205
231
|
it "finds content after loading a URL" do
|
206
|
-
|
232
|
+
driver.find("//*[contains(., 'hello')]").should_not be_empty
|
207
233
|
end
|
208
234
|
|
209
235
|
it "has an empty page after reseting" do
|
210
|
-
|
211
|
-
|
236
|
+
driver.reset!
|
237
|
+
driver.find("//*[contains(., 'hello')]").should be_empty
|
212
238
|
end
|
213
239
|
|
214
|
-
it "has a location
|
215
|
-
|
216
|
-
|
240
|
+
it "has a blank location after reseting" do
|
241
|
+
driver.reset!
|
242
|
+
driver.current_url.should == ""
|
217
243
|
end
|
218
244
|
|
219
245
|
it "raises an error for an invalid xpath query" do
|
220
|
-
expect {
|
221
|
-
to raise_error(Capybara::
|
246
|
+
expect { driver.find("totally invalid salad") }.
|
247
|
+
to raise_error(Capybara::Webkit::InvalidResponseError, /xpath/i)
|
222
248
|
end
|
223
249
|
|
224
250
|
it "returns an attribute's value" do
|
225
|
-
|
251
|
+
driver.find("//p").first["id"].should == "greeting"
|
226
252
|
end
|
227
253
|
|
228
254
|
it "parses xpath with quotes" do
|
229
|
-
|
255
|
+
driver.find('//*[contains(., "hello")]').should_not be_empty
|
230
256
|
end
|
231
257
|
|
232
258
|
it "returns a node's text" do
|
233
|
-
|
259
|
+
driver.find("//p").first.text.should == "hello"
|
234
260
|
end
|
235
261
|
|
236
262
|
it "normalizes a node's text" do
|
237
|
-
|
263
|
+
driver.find("//div[contains(@class, 'normalize')]").first.text.should == "Spaces not normalized"
|
238
264
|
end
|
239
265
|
|
240
266
|
it "returns the current URL" do
|
241
|
-
|
242
|
-
|
267
|
+
driver.visit "/hello/world?success=true"
|
268
|
+
driver.current_url.should == driver_url(driver, "/hello/world?success=true")
|
243
269
|
end
|
244
270
|
|
245
271
|
it "returns the current URL when changed by pushState" do
|
246
|
-
|
247
|
-
|
248
|
-
subject.current_url.should == "http://127.0.0.1:#{port}/pushed"
|
272
|
+
driver.execute_script("window.history.pushState({}, '', '/pushed')")
|
273
|
+
driver.current_url.should == driver_url(driver, "/pushed")
|
249
274
|
end
|
250
275
|
|
251
276
|
it "returns the current URL when changed by replaceState" do
|
252
|
-
|
253
|
-
|
254
|
-
subject.current_url.should == "http://127.0.0.1:#{port}/replaced"
|
277
|
+
driver.execute_script("window.history.replaceState({}, '', '/replaced')")
|
278
|
+
driver.current_url.should == driver_url(driver, "/replaced")
|
255
279
|
end
|
256
280
|
|
257
281
|
it "does not double-encode URLs" do
|
258
|
-
|
259
|
-
|
282
|
+
driver.visit("/hello/world?success=%25true")
|
283
|
+
driver.current_url.should =~ /success=\%25true/
|
260
284
|
end
|
261
285
|
|
262
286
|
it "visits a page with an anchor" do
|
263
|
-
|
264
|
-
|
287
|
+
driver.visit("/hello#display_none")
|
288
|
+
driver.current_url.should =~ /hello#display_none/
|
265
289
|
end
|
266
290
|
|
267
291
|
it "returns the source code for the page" do
|
268
|
-
|
292
|
+
driver.source.should =~ %r{<html>.*greeting.*}m
|
269
293
|
end
|
270
294
|
|
271
295
|
it "evaluates Javascript and returns a string" do
|
272
|
-
result =
|
296
|
+
result = driver.evaluate_script(%<document.getElementById('greeting').innerText>)
|
273
297
|
result.should == "hello"
|
274
298
|
end
|
275
299
|
|
276
300
|
it "evaluates Javascript and returns an array" do
|
277
|
-
result =
|
301
|
+
result = driver.evaluate_script(%<["hello", "world"]>)
|
278
302
|
result.should == %w(hello world)
|
279
303
|
end
|
280
304
|
|
281
305
|
it "evaluates Javascript and returns an int" do
|
282
|
-
result =
|
306
|
+
result = driver.evaluate_script(%<123>)
|
283
307
|
result.should == 123
|
284
308
|
end
|
285
309
|
|
286
310
|
it "evaluates Javascript and returns a float" do
|
287
|
-
result =
|
311
|
+
result = driver.evaluate_script(%<1.5>)
|
288
312
|
result.should == 1.5
|
289
313
|
end
|
290
314
|
|
291
315
|
it "evaluates Javascript and returns null" do
|
292
|
-
result =
|
316
|
+
result = driver.evaluate_script(%<(function () {})()>)
|
293
317
|
result.should == nil
|
294
318
|
end
|
295
319
|
|
296
320
|
it "evaluates Javascript and returns an object" do
|
297
|
-
result =
|
321
|
+
result = driver.evaluate_script(%<({ 'one' : 1 })>)
|
298
322
|
result.should == { 'one' => 1 }
|
299
323
|
end
|
300
324
|
|
301
325
|
it "evaluates Javascript and returns true" do
|
302
|
-
result =
|
326
|
+
result = driver.evaluate_script(%<true>)
|
303
327
|
result.should === true
|
304
328
|
end
|
305
329
|
|
306
330
|
it "evaluates Javascript and returns false" do
|
307
|
-
result =
|
331
|
+
result = driver.evaluate_script(%<false>)
|
308
332
|
result.should === false
|
309
333
|
end
|
310
334
|
|
311
335
|
it "evaluates Javascript and returns an escaped string" do
|
312
|
-
result =
|
336
|
+
result = driver.evaluate_script(%<'"'>)
|
313
337
|
result.should === "\""
|
314
338
|
end
|
315
339
|
|
316
340
|
it "evaluates Javascript with multiple lines" do
|
317
|
-
result =
|
341
|
+
result = driver.evaluate_script("[1,\n2]")
|
318
342
|
result.should == [1, 2]
|
319
343
|
end
|
320
344
|
|
321
345
|
it "executes Javascript" do
|
322
|
-
|
323
|
-
|
346
|
+
driver.execute_script(%<document.getElementById('greeting').innerHTML = 'yo'>)
|
347
|
+
driver.find("//p[contains(., 'yo')]").should_not be_empty
|
324
348
|
end
|
325
349
|
|
326
350
|
it "raises an error for failing Javascript" do
|
327
|
-
expect {
|
328
|
-
to raise_error(Capybara::
|
351
|
+
expect { driver.execute_script(%<invalid salad>) }.
|
352
|
+
to raise_error(Capybara::Webkit::InvalidResponseError)
|
329
353
|
end
|
330
354
|
|
331
355
|
it "doesn't raise an error for Javascript that doesn't return anything" do
|
332
|
-
lambda {
|
356
|
+
lambda { driver.execute_script(%<(function () { "returns nothing" })()>) }.
|
333
357
|
should_not raise_error
|
334
358
|
end
|
335
359
|
|
336
360
|
it "returns a node's tag name" do
|
337
|
-
|
361
|
+
driver.find("//p").first.tag_name.should == "p"
|
338
362
|
end
|
339
363
|
|
340
364
|
it "reads disabled property" do
|
341
|
-
|
365
|
+
driver.find("//input").first.should be_disabled
|
342
366
|
end
|
343
367
|
|
344
368
|
it "reads checked property" do
|
345
|
-
|
369
|
+
driver.find("//input[@id='checktest']").first.should be_checked
|
346
370
|
end
|
347
371
|
|
348
372
|
it "finds visible elements" do
|
349
|
-
|
350
|
-
|
373
|
+
driver.find("//p").first.should be_visible
|
374
|
+
driver.find("//*[@id='invisible']").first.should_not be_visible
|
351
375
|
end
|
352
376
|
end
|
353
377
|
|
354
378
|
context "console messages app" do
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
</html>
|
370
|
-
HTML
|
371
|
-
[200,
|
372
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
373
|
-
[body]]
|
374
|
-
end
|
379
|
+
let(:driver) do
|
380
|
+
driver_for_html(<<-HTML)
|
381
|
+
<html>
|
382
|
+
<head>
|
383
|
+
</head>
|
384
|
+
<body>
|
385
|
+
<script type="text/javascript">
|
386
|
+
console.log("hello");
|
387
|
+
console.log("hello again");
|
388
|
+
oops
|
389
|
+
</script>
|
390
|
+
</body>
|
391
|
+
</html>
|
392
|
+
HTML
|
375
393
|
end
|
376
394
|
|
395
|
+
before { driver.visit("/") }
|
396
|
+
|
377
397
|
it "collects messages logged to the console" do
|
378
|
-
|
379
|
-
|
398
|
+
driver.console_messages.first.should include :source, :message => "hello", :line_number => 6
|
399
|
+
driver.console_messages.length.should eq 3
|
380
400
|
end
|
381
401
|
|
382
402
|
it "logs errors to the console" do
|
383
|
-
|
403
|
+
driver.error_messages.length.should eq 1
|
384
404
|
end
|
385
405
|
|
386
406
|
end
|
387
407
|
|
388
408
|
context "form app" do
|
389
|
-
|
390
|
-
|
391
|
-
body
|
392
|
-
<
|
393
|
-
<
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
<
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
<
|
404
|
-
<
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
<
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
[body]]
|
421
|
-
end
|
422
|
-
end
|
409
|
+
let(:driver) do
|
410
|
+
driver_for_html(<<-HTML)
|
411
|
+
<html><body>
|
412
|
+
<form action="/" method="GET">
|
413
|
+
<input type="text" name="foo" value="bar"/>
|
414
|
+
<input type="text" name="maxlength_foo" value="bar" maxlength="10"/>
|
415
|
+
<input type="text" id="disabled_input" disabled="disabled"/>
|
416
|
+
<input type="checkbox" name="checkedbox" value="1" checked="checked"/>
|
417
|
+
<input type="checkbox" name="uncheckedbox" value="2"/>
|
418
|
+
<select name="animal">
|
419
|
+
<option id="select-option-monkey">Monkey</option>
|
420
|
+
<option id="select-option-capybara" selected="selected">Capybara</option>
|
421
|
+
</select>
|
422
|
+
<select name="toppings" multiple="multiple">
|
423
|
+
<optgroup label="Mediocre Toppings">
|
424
|
+
<option selected="selected" id="topping-apple">Apple</option>
|
425
|
+
<option selected="selected" id="topping-banana">Banana</option>
|
426
|
+
</optgroup>
|
427
|
+
<optgroup label="Best Toppings">
|
428
|
+
<option selected="selected" id="topping-cherry">Cherry</option>
|
429
|
+
</optgroup>
|
430
|
+
</select>
|
431
|
+
<textarea id="only-textarea">what a wonderful area for text</textarea>
|
432
|
+
<input type="radio" id="only-radio" value="1"/>
|
433
|
+
<button type="reset">Reset Form</button>
|
434
|
+
</form>
|
435
|
+
</body></html>
|
436
|
+
HTML
|
437
|
+
end
|
438
|
+
|
439
|
+
before { driver.visit("/") }
|
423
440
|
|
424
441
|
it "returns a textarea's value" do
|
425
|
-
|
442
|
+
driver.find("//textarea").first.value.should == "what a wonderful area for text"
|
426
443
|
end
|
427
444
|
|
428
445
|
it "returns a text input's value" do
|
429
|
-
|
446
|
+
driver.find("//input").first.value.should == "bar"
|
430
447
|
end
|
431
448
|
|
432
449
|
it "returns a select's value" do
|
433
|
-
|
450
|
+
driver.find("//select").first.value.should == "Capybara"
|
434
451
|
end
|
435
452
|
|
436
453
|
it "sets an input's value" do
|
437
|
-
input =
|
454
|
+
input = driver.find("//input").first
|
438
455
|
input.set("newvalue")
|
439
456
|
input.value.should == "newvalue"
|
440
457
|
end
|
441
458
|
|
442
459
|
it "sets an input's value greater than the max length" do
|
443
|
-
input =
|
460
|
+
input = driver.find("//input[@name='maxlength_foo']").first
|
444
461
|
input.set("allegories (poems)")
|
445
462
|
input.value.should == "allegories"
|
446
463
|
end
|
447
464
|
|
448
465
|
it "sets an input's value equal to the max length" do
|
449
|
-
input =
|
466
|
+
input = driver.find("//input[@name='maxlength_foo']").first
|
450
467
|
input.set("allegories")
|
451
468
|
input.value.should == "allegories"
|
452
469
|
end
|
453
470
|
|
454
471
|
it "sets an input's value less than the max length" do
|
455
|
-
input =
|
472
|
+
input = driver.find("//input[@name='maxlength_foo']").first
|
456
473
|
input.set("poems")
|
457
474
|
input.value.should == "poems"
|
458
475
|
end
|
459
476
|
|
460
477
|
it "sets an input's nil value" do
|
461
|
-
input =
|
478
|
+
input = driver.find("//input").first
|
462
479
|
input.set(nil)
|
463
480
|
input.value.should == ""
|
464
481
|
end
|
465
482
|
|
466
483
|
it "sets a select's value" do
|
467
|
-
select =
|
484
|
+
select = driver.find("//select").first
|
468
485
|
select.set("Monkey")
|
469
486
|
select.value.should == "Monkey"
|
470
487
|
end
|
471
488
|
|
472
489
|
it "sets a textarea's value" do
|
473
|
-
textarea =
|
490
|
+
textarea = driver.find("//textarea").first
|
474
491
|
textarea.set("newvalue")
|
475
492
|
textarea.value.should == "newvalue"
|
476
493
|
end
|
477
494
|
|
478
|
-
let(:monkey_option) {
|
479
|
-
let(:capybara_option) {
|
480
|
-
let(:animal_select) {
|
481
|
-
let(:apple_option) {
|
482
|
-
let(:banana_option) {
|
483
|
-
let(:cherry_option) {
|
484
|
-
let(:toppings_select) {
|
485
|
-
let(:reset_button) {
|
495
|
+
let(:monkey_option) { driver.find("//option[@id='select-option-monkey']").first }
|
496
|
+
let(:capybara_option) { driver.find("//option[@id='select-option-capybara']").first }
|
497
|
+
let(:animal_select) { driver.find("//select[@name='animal']").first }
|
498
|
+
let(:apple_option) { driver.find("//option[@id='topping-apple']").first }
|
499
|
+
let(:banana_option) { driver.find("//option[@id='topping-banana']").first }
|
500
|
+
let(:cherry_option) { driver.find("//option[@id='topping-cherry']").first }
|
501
|
+
let(:toppings_select) { driver.find("//select[@name='toppings']").first }
|
502
|
+
let(:reset_button) { driver.find("//button[@type='reset']").first }
|
486
503
|
|
487
504
|
context "a select element's selection has been changed" do
|
488
505
|
before do
|
@@ -537,8 +554,8 @@ describe Capybara::Driver::Webkit do
|
|
537
554
|
toppings_select.value.should include("Apple", "Banana", "Cherry")
|
538
555
|
end
|
539
556
|
|
540
|
-
let(:checked_box) {
|
541
|
-
let(:unchecked_box) {
|
557
|
+
let(:checked_box) { driver.find("//input[@name='checkedbox']").first }
|
558
|
+
let(:unchecked_box) { driver.find("//input[@name='uncheckedbox']").first }
|
542
559
|
|
543
560
|
it "knows a checked box is checked" do
|
544
561
|
checked_box['checked'].should be_true
|
@@ -576,8 +593,8 @@ describe Capybara::Driver::Webkit do
|
|
576
593
|
unchecked_box.should_not be_checked
|
577
594
|
end
|
578
595
|
|
579
|
-
let(:enabled_input) {
|
580
|
-
let(:disabled_input) {
|
596
|
+
let(:enabled_input) { driver.find("//input[@name='foo']").first }
|
597
|
+
let(:disabled_input) { driver.find("//input[@id='disabled_input']").first }
|
581
598
|
|
582
599
|
it "knows a disabled input is disabled" do
|
583
600
|
disabled_input['disabled'].should be_true
|
@@ -589,91 +606,84 @@ describe Capybara::Driver::Webkit do
|
|
589
606
|
end
|
590
607
|
|
591
608
|
context "dom events" do
|
592
|
-
|
593
|
-
|
594
|
-
body
|
595
|
-
|
596
|
-
<
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
var
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
var
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
619
|
-
[body]]
|
620
|
-
end
|
621
|
-
end
|
609
|
+
let(:driver) do
|
610
|
+
driver_for_html(<<-HTML)
|
611
|
+
<html><body>
|
612
|
+
<a href='#' class='watch'>Link</a>
|
613
|
+
<ul id="events"></ul>
|
614
|
+
<script type="text/javascript">
|
615
|
+
var events = document.getElementById("events");
|
616
|
+
var recordEvent = function (event) {
|
617
|
+
var element = document.createElement("li");
|
618
|
+
element.innerHTML = event.type;
|
619
|
+
events.appendChild(element);
|
620
|
+
};
|
621
|
+
|
622
|
+
var elements = document.getElementsByClassName("watch");
|
623
|
+
for (var i = 0; i < elements.length; i++) {
|
624
|
+
var element = elements[i];
|
625
|
+
element.addEventListener("mousedown", recordEvent);
|
626
|
+
element.addEventListener("mouseup", recordEvent);
|
627
|
+
element.addEventListener("click", recordEvent);
|
628
|
+
}
|
629
|
+
</script>
|
630
|
+
</body></html>
|
631
|
+
HTML
|
632
|
+
end
|
633
|
+
|
634
|
+
before { driver.visit("/") }
|
622
635
|
|
623
636
|
it "triggers mouse events" do
|
624
|
-
|
625
|
-
|
637
|
+
driver.find("//a").first.click
|
638
|
+
driver.find("//li").map(&:text).should == %w(mousedown mouseup click)
|
626
639
|
end
|
627
640
|
end
|
628
641
|
|
629
642
|
context "form events app" do
|
630
|
-
|
631
|
-
|
632
|
-
body
|
633
|
-
<
|
634
|
-
<
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
var
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
[body]]
|
675
|
-
end
|
676
|
-
end
|
643
|
+
let(:driver) do
|
644
|
+
driver_for_html(<<-HTML)
|
645
|
+
<html><body>
|
646
|
+
<form action="/" method="GET">
|
647
|
+
<input class="watch" type="email"/>
|
648
|
+
<input class="watch" type="number"/>
|
649
|
+
<input class="watch" type="password"/>
|
650
|
+
<input class="watch" type="search"/>
|
651
|
+
<input class="watch" type="tel"/>
|
652
|
+
<input class="watch" type="text"/>
|
653
|
+
<input class="watch" type="url"/>
|
654
|
+
<textarea class="watch"></textarea>
|
655
|
+
<input class="watch" type="checkbox"/>
|
656
|
+
<input class="watch" type="radio"/>
|
657
|
+
</form>
|
658
|
+
<ul id="events"></ul>
|
659
|
+
<script type="text/javascript">
|
660
|
+
var events = document.getElementById("events");
|
661
|
+
var recordEvent = function (event) {
|
662
|
+
var element = document.createElement("li");
|
663
|
+
element.innerHTML = event.type;
|
664
|
+
events.appendChild(element);
|
665
|
+
};
|
666
|
+
|
667
|
+
var elements = document.getElementsByClassName("watch");
|
668
|
+
for (var i = 0; i < elements.length; i++) {
|
669
|
+
var element = elements[i];
|
670
|
+
element.addEventListener("focus", recordEvent);
|
671
|
+
element.addEventListener("keydown", recordEvent);
|
672
|
+
element.addEventListener("keypress", recordEvent);
|
673
|
+
element.addEventListener("keyup", recordEvent);
|
674
|
+
element.addEventListener("input", recordEvent);
|
675
|
+
element.addEventListener("change", recordEvent);
|
676
|
+
element.addEventListener("blur", recordEvent);
|
677
|
+
element.addEventListener("mousedown", recordEvent);
|
678
|
+
element.addEventListener("mouseup", recordEvent);
|
679
|
+
element.addEventListener("click", recordEvent);
|
680
|
+
}
|
681
|
+
</script>
|
682
|
+
</body></html>
|
683
|
+
HTML
|
684
|
+
end
|
685
|
+
|
686
|
+
before { driver.visit("/") }
|
677
687
|
|
678
688
|
let(:newtext) { 'newvalue' }
|
679
689
|
|
@@ -685,171 +695,165 @@ describe Capybara::Driver::Webkit do
|
|
685
695
|
|
686
696
|
%w(email number password search tel text url).each do | field_type |
|
687
697
|
it "triggers text input events on inputs of type #{field_type}" do
|
688
|
-
|
689
|
-
|
698
|
+
driver.find("//input[@type='#{field_type}']").first.set(newtext)
|
699
|
+
driver.find("//li").map(&:text).should == keyevents
|
690
700
|
end
|
691
701
|
end
|
692
702
|
|
693
703
|
it "triggers textarea input events" do
|
694
|
-
|
695
|
-
|
704
|
+
driver.find("//textarea").first.set(newtext)
|
705
|
+
driver.find("//li").map(&:text).should == keyevents
|
696
706
|
end
|
697
707
|
|
698
708
|
it "triggers radio input events" do
|
699
|
-
|
700
|
-
|
709
|
+
driver.find("//input[@type='radio']").first.set(true)
|
710
|
+
driver.find("//li").map(&:text).should == %w(mousedown mouseup change click)
|
701
711
|
end
|
702
712
|
|
703
713
|
it "triggers checkbox events" do
|
704
|
-
|
705
|
-
|
714
|
+
driver.find("//input[@type='checkbox']").first.set(true)
|
715
|
+
driver.find("//li").map(&:text).should == %w(mousedown mouseup change click)
|
706
716
|
end
|
707
717
|
end
|
708
718
|
|
709
719
|
context "mouse app" do
|
710
|
-
|
711
|
-
|
712
|
-
body
|
713
|
-
<
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
<
|
718
|
-
<
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
[body]]
|
747
|
-
end
|
748
|
-
end
|
720
|
+
let(:driver) do
|
721
|
+
driver_for_html(<<-HTML)
|
722
|
+
<html><body>
|
723
|
+
<div id="change">Change me</div>
|
724
|
+
<div id="mouseup">Push me</div>
|
725
|
+
<div id="mousedown">Release me</div>
|
726
|
+
<form action="/" method="GET">
|
727
|
+
<select id="change_select" name="change_select">
|
728
|
+
<option value="1" id="option-1" selected="selected">one</option>
|
729
|
+
<option value="2" id="option-2">two</option>
|
730
|
+
</select>
|
731
|
+
</form>
|
732
|
+
<script type="text/javascript">
|
733
|
+
document.getElementById("change_select").
|
734
|
+
addEventListener("change", function () {
|
735
|
+
this.className = "triggered";
|
736
|
+
});
|
737
|
+
document.getElementById("change").
|
738
|
+
addEventListener("change", function () {
|
739
|
+
this.className = "triggered";
|
740
|
+
});
|
741
|
+
document.getElementById("mouseup").
|
742
|
+
addEventListener("mouseup", function () {
|
743
|
+
this.className = "triggered";
|
744
|
+
});
|
745
|
+
document.getElementById("mousedown").
|
746
|
+
addEventListener("mousedown", function () {
|
747
|
+
this.className = "triggered";
|
748
|
+
});
|
749
|
+
</script>
|
750
|
+
<a href="/next">Next</a>
|
751
|
+
</body></html>
|
752
|
+
HTML
|
753
|
+
end
|
754
|
+
|
755
|
+
before { driver.visit("/") }
|
749
756
|
|
750
757
|
it "clicks an element" do
|
751
|
-
|
752
|
-
|
758
|
+
driver.find("//a").first.click
|
759
|
+
driver.current_url =~ %r{/next$}
|
753
760
|
end
|
754
761
|
|
755
762
|
it "fires a mouse event" do
|
756
|
-
|
757
|
-
|
763
|
+
driver.find("//*[@id='mouseup']").first.trigger("mouseup")
|
764
|
+
driver.find("//*[@class='triggered']").should_not be_empty
|
758
765
|
end
|
759
766
|
|
760
767
|
it "fires a non-mouse event" do
|
761
|
-
|
762
|
-
|
768
|
+
driver.find("//*[@id='change']").first.trigger("change")
|
769
|
+
driver.find("//*[@class='triggered']").should_not be_empty
|
763
770
|
end
|
764
771
|
|
765
772
|
it "fires a change on select" do
|
766
|
-
select =
|
773
|
+
select = driver.find("//select").first
|
767
774
|
select.value.should == "1"
|
768
|
-
option =
|
775
|
+
option = driver.find("//option[@id='option-2']").first
|
769
776
|
option.select_option
|
770
777
|
select.value.should == "2"
|
771
|
-
|
778
|
+
driver.find("//select[@class='triggered']").should_not be_empty
|
772
779
|
end
|
773
780
|
|
774
781
|
it "fires drag events" do
|
775
|
-
draggable =
|
776
|
-
container =
|
782
|
+
draggable = driver.find("//*[@id='mousedown']").first
|
783
|
+
container = driver.find("//*[@id='mouseup']").first
|
777
784
|
|
778
785
|
draggable.drag_to(container)
|
779
786
|
|
780
|
-
|
787
|
+
driver.find("//*[@class='triggered']").size.should == 1
|
781
788
|
end
|
782
789
|
end
|
783
790
|
|
784
791
|
context "nesting app" do
|
785
|
-
|
786
|
-
|
787
|
-
body
|
788
|
-
<
|
789
|
-
<div
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
HTML
|
795
|
-
[200,
|
796
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
797
|
-
[body]]
|
798
|
-
end
|
792
|
+
let(:driver) do
|
793
|
+
driver_for_html(<<-HTML)
|
794
|
+
<html><body>
|
795
|
+
<div id="parent">
|
796
|
+
<div class="find">Expected</div>
|
797
|
+
</div>
|
798
|
+
<div class="find">Unexpected</div>
|
799
|
+
</body></html>
|
800
|
+
HTML
|
799
801
|
end
|
800
802
|
|
803
|
+
before { driver.visit("/") }
|
804
|
+
|
801
805
|
it "evaluates nested xpath expressions" do
|
802
|
-
parent =
|
806
|
+
parent = driver.find("//*[@id='parent']").first
|
803
807
|
parent.find("./*[@class='find']").map(&:text).should == %w(Expected)
|
804
808
|
end
|
805
809
|
end
|
806
810
|
|
807
811
|
context "slow app" do
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
+
it "waits for a request to load" do
|
813
|
+
result = ""
|
814
|
+
driver = driver_for_app do
|
815
|
+
get "/result" do
|
812
816
|
sleep(0.5)
|
813
|
-
|
817
|
+
result << "finished"
|
818
|
+
""
|
814
819
|
end
|
815
|
-
body = %{<html><body><a href="/result">Go</a></body></html>}
|
816
|
-
[200,
|
817
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
818
|
-
[body]]
|
819
|
-
end
|
820
|
-
end
|
821
820
|
|
822
|
-
|
823
|
-
|
824
|
-
|
821
|
+
get "/" do
|
822
|
+
%{<html><body><a href="/result">Go</a></body></html>}
|
823
|
+
end
|
824
|
+
end
|
825
|
+
driver.visit("/")
|
826
|
+
driver.find("//a").first.click
|
827
|
+
result.should == "finished"
|
825
828
|
end
|
826
829
|
end
|
827
830
|
|
828
831
|
context "error app" do
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
832
|
+
let(:driver) do
|
833
|
+
driver_for_app do
|
834
|
+
get "/error" do
|
835
|
+
invalid_response
|
836
|
+
end
|
837
|
+
|
838
|
+
get "/" do
|
839
|
+
<<-HTML
|
835
840
|
<html><body>
|
836
841
|
<form action="/error"><input type="submit"/></form>
|
837
842
|
</body></html>
|
838
843
|
HTML
|
839
|
-
[200,
|
840
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
841
|
-
[body]]
|
842
844
|
end
|
843
845
|
end
|
844
846
|
end
|
845
847
|
|
848
|
+
before { driver.visit("/") }
|
849
|
+
|
846
850
|
it "raises a webkit error for the requested url" do
|
847
851
|
expect {
|
848
|
-
|
852
|
+
driver.find("//input").first.click
|
849
853
|
wait_for_error_to_complete
|
850
|
-
|
854
|
+
driver.find("//body")
|
851
855
|
}.
|
852
|
-
to raise_error(Capybara::
|
856
|
+
to raise_error(Capybara::Webkit::InvalidResponseError, %r{/error})
|
853
857
|
end
|
854
858
|
|
855
859
|
def wait_for_error_to_complete
|
@@ -858,171 +862,167 @@ describe Capybara::Driver::Webkit do
|
|
858
862
|
end
|
859
863
|
|
860
864
|
context "slow error app" do
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
body = "error"
|
865
|
+
let(:driver) do
|
866
|
+
driver_for_app do
|
867
|
+
get "/error" do
|
865
868
|
sleep(1)
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
+
invalid_response
|
870
|
+
end
|
871
|
+
|
872
|
+
get "/" do
|
873
|
+
<<-HTML
|
869
874
|
<html><body>
|
870
875
|
<form action="/error"><input type="submit"/></form>
|
871
876
|
<p>hello</p>
|
872
877
|
</body></html>
|
873
878
|
HTML
|
874
|
-
[200,
|
875
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
876
|
-
[body]]
|
877
879
|
end
|
878
880
|
end
|
879
881
|
end
|
880
882
|
|
883
|
+
before { driver.visit("/") }
|
884
|
+
|
881
885
|
it "raises a webkit error and then continues" do
|
882
|
-
|
883
|
-
expect {
|
884
|
-
|
885
|
-
|
886
|
+
driver.find("//input").first.click
|
887
|
+
expect { driver.find("//p") }.to raise_error(Capybara::Webkit::InvalidResponseError)
|
888
|
+
driver.visit("/")
|
889
|
+
driver.find("//p").first.text.should == "hello"
|
886
890
|
end
|
887
891
|
end
|
888
892
|
|
889
893
|
context "popup app" do
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
[body]]
|
894
|
+
let(:driver) do
|
895
|
+
driver_for_app do
|
896
|
+
get "/" do
|
897
|
+
sleep(0.5)
|
898
|
+
return <<-HTML
|
899
|
+
<html><body>
|
900
|
+
<script type="text/javascript">
|
901
|
+
alert("alert");
|
902
|
+
confirm("confirm");
|
903
|
+
prompt("prompt");
|
904
|
+
</script>
|
905
|
+
<p>success</p>
|
906
|
+
</body></html>
|
907
|
+
HTML
|
908
|
+
end
|
906
909
|
end
|
907
910
|
end
|
908
911
|
|
912
|
+
before { driver.visit("/") }
|
913
|
+
|
909
914
|
it "doesn't crash from alerts" do
|
910
|
-
|
915
|
+
driver.find("//p").first.text.should == "success"
|
911
916
|
end
|
912
917
|
end
|
913
918
|
|
914
919
|
context "custom header" do
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
<
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
[body]]
|
920
|
+
let(:driver) do
|
921
|
+
driver_for_app do
|
922
|
+
get "/" do
|
923
|
+
<<-HTML
|
924
|
+
<html><body>
|
925
|
+
<p id="user-agent">#{env['HTTP_USER_AGENT']}</p>
|
926
|
+
<p id="x-capybara-webkit-header">#{env['HTTP_X_CAPYBARA_WEBKIT_HEADER']}</p>
|
927
|
+
<p id="accept">#{env['HTTP_ACCEPT']}</p>
|
928
|
+
<a href="/">/</a>
|
929
|
+
</body></html>
|
930
|
+
HTML
|
931
|
+
end
|
928
932
|
end
|
929
933
|
end
|
930
934
|
|
935
|
+
before { driver.visit("/") }
|
936
|
+
|
931
937
|
before do
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
938
|
+
driver.header('user-agent', 'capybara-webkit/custom-user-agent')
|
939
|
+
driver.header('x-capybara-webkit-header', 'x-capybara-webkit-header')
|
940
|
+
driver.header('accept', 'text/html')
|
941
|
+
driver.visit('/')
|
936
942
|
end
|
937
943
|
|
938
944
|
it "can set user_agent" do
|
939
|
-
|
940
|
-
|
945
|
+
driver.find('id("user-agent")').first.text.should == 'capybara-webkit/custom-user-agent'
|
946
|
+
driver.evaluate_script('navigator.userAgent').should == 'capybara-webkit/custom-user-agent'
|
941
947
|
end
|
942
948
|
|
943
949
|
it "keep user_agent in next page" do
|
944
|
-
|
945
|
-
|
946
|
-
|
950
|
+
driver.find("//a").first.click
|
951
|
+
driver.find('id("user-agent")').first.text.should == 'capybara-webkit/custom-user-agent'
|
952
|
+
driver.evaluate_script('navigator.userAgent').should == 'capybara-webkit/custom-user-agent'
|
947
953
|
end
|
948
954
|
|
949
955
|
it "can set custom header" do
|
950
|
-
|
956
|
+
driver.find('id("x-capybara-webkit-header")').first.text.should == 'x-capybara-webkit-header'
|
951
957
|
end
|
952
958
|
|
953
959
|
it "can set Accept header" do
|
954
|
-
|
960
|
+
driver.find('id("accept")').first.text.should == 'text/html'
|
955
961
|
end
|
956
962
|
|
957
963
|
it "can reset all custom header" do
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
+
driver.reset!
|
965
|
+
driver.visit('/')
|
966
|
+
driver.find('id("user-agent")').first.text.should_not == 'capybara-webkit/custom-user-agent'
|
967
|
+
driver.evaluate_script('navigator.userAgent').should_not == 'capybara-webkit/custom-user-agent'
|
968
|
+
driver.find('id("x-capybara-webkit-header")').first.text.should be_empty
|
969
|
+
driver.find('id("accept")').first.text.should_not == 'text/html'
|
964
970
|
end
|
965
971
|
end
|
966
972
|
|
967
973
|
context "no response app" do
|
968
|
-
|
969
|
-
|
970
|
-
body
|
971
|
-
<
|
972
|
-
|
973
|
-
|
974
|
-
HTML
|
975
|
-
[200,
|
976
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
977
|
-
[body]]
|
978
|
-
end
|
974
|
+
let(:driver) do
|
975
|
+
driver_for_html(<<-HTML)
|
976
|
+
<html><body>
|
977
|
+
<form action="/error"><input type="submit"/></form>
|
978
|
+
</body></html>
|
979
|
+
HTML
|
979
980
|
end
|
980
981
|
|
982
|
+
before { driver.visit("/") }
|
983
|
+
|
981
984
|
it "raises a webkit error for the requested url" do
|
982
985
|
make_the_server_go_away
|
983
986
|
expect {
|
984
|
-
|
987
|
+
driver.find("//body")
|
985
988
|
}.
|
986
|
-
to raise_error(Capybara::
|
989
|
+
to raise_error(Capybara::Webkit::NoResponseError, %r{response})
|
987
990
|
make_the_server_come_back
|
988
991
|
end
|
989
992
|
|
990
993
|
def make_the_server_come_back
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
+
driver.browser.instance_variable_get(:@connection).unstub!(:gets)
|
995
|
+
driver.browser.instance_variable_get(:@connection).unstub!(:puts)
|
996
|
+
driver.browser.instance_variable_get(:@connection).unstub!(:print)
|
994
997
|
end
|
995
998
|
|
996
999
|
def make_the_server_go_away
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
+
driver.browser.instance_variable_get(:@connection).stub!(:gets).and_return(nil)
|
1001
|
+
driver.browser.instance_variable_get(:@connection).stub!(:puts)
|
1002
|
+
driver.browser.instance_variable_get(:@connection).stub!(:print)
|
1000
1003
|
end
|
1001
1004
|
end
|
1002
1005
|
|
1003
1006
|
context "custom font app" do
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
<
|
1008
|
-
<
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
<
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
HTML
|
1018
|
-
[200,
|
1019
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
1020
|
-
[body]]
|
1021
|
-
end
|
1007
|
+
let(:driver) do
|
1008
|
+
driver_for_html(<<-HTML)
|
1009
|
+
<html>
|
1010
|
+
<head>
|
1011
|
+
<style type="text/css">
|
1012
|
+
p { font-family: "Verdana"; }
|
1013
|
+
</style>
|
1014
|
+
</head>
|
1015
|
+
<body>
|
1016
|
+
<p id="text">Hello</p>
|
1017
|
+
</body>
|
1018
|
+
</html>
|
1019
|
+
HTML
|
1022
1020
|
end
|
1023
1021
|
|
1022
|
+
before { driver.visit("/") }
|
1023
|
+
|
1024
1024
|
it "ignores custom fonts" do
|
1025
|
-
font_family =
|
1025
|
+
font_family = driver.evaluate_script(<<-SCRIPT)
|
1026
1026
|
var element = document.getElementById("text");
|
1027
1027
|
element.ownerDocument.defaultView.getComputedStyle(element, null).getPropertyValue("font-family");
|
1028
1028
|
SCRIPT
|
@@ -1031,49 +1031,45 @@ describe Capybara::Driver::Webkit do
|
|
1031
1031
|
end
|
1032
1032
|
|
1033
1033
|
context "cookie-based app" do
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
[200,
|
1045
|
-
{ 'Content-Type' => 'text/html; charset=UTF-8',
|
1046
|
-
'Content-Length' => body.length.to_s,
|
1047
|
-
'Set-Cookie' => @cookie,
|
1048
|
-
},
|
1049
|
-
[body]]
|
1034
|
+
let(:driver) do
|
1035
|
+
driver_for_app do
|
1036
|
+
get "/" do
|
1037
|
+
headers 'Set-Cookie' => 'cookie=abc; domain=127.0.0.1; path=/'
|
1038
|
+
<<-HTML
|
1039
|
+
<html><body>
|
1040
|
+
<p id="cookie">#{request.cookies["cookie"] || ""}</p>
|
1041
|
+
</body></html>
|
1042
|
+
HTML
|
1043
|
+
end
|
1050
1044
|
end
|
1051
1045
|
end
|
1052
1046
|
|
1047
|
+
before { driver.visit("/") }
|
1048
|
+
|
1053
1049
|
def echoed_cookie
|
1054
|
-
|
1050
|
+
driver.find('id("cookie")').first.text
|
1055
1051
|
end
|
1056
1052
|
|
1057
1053
|
it "remembers the cookie on second visit" do
|
1058
1054
|
echoed_cookie.should == ""
|
1059
|
-
|
1055
|
+
driver.visit "/"
|
1060
1056
|
echoed_cookie.should == "abc"
|
1061
1057
|
end
|
1062
1058
|
|
1063
1059
|
it "uses a custom cookie" do
|
1064
|
-
|
1065
|
-
|
1060
|
+
driver.browser.set_cookie 'cookie=abc; domain=127.0.0.1; path=/'
|
1061
|
+
driver.visit "/"
|
1066
1062
|
echoed_cookie.should == "abc"
|
1067
1063
|
end
|
1068
1064
|
|
1069
1065
|
it "clears cookies" do
|
1070
|
-
|
1071
|
-
|
1066
|
+
driver.browser.clear_cookies
|
1067
|
+
driver.visit "/"
|
1072
1068
|
echoed_cookie.should == ""
|
1073
1069
|
end
|
1074
1070
|
|
1075
1071
|
it "allows enumeration of cookies" do
|
1076
|
-
cookies =
|
1072
|
+
cookies = driver.browser.get_cookies
|
1077
1073
|
|
1078
1074
|
cookies.size.should == 1
|
1079
1075
|
|
@@ -1084,64 +1080,23 @@ describe Capybara::Driver::Webkit do
|
|
1084
1080
|
end
|
1085
1081
|
|
1086
1082
|
it "allows reading access to cookies using a nice syntax" do
|
1087
|
-
|
1088
|
-
end
|
1089
|
-
end
|
1090
|
-
|
1091
|
-
context "with socket debugger" do
|
1092
|
-
let(:socket_debugger_class){ Capybara::Driver::Webkit::SocketDebugger }
|
1093
|
-
let(:browser_with_debugger){
|
1094
|
-
connection = Capybara::Driver::Webkit::Connection.new(:socket_class => socket_debugger_class)
|
1095
|
-
Capybara::Driver::Webkit::Browser.new(connection)
|
1096
|
-
}
|
1097
|
-
let(:driver_with_debugger){ Capybara::Driver::Webkit.new(@app, :browser => browser_with_debugger) }
|
1098
|
-
|
1099
|
-
before(:all) do
|
1100
|
-
@app = lambda do |env|
|
1101
|
-
body = <<-HTML
|
1102
|
-
<html><body>
|
1103
|
-
<div id="parent">
|
1104
|
-
<div class="find">Expected</div>
|
1105
|
-
</div>
|
1106
|
-
<div class="find">Unexpected</div>
|
1107
|
-
</body></html>
|
1108
|
-
HTML
|
1109
|
-
[200,
|
1110
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
1111
|
-
[body]]
|
1112
|
-
end
|
1113
|
-
end
|
1114
|
-
|
1115
|
-
it "prints out sent content" do
|
1116
|
-
socket_debugger_class.any_instance.stub(:received){|content| content }
|
1117
|
-
sent_content = ['Find', 1, 17, "//*[@id='parent']"]
|
1118
|
-
socket_debugger_class.any_instance.should_receive(:sent).exactly(sent_content.size).times
|
1119
|
-
driver_with_debugger.find("//*[@id='parent']")
|
1120
|
-
end
|
1121
|
-
|
1122
|
-
it "prints out received content" do
|
1123
|
-
socket_debugger_class.any_instance.stub(:sent)
|
1124
|
-
socket_debugger_class.any_instance.should_receive(:received).at_least(:once).and_return("ok")
|
1125
|
-
driver_with_debugger.find("//*[@id='parent']")
|
1083
|
+
driver.cookies["cookie"].should == "abc"
|
1126
1084
|
end
|
1127
1085
|
end
|
1128
1086
|
|
1129
1087
|
context "remove node app" do
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
<
|
1134
|
-
<
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
HTML
|
1139
|
-
[200,
|
1140
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
1141
|
-
[body]]
|
1142
|
-
end
|
1088
|
+
let(:driver) do
|
1089
|
+
driver_for_html(<<-HTML)
|
1090
|
+
<html>
|
1091
|
+
<div id="parent">
|
1092
|
+
<p id="removeMe">Hello</p>
|
1093
|
+
</div>
|
1094
|
+
</html>
|
1095
|
+
HTML
|
1143
1096
|
end
|
1144
1097
|
|
1098
|
+
before { driver.visit("/") }
|
1099
|
+
|
1145
1100
|
before { set_automatic_reload false }
|
1146
1101
|
after { set_automatic_reload true }
|
1147
1102
|
|
@@ -1152,58 +1107,55 @@ describe Capybara::Driver::Webkit do
|
|
1152
1107
|
end
|
1153
1108
|
|
1154
1109
|
it "allows removed nodes when reloading is disabled" do
|
1155
|
-
node =
|
1156
|
-
|
1110
|
+
node = driver.find("//p[@id='removeMe']").first
|
1111
|
+
driver.evaluate_script("document.getElementById('parent').innerHTML = 'Magic'")
|
1157
1112
|
node.text.should == 'Hello'
|
1158
1113
|
end
|
1159
1114
|
end
|
1160
1115
|
|
1161
1116
|
context "app with a lot of HTML tags" do
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
<
|
1166
|
-
<
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
<
|
1172
|
-
<
|
1173
|
-
<
|
1174
|
-
<
|
1175
|
-
|
1176
|
-
|
1177
|
-
<
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
<
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
HTML
|
1201
|
-
[200,
|
1202
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
1203
|
-
[body]]
|
1204
|
-
end
|
1117
|
+
let(:driver) do
|
1118
|
+
driver_for_html(<<-HTML)
|
1119
|
+
<html>
|
1120
|
+
<head>
|
1121
|
+
<title>My eBook</title>
|
1122
|
+
<meta class="charset" name="charset" value="utf-8" />
|
1123
|
+
<meta class="author" name="author" value="Firstname Lastname" />
|
1124
|
+
</head>
|
1125
|
+
<body>
|
1126
|
+
<div id="toc">
|
1127
|
+
<table>
|
1128
|
+
<thead id="head">
|
1129
|
+
<tr><td class="td1">Chapter</td><td>Page</td></tr>
|
1130
|
+
</thead>
|
1131
|
+
<tbody>
|
1132
|
+
<tr><td>Intro</td><td>1</td></tr>
|
1133
|
+
<tr><td>Chapter 1</td><td class="td2">1</td></tr>
|
1134
|
+
<tr><td>Chapter 2</td><td>1</td></tr>
|
1135
|
+
</tbody>
|
1136
|
+
</table>
|
1137
|
+
</div>
|
1138
|
+
|
1139
|
+
<h1 class="h1">My first book</h1>
|
1140
|
+
<p class="p1">Written by me</p>
|
1141
|
+
<div id="intro" class="intro">
|
1142
|
+
<p>Let's try out XPath</p>
|
1143
|
+
<p class="p2">in capybara-webkit</p>
|
1144
|
+
</div>
|
1145
|
+
|
1146
|
+
<h2 class="chapter1">Chapter 1</h2>
|
1147
|
+
<p>This paragraph is fascinating.</p>
|
1148
|
+
<p class="p3">But not as much as this one.</p>
|
1149
|
+
|
1150
|
+
<h2 class="chapter2">Chapter 2</h2>
|
1151
|
+
<p>Let's try if we can select this</p>
|
1152
|
+
</body>
|
1153
|
+
</html>
|
1154
|
+
HTML
|
1205
1155
|
end
|
1206
1156
|
|
1157
|
+
before { driver.visit("/") }
|
1158
|
+
|
1207
1159
|
it "builds up node paths correctly" do
|
1208
1160
|
cases = {
|
1209
1161
|
"//*[contains(@class, 'author')]" => "/html/head/meta[2]",
|
@@ -1217,7 +1169,7 @@ describe Capybara::Driver::Webkit do
|
|
1217
1169
|
}
|
1218
1170
|
|
1219
1171
|
cases.each do |xpath, path|
|
1220
|
-
nodes =
|
1172
|
+
nodes = driver.find(xpath)
|
1221
1173
|
nodes.size.should == 1
|
1222
1174
|
nodes[0].path.should == path
|
1223
1175
|
end
|
@@ -1225,165 +1177,94 @@ describe Capybara::Driver::Webkit do
|
|
1225
1177
|
end
|
1226
1178
|
|
1227
1179
|
context "css overflow app" do
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
<
|
1232
|
-
<
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
<
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
HTML
|
1242
|
-
[200,
|
1243
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
1244
|
-
[body]]
|
1245
|
-
end
|
1180
|
+
let(:driver) do
|
1181
|
+
driver_for_html(<<-HTML)
|
1182
|
+
<html>
|
1183
|
+
<head>
|
1184
|
+
<style type="text/css">
|
1185
|
+
#overflow { overflow: hidden }
|
1186
|
+
</style>
|
1187
|
+
</head>
|
1188
|
+
<body>
|
1189
|
+
<div id="overflow">Overflow</div>
|
1190
|
+
</body>
|
1191
|
+
</html>
|
1192
|
+
HTML
|
1246
1193
|
end
|
1247
1194
|
|
1195
|
+
before { driver.visit("/") }
|
1196
|
+
|
1248
1197
|
it "handles overflow hidden" do
|
1249
|
-
|
1198
|
+
driver.find("//div[@id='overflow']").first.text.should == "Overflow"
|
1250
1199
|
end
|
1251
1200
|
end
|
1252
1201
|
|
1253
1202
|
context "javascript redirect app" do
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1203
|
+
let(:driver) do
|
1204
|
+
driver_for_app do
|
1205
|
+
get '/redirect' do
|
1206
|
+
<<-HTML
|
1258
1207
|
<html>
|
1259
1208
|
<script type="text/javascript">
|
1260
|
-
window.location = "/
|
1209
|
+
window.location = "/";
|
1261
1210
|
</script>
|
1262
1211
|
</html>
|
1263
1212
|
HTML
|
1264
|
-
else
|
1265
|
-
body = "<html><p>finished</p></html>"
|
1266
1213
|
end
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1214
|
+
|
1215
|
+
get '/' do
|
1216
|
+
"<html><p>finished</p></html>"
|
1217
|
+
end
|
1270
1218
|
end
|
1271
1219
|
end
|
1272
1220
|
|
1273
1221
|
it "loads a page without error" do
|
1274
1222
|
10.times do
|
1275
|
-
|
1276
|
-
|
1223
|
+
driver.visit("/redirect")
|
1224
|
+
driver.find("//p").first.text.should == "finished"
|
1277
1225
|
end
|
1278
1226
|
end
|
1279
1227
|
end
|
1280
1228
|
|
1281
1229
|
context "localStorage works" do
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
<
|
1286
|
-
<
|
1287
|
-
|
1288
|
-
|
1289
|
-
if (
|
1290
|
-
|
1291
|
-
localStorage.refreshCounter = 0;
|
1292
|
-
}
|
1293
|
-
if (localStorage.refreshCounter++ > 0) {
|
1294
|
-
document.getElementById("output").innerHTML = "localStorage is enabled";
|
1295
|
-
}
|
1230
|
+
let(:driver) do
|
1231
|
+
driver_for_html(<<-HTML)
|
1232
|
+
<html>
|
1233
|
+
<body>
|
1234
|
+
<span id='output'></span>
|
1235
|
+
<script type="text/javascript">
|
1236
|
+
if (typeof localStorage !== "undefined") {
|
1237
|
+
if (!localStorage.refreshCounter) {
|
1238
|
+
localStorage.refreshCounter = 0;
|
1296
1239
|
}
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
end
|
1306
|
-
|
1307
|
-
it "displays the message on subsequent page loads" do
|
1308
|
-
subject.find("//span[contains(.,'localStorage is enabled')]").should be_empty
|
1309
|
-
subject.visit "/"
|
1310
|
-
subject.find("//span[contains(.,'localStorage is enabled')]").should_not be_empty
|
1311
|
-
end
|
1312
|
-
end
|
1313
|
-
|
1314
|
-
context "app with a lot of HTML tags" do
|
1315
|
-
before(:all) do
|
1316
|
-
@app = lambda do |env|
|
1317
|
-
body = <<-HTML
|
1318
|
-
<html>
|
1319
|
-
<head>
|
1320
|
-
<title>My eBook</title>
|
1321
|
-
<meta class="charset" name="charset" value="utf-8" />
|
1322
|
-
<meta class="author" name="author" value="Firstname Lastname" />
|
1323
|
-
</head>
|
1324
|
-
<body>
|
1325
|
-
<div id="toc">
|
1326
|
-
<table>
|
1327
|
-
<thead id="head">
|
1328
|
-
<tr><td class="td1">Chapter</td><td>Page</td></tr>
|
1329
|
-
</thead>
|
1330
|
-
<tbody>
|
1331
|
-
<tr><td>Intro</td><td>1</td></tr>
|
1332
|
-
<tr><td>Chapter 1</td><td class="td2">1</td></tr>
|
1333
|
-
<tr><td>Chapter 2</td><td>1</td></tr>
|
1334
|
-
</tbody>
|
1335
|
-
</table>
|
1336
|
-
</div>
|
1337
|
-
|
1338
|
-
<h1 class="h1">My first book</h1>
|
1339
|
-
<p class="p1">Written by me</p>
|
1340
|
-
<div id="intro" class="intro">
|
1341
|
-
<p>Let's try out XPath</p>
|
1342
|
-
<p class="p2">in capybara-webkit</p>
|
1343
|
-
</div>
|
1344
|
-
|
1345
|
-
<h2 class="chapter1">Chapter 1</h2>
|
1346
|
-
<p>This paragraph is fascinating.</p>
|
1347
|
-
<p class="p3">But not as much as this one.</p>
|
1348
|
-
|
1349
|
-
<h2 class="chapter2">Chapter 2</h2>
|
1350
|
-
<p>Let's try if we can select this</p>
|
1351
|
-
</body>
|
1352
|
-
</html>
|
1353
|
-
HTML
|
1354
|
-
[200,
|
1355
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
1356
|
-
[body]]
|
1357
|
-
end
|
1240
|
+
if (localStorage.refreshCounter++ > 0) {
|
1241
|
+
document.getElementById("output").innerHTML = "localStorage is enabled";
|
1242
|
+
}
|
1243
|
+
}
|
1244
|
+
</script>
|
1245
|
+
</body>
|
1246
|
+
</html>
|
1247
|
+
HTML
|
1358
1248
|
end
|
1359
1249
|
|
1360
|
-
|
1361
|
-
cases = {
|
1362
|
-
"//*[contains(@class, 'author')]" => "/html/head/meta[2]",
|
1363
|
-
"//*[contains(@class, 'td1')]" => "/html/body/div[@id='toc']/table/thead[@id='head']/tr/td[1]",
|
1364
|
-
"//*[contains(@class, 'td2')]" => "/html/body/div[@id='toc']/table/tbody/tr[2]/td[2]",
|
1365
|
-
"//h1" => "/html/body/h1",
|
1366
|
-
"//*[contains(@class, 'chapter2')]" => "/html/body/h2[2]",
|
1367
|
-
"//*[contains(@class, 'p1')]" => "/html/body/p[1]",
|
1368
|
-
"//*[contains(@class, 'p2')]" => "/html/body/div[@id='intro']/p[2]",
|
1369
|
-
"//*[contains(@class, 'p3')]" => "/html/body/p[3]",
|
1370
|
-
}
|
1250
|
+
before { driver.visit("/") }
|
1371
1251
|
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
end
|
1252
|
+
it "displays the message on subsequent page loads" do
|
1253
|
+
driver.find("//span[contains(.,'localStorage is enabled')]").should be_empty
|
1254
|
+
driver.visit "/"
|
1255
|
+
driver.find("//span[contains(.,'localStorage is enabled')]").should_not be_empty
|
1377
1256
|
end
|
1378
1257
|
end
|
1379
1258
|
|
1380
1259
|
context "form app with server-side handler" do
|
1381
|
-
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1260
|
+
let(:driver) do
|
1261
|
+
driver_for_app do
|
1262
|
+
post "/" do
|
1263
|
+
"<html><body><p>Congrats!</p></body></html>"
|
1264
|
+
end
|
1265
|
+
|
1266
|
+
get "/" do
|
1267
|
+
<<-HTML
|
1387
1268
|
<html>
|
1388
1269
|
<head><title>Form</title>
|
1389
1270
|
<body>
|
@@ -1395,67 +1276,66 @@ describe Capybara::Driver::Webkit do
|
|
1395
1276
|
</html>
|
1396
1277
|
HTML
|
1397
1278
|
end
|
1398
|
-
[200,
|
1399
|
-
{ 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
|
1400
|
-
[body]]
|
1401
1279
|
end
|
1402
1280
|
end
|
1403
1281
|
|
1282
|
+
before { driver.visit("/") }
|
1283
|
+
|
1404
1284
|
it "submits a form without clicking" do
|
1405
|
-
|
1406
|
-
|
1285
|
+
driver.find("//form")[0].submit
|
1286
|
+
driver.body.should include "Congrats"
|
1407
1287
|
end
|
1408
1288
|
end
|
1409
1289
|
|
1410
|
-
def
|
1411
|
-
|
1412
|
-
|
1413
|
-
|
1414
|
-
<
|
1415
|
-
<
|
1416
|
-
<
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1290
|
+
def driver_for_key_body(event)
|
1291
|
+
driver_for_app do
|
1292
|
+
get "/" do
|
1293
|
+
<<-HTML
|
1294
|
+
<html>
|
1295
|
+
<head><title>Form</title></head>
|
1296
|
+
<body>
|
1297
|
+
<div id="charcode_value"></div>
|
1298
|
+
<div id="keycode_value"></div>
|
1299
|
+
<div id="which_value"></div>
|
1300
|
+
<input type="text" id="charcode" name="charcode" on#{event}="setcharcode" />
|
1301
|
+
<script type="text/javascript">
|
1302
|
+
var element = document.getElementById("charcode")
|
1303
|
+
element.addEventListener("#{event}", setcharcode);
|
1304
|
+
function setcharcode(event) {
|
1305
|
+
var element = document.getElementById("charcode_value");
|
1306
|
+
element.innerHTML = event.charCode;
|
1307
|
+
element = document.getElementById("keycode_value");
|
1308
|
+
element.innerHTML = event.keyCode;
|
1309
|
+
element = document.getElementById("which_value");
|
1310
|
+
element.innerHTML = event.which;
|
1311
|
+
}
|
1312
|
+
</script>
|
1313
|
+
</body>
|
1314
|
+
</html>
|
1315
|
+
HTML
|
1316
|
+
end
|
1317
|
+
end
|
1435
1318
|
end
|
1436
1319
|
|
1437
1320
|
def charCode_for(character)
|
1438
|
-
|
1439
|
-
|
1321
|
+
driver.find("//input")[0].set(character)
|
1322
|
+
driver.find("//div[@id='charcode_value']")[0].text
|
1440
1323
|
end
|
1441
1324
|
|
1442
1325
|
def keyCode_for(character)
|
1443
|
-
|
1444
|
-
|
1326
|
+
driver.find("//input")[0].set(character)
|
1327
|
+
driver.find("//div[@id='keycode_value']")[0].text
|
1445
1328
|
end
|
1446
1329
|
|
1447
1330
|
def which_for(character)
|
1448
|
-
|
1449
|
-
|
1331
|
+
driver.find("//input")[0].set(character)
|
1332
|
+
driver.find("//div[@id='which_value']")[0].text
|
1450
1333
|
end
|
1451
1334
|
|
1452
1335
|
context "keypress app" do
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
[200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]]
|
1457
|
-
end
|
1458
|
-
end
|
1336
|
+
let(:driver) { driver_for_key_body "keypress" }
|
1337
|
+
|
1338
|
+
before { driver.visit("/") }
|
1459
1339
|
|
1460
1340
|
it "returns the charCode for the keypressed" do
|
1461
1341
|
charCode_for("a").should == "97"
|
@@ -1515,38 +1395,236 @@ describe Capybara::Driver::Webkit do
|
|
1515
1395
|
end
|
1516
1396
|
|
1517
1397
|
context "keydown app" do
|
1518
|
-
|
1519
|
-
|
1520
|
-
body = key_app_body("keydown")
|
1521
|
-
[200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]]
|
1522
|
-
end
|
1523
|
-
end
|
1398
|
+
let(:driver) { driver_for_key_body "keydown" }
|
1399
|
+
before { driver.visit("/") }
|
1524
1400
|
it_behaves_like "a keyupdown app"
|
1525
1401
|
end
|
1526
1402
|
|
1527
1403
|
context "keyup app" do
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1404
|
+
let(:driver) { driver_for_key_body "keyup" }
|
1405
|
+
before { driver.visit("/") }
|
1406
|
+
it_behaves_like "a keyupdown app"
|
1407
|
+
end
|
1408
|
+
|
1409
|
+
context "null byte app" do
|
1410
|
+
let(:driver) do
|
1411
|
+
driver_for_html("Hello\0World")
|
1412
|
+
end
|
1413
|
+
|
1414
|
+
before { driver.visit("/") }
|
1415
|
+
|
1416
|
+
it "should include all the bytes in the source" do
|
1417
|
+
driver.source.should == "Hello\0World"
|
1418
|
+
end
|
1419
|
+
end
|
1420
|
+
|
1421
|
+
context "javascript new window app" do
|
1422
|
+
let(:driver) do
|
1423
|
+
driver_for_app do
|
1424
|
+
get '/new_window' do
|
1425
|
+
<<-HTML
|
1426
|
+
<html>
|
1427
|
+
<script type="text/javascript">
|
1428
|
+
window.open('http://#{request.host_with_port}/?#{request.query_string}', 'myWindow');
|
1429
|
+
</script>
|
1430
|
+
<p>bananas</p>
|
1431
|
+
</html>
|
1432
|
+
HTML
|
1433
|
+
end
|
1434
|
+
|
1435
|
+
get "/" do
|
1436
|
+
sleep params['sleep'].to_i if params['sleep']
|
1437
|
+
"<html><head><title>My New Window</title></head><body><p>finished</p></body></html>"
|
1438
|
+
end
|
1532
1439
|
end
|
1533
1440
|
end
|
1534
1441
|
|
1535
|
-
|
1442
|
+
before { driver.visit("/") }
|
1443
|
+
|
1444
|
+
it "has the expected text in the new window" do
|
1445
|
+
driver.visit("/new_window")
|
1446
|
+
driver.within_window(driver.window_handles.last) do
|
1447
|
+
driver.find("//p").first.text.should == "finished"
|
1448
|
+
end
|
1449
|
+
end
|
1450
|
+
|
1451
|
+
it "waits for the new window to load" do
|
1452
|
+
driver.visit("/new_window?sleep=1")
|
1453
|
+
driver.within_window(driver.window_handles.last) do
|
1454
|
+
driver.find("//p").first.text.should == "finished"
|
1455
|
+
end
|
1456
|
+
end
|
1457
|
+
|
1458
|
+
it "waits for the new window to load when the window location has changed" do
|
1459
|
+
driver.visit("/new_window?sleep=2")
|
1460
|
+
driver.execute_script("setTimeout(function() { window.location = 'about:blank' }, 1000)")
|
1461
|
+
driver.within_window(driver.window_handles.last) do
|
1462
|
+
driver.find("//p").first.text.should == "finished"
|
1463
|
+
end
|
1464
|
+
end
|
1465
|
+
|
1466
|
+
it "switches back to the original window" do
|
1467
|
+
driver.visit("/new_window")
|
1468
|
+
driver.within_window(driver.window_handles.last) { }
|
1469
|
+
driver.find("//p").first.text.should == "bananas"
|
1470
|
+
end
|
1471
|
+
|
1472
|
+
it "supports finding a window by name" do
|
1473
|
+
driver.visit("/new_window")
|
1474
|
+
driver.within_window('myWindow') do
|
1475
|
+
driver.find("//p").first.text.should == "finished"
|
1476
|
+
end
|
1477
|
+
end
|
1478
|
+
|
1479
|
+
it "supports finding a window by title" do
|
1480
|
+
driver.visit("/new_window?sleep=5")
|
1481
|
+
driver.within_window('My New Window') do
|
1482
|
+
driver.find("//p").first.text.should == "finished"
|
1483
|
+
end
|
1484
|
+
end
|
1485
|
+
|
1486
|
+
it "supports finding a window by url" do
|
1487
|
+
driver.visit("/new_window?test")
|
1488
|
+
driver.within_window(driver_url(driver, "/?test")) do
|
1489
|
+
driver.find("//p").first.text.should == "finished"
|
1490
|
+
end
|
1491
|
+
end
|
1492
|
+
|
1493
|
+
it "raises an error if the window is not found" do
|
1494
|
+
expect { driver.within_window('myWindowDoesNotExist') }.
|
1495
|
+
to raise_error(Capybara::Webkit::InvalidResponseError)
|
1496
|
+
end
|
1497
|
+
|
1498
|
+
it "has a number of window handles equal to the number of open windows" do
|
1499
|
+
driver.window_handles.size.should == 1
|
1500
|
+
driver.visit("/new_window")
|
1501
|
+
driver.window_handles.size.should == 2
|
1502
|
+
end
|
1503
|
+
|
1504
|
+
it "closes new windows on reset" do
|
1505
|
+
driver.visit("/new_window")
|
1506
|
+
last_handle = driver.window_handles.last
|
1507
|
+
driver.reset!
|
1508
|
+
driver.window_handles.should_not include(last_handle)
|
1509
|
+
end
|
1536
1510
|
end
|
1537
1511
|
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1512
|
+
it "preserves cookies across windows" do
|
1513
|
+
session_id = '12345'
|
1514
|
+
driver = driver_for_app do
|
1515
|
+
get '/new_window' do
|
1516
|
+
<<-HTML
|
1517
|
+
<html>
|
1518
|
+
<script type="text/javascript">
|
1519
|
+
window.open('http://#{request.host_with_port}/set_cookie');
|
1520
|
+
</script>
|
1521
|
+
</html>
|
1522
|
+
HTML
|
1523
|
+
end
|
1524
|
+
|
1525
|
+
get '/set_cookie' do
|
1526
|
+
response.set_cookie 'session_id', session_id
|
1545
1527
|
end
|
1546
1528
|
end
|
1547
1529
|
|
1548
|
-
|
1549
|
-
|
1530
|
+
driver.visit("/new_window")
|
1531
|
+
driver.cookies['session_id'].should == session_id
|
1532
|
+
end
|
1533
|
+
|
1534
|
+
context "timers app" do
|
1535
|
+
let(:driver) do
|
1536
|
+
driver_for_app do
|
1537
|
+
get "/success" do
|
1538
|
+
'<html><body></body></html>'
|
1539
|
+
end
|
1540
|
+
|
1541
|
+
get "/not-found" do
|
1542
|
+
404
|
1543
|
+
end
|
1544
|
+
|
1545
|
+
get "/outer" do
|
1546
|
+
<<-HTML
|
1547
|
+
<html>
|
1548
|
+
<head>
|
1549
|
+
<script>
|
1550
|
+
function emit_true_load_finished(){var divTag = document.createElement("div");divTag.innerHTML = "<iframe src='/success'></iframe>";document.body.appendChild(divTag);};
|
1551
|
+
function emit_false_load_finished(){var divTag = document.createElement("div");divTag.innerHTML = "<iframe src='/not-found'></iframe>";document.body.appendChild(divTag);};
|
1552
|
+
function emit_false_true_load_finished() { emit_false_load_finished(); setTimeout('emit_true_load_finished()',100); };
|
1553
|
+
</script>
|
1554
|
+
</head>
|
1555
|
+
<body onload="setTimeout('emit_false_true_load_finished()',100)">
|
1556
|
+
</body>
|
1557
|
+
</html>
|
1558
|
+
HTML
|
1559
|
+
end
|
1560
|
+
|
1561
|
+
get '/' do
|
1562
|
+
"<html><body></body></html>"
|
1563
|
+
end
|
1564
|
+
end
|
1550
1565
|
end
|
1566
|
+
|
1567
|
+
before { driver.visit("/") }
|
1568
|
+
|
1569
|
+
it "raises error for any loadFinished failure" do
|
1570
|
+
expect do
|
1571
|
+
driver.visit("/outer")
|
1572
|
+
sleep 1
|
1573
|
+
driver.find("//body")
|
1574
|
+
end.to raise_error(Capybara::Webkit::InvalidResponseError)
|
1575
|
+
end
|
1576
|
+
end
|
1577
|
+
|
1578
|
+
describe "basic auth" do
|
1579
|
+
let(:driver) do
|
1580
|
+
driver_for_app do
|
1581
|
+
get "/" do
|
1582
|
+
if env["HTTP_AUTHORIZATION"]
|
1583
|
+
env["HTTP_AUTHORIZATION"]
|
1584
|
+
else
|
1585
|
+
headers "WWW-Authenticate" => 'Basic realm="Secure Area"'
|
1586
|
+
status 401
|
1587
|
+
"401 Unauthorized."
|
1588
|
+
end
|
1589
|
+
end
|
1590
|
+
end
|
1591
|
+
end
|
1592
|
+
|
1593
|
+
it "can authenticate a request" do
|
1594
|
+
driver.browser.authenticate('user', 'password')
|
1595
|
+
driver.visit("/")
|
1596
|
+
driver.body.should include("Basic "+Base64.encode64("user:password").strip)
|
1597
|
+
end
|
1598
|
+
end
|
1599
|
+
|
1600
|
+
describe "logger app" do
|
1601
|
+
it "logs nothing before turning on the logger" do
|
1602
|
+
driver.visit("/")
|
1603
|
+
log.should == ""
|
1604
|
+
end
|
1605
|
+
|
1606
|
+
it "logs its commands after turning on the logger" do
|
1607
|
+
driver.enable_logging
|
1608
|
+
driver.visit("/")
|
1609
|
+
log.should_not == ""
|
1610
|
+
end
|
1611
|
+
|
1612
|
+
let(:driver) do
|
1613
|
+
command = "#{Capybara::Webkit::Connection::SERVER_PATH} 2>&1"
|
1614
|
+
connection = Capybara::Webkit::Connection.new(:command => command, :stdout => output)
|
1615
|
+
browser = Capybara::Webkit::Browser.new(connection)
|
1616
|
+
Capybara::Webkit::Driver.new(AppRunner.app, :browser => browser)
|
1617
|
+
end
|
1618
|
+
|
1619
|
+
let(:output) { StringIO.new }
|
1620
|
+
|
1621
|
+
def log
|
1622
|
+
output.rewind
|
1623
|
+
output.read
|
1624
|
+
end
|
1625
|
+
end
|
1626
|
+
|
1627
|
+
def driver_url(driver, path)
|
1628
|
+
URI.parse(driver.current_url).merge(path).to_s
|
1551
1629
|
end
|
1552
1630
|
end
|