otherinbox-capybara-webkit 0.12.0 → 0.12.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. data/GOALS +9 -0
  2. data/README.md +1 -1
  3. data/capybara-webkit.gemspec +1 -1
  4. data/lib/capybara/webkit.rb +11 -4
  5. data/lib/capybara/{driver/webkit → webkit}/browser.rb +27 -3
  6. data/lib/capybara/{driver/webkit → webkit}/connection.rb +45 -47
  7. data/lib/capybara/{driver/webkit → webkit}/cookie_jar.rb +1 -1
  8. data/lib/capybara/webkit/driver.rb +150 -0
  9. data/lib/capybara/webkit/errors.rb +10 -0
  10. data/lib/capybara/{driver/webkit → webkit}/node.rb +2 -2
  11. data/lib/capybara/{driver/webkit → webkit}/socket_debugger.rb +1 -1
  12. data/lib/capybara/{driver/webkit → webkit}/version.rb +1 -1
  13. data/lib/capybara_webkit_builder.rb +17 -3
  14. data/spec/browser_spec.rb +38 -25
  15. data/spec/connection_spec.rb +5 -5
  16. data/spec/cookie_jar_spec.rb +3 -3
  17. data/spec/driver_rendering_spec.rb +19 -26
  18. data/spec/driver_resize_window_spec.rb +3 -3
  19. data/spec/driver_spec.rb +907 -829
  20. data/spec/integration/driver_spec.rb +4 -3
  21. data/spec/spec_helper.rb +14 -6
  22. data/spec/support/app_runner.rb +91 -0
  23. data/src/Authenticate.cpp +18 -0
  24. data/src/Authenticate.h +12 -0
  25. data/src/Body.h +3 -5
  26. data/src/ClearCookies.cpp +3 -5
  27. data/src/ClearCookies.h +3 -5
  28. data/src/Command.cpp +4 -15
  29. data/src/Command.h +3 -14
  30. data/src/CommandFactory.cpp +10 -6
  31. data/src/CommandFactory.h +3 -2
  32. data/src/CommandParser.cpp +1 -1
  33. data/src/Connection.cpp +22 -11
  34. data/src/Connection.h +4 -2
  35. data/src/ConsoleMessages.cpp +2 -1
  36. data/src/ConsoleMessages.h +3 -5
  37. data/src/CurrentUrl.cpp +2 -1
  38. data/src/CurrentUrl.h +3 -5
  39. data/src/EnableLogging.cpp +10 -0
  40. data/src/EnableLogging.h +12 -0
  41. data/src/Evaluate.cpp +2 -1
  42. data/src/Evaluate.h +3 -5
  43. data/src/Execute.cpp +2 -1
  44. data/src/Execute.h +3 -5
  45. data/src/Find.cpp +3 -2
  46. data/src/Find.h +3 -5
  47. data/src/FrameFocus.cpp +3 -2
  48. data/src/FrameFocus.h +3 -4
  49. data/src/GetCookies.cpp +3 -4
  50. data/src/GetCookies.h +3 -5
  51. data/src/GetWindowHandle.cpp +11 -0
  52. data/src/GetWindowHandle.h +10 -0
  53. data/src/GetWindowHandles.cpp +20 -0
  54. data/src/GetWindowHandles.h +10 -0
  55. data/src/Header.cpp +2 -1
  56. data/src/Header.h +3 -5
  57. data/src/Headers.cpp +2 -1
  58. data/src/Headers.h +3 -5
  59. data/src/IgnoreSslErrors.cpp +4 -3
  60. data/src/IgnoreSslErrors.h +3 -5
  61. data/src/JavascriptInvocation.cpp +1 -1
  62. data/src/JavascriptInvocation.h +1 -1
  63. data/src/NetworkAccessManager.cpp +19 -1
  64. data/src/NetworkAccessManager.h +10 -0
  65. data/src/Node.cpp +6 -1
  66. data/src/Node.h +4 -5
  67. data/src/NullCommand.cpp +5 -2
  68. data/src/NullCommand.h +4 -3
  69. data/src/PageLoadingCommand.cpp +12 -7
  70. data/src/PageLoadingCommand.h +6 -9
  71. data/src/Render.cpp +2 -1
  72. data/src/Render.h +3 -5
  73. data/src/RequestedUrl.cpp +2 -1
  74. data/src/RequestedUrl.h +3 -5
  75. data/src/Reset.cpp +3 -17
  76. data/src/Reset.h +3 -8
  77. data/src/ResizeWindow.cpp +2 -1
  78. data/src/ResizeWindow.h +3 -5
  79. data/src/Server.cpp +2 -3
  80. data/src/Server.h +0 -2
  81. data/src/SetCookie.cpp +3 -4
  82. data/src/SetCookie.h +3 -5
  83. data/src/SetProxy.cpp +2 -1
  84. data/src/SetProxy.h +3 -5
  85. data/src/SetSkipImageLoading.cpp +3 -2
  86. data/src/SetSkipImageLoading.h +3 -5
  87. data/src/SocketCommand.cpp +21 -0
  88. data/src/SocketCommand.h +29 -0
  89. data/src/Source.cpp +2 -1
  90. data/src/Source.h +3 -4
  91. data/src/Status.cpp +2 -1
  92. data/src/Status.h +3 -5
  93. data/src/UnsupportedContentHandler.cpp +1 -1
  94. data/src/Url.cpp +2 -1
  95. data/src/Url.h +3 -5
  96. data/src/Visit.cpp +3 -2
  97. data/src/Visit.h +3 -5
  98. data/src/WebPage.cpp +86 -39
  99. data/src/WebPage.h +22 -8
  100. data/src/WebPageManager.cpp +117 -0
  101. data/src/WebPageManager.h +56 -0
  102. data/src/WindowFocus.cpp +32 -0
  103. data/src/WindowFocus.h +15 -0
  104. data/src/body.cpp +2 -1
  105. data/src/find_command.h +6 -2
  106. data/src/webkit_server.pro +14 -0
  107. data/templates/Command.cpp +2 -4
  108. data/templates/Command.h +3 -3
  109. metadata +29 -10
  110. data/lib/capybara/driver/webkit.rb +0 -135
@@ -1,7 +1,7 @@
1
1
  module Capybara
2
2
  module Driver
3
3
  class Webkit
4
- VERSION = '0.12.0'.freeze
4
+ VERSION = '0.12.0.1'.freeze
5
5
  end
6
6
  end
7
7
  end
@@ -4,6 +4,9 @@ require "rbconfig"
4
4
  module CapybaraWebkitBuilder
5
5
  extend self
6
6
 
7
+ SUCCESS_STATUS = 0
8
+ COMMAND_NOT_FOUND_STATUS = 127
9
+
7
10
  def make_bin
8
11
  ENV['MAKE'] || 'make'
9
12
  end
@@ -29,12 +32,23 @@ module CapybaraWebkitBuilder
29
32
  end
30
33
  end
31
34
 
35
+ def sh(command)
36
+ system(command)
37
+ success = $?.exitstatus == SUCCESS_STATUS
38
+ if $?.exitstatus == COMMAND_NOT_FOUND_STATUS
39
+ puts "Command '#{command}' not available"
40
+ elsif !success
41
+ puts "Command '#{command}' failed"
42
+ end
43
+ success
44
+ end
45
+
32
46
  def makefile
33
- system("#{qmake_bin} -spec #{spec}")
47
+ sh("#{qmake_bin} -spec #{spec}")
34
48
  end
35
49
 
36
50
  def qmake
37
- system("#{make_bin} qmake")
51
+ sh("#{make_bin} qmake")
38
52
  end
39
53
 
40
54
  def path_to_binary
@@ -47,7 +61,7 @@ module CapybaraWebkitBuilder
47
61
  end
48
62
 
49
63
  def build
50
- system(make_bin) or return false
64
+ sh(make_bin) or return false
51
65
 
52
66
  FileUtils.mkdir("bin") unless File.directory?("bin")
53
67
  FileUtils.cp(path_to_binary, "bin", :preserve => true)
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/driver/webkit/browser'
5
- require 'capybara/driver/webkit/connection'
4
+ require 'capybara/webkit/driver'
6
5
  require 'socket'
7
6
  require 'base64'
8
7
 
9
- describe Capybara::Driver::Webkit::Browser do
8
+ describe Capybara::Webkit::Browser do
10
9
 
11
- let(:browser) { Capybara::Driver::Webkit::Browser.new(Capybara::Driver::Webkit::Connection.new) }
10
+ let(:browser) { Capybara::Webkit::Browser.new(Capybara::Webkit::Connection.new) }
12
11
  let(:browser_ignore_ssl_err) do
13
- Capybara::Driver::Webkit::Browser.new(Capybara::Driver::Webkit::Connection.new).tap do |browser|
12
+ Capybara::Webkit::Browser.new(Capybara::Webkit::Connection.new).tap do |browser|
14
13
  browser.ignore_ssl_errors
15
14
  end
16
15
  end
17
16
  let(:browser_skip_images) do
18
- Capybara::Driver::Webkit::Browser.new(Capybara::Driver::Webkit::Connection.new).tap do |browser|
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(@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
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
- @received_requests << request.join("\n")
95
+ @received_requests << request.join("\n")
84
96
 
85
- # write response
86
- html = <<-HTML
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
- 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
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::Driver::Webkit::Browser.new(connection)
257
+ browser = Capybara::Webkit::Browser.new(connection)
245
258
 
246
259
  expect { browser.visit("/") }.not_to raise_error(/empty response/)
247
260
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
- require 'capybara/driver/webkit/connection'
2
+ require 'capybara/webkit/connection'
3
3
 
4
- describe Capybara::Driver::Webkit::Connection do
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::Driver::Webkit::Connection.new(:stdout => io)
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::Driver::Webkit::Connection.new
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::Driver::Webkit::Connection.new }
42
+ let(:connection) { Capybara::Webkit::Connection.new }
43
43
 
44
44
  before(:all) do
45
45
  @app = lambda do |env|
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
- require 'capybara/driver/webkit/cookie_jar'
2
+ require 'capybara/webkit/cookie_jar'
3
3
 
4
- describe Capybara::Driver::Webkit::CookieJar do
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::Driver::Webkit::CookieJar.new(browser) }
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/webkit'
2
+ require 'capybara/webkit/driver'
3
3
  require 'mini_magick'
4
4
 
5
- describe Capybara::Driver::Webkit, "rendering an image" do
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(:all) do
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
- @driver.render @file_name, options
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(:all){ render({}) }
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(:all){ render(:width => 500, :height => 400) }
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(:all){ render(:width => 50, :height => 10) }
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/webkit'
2
+ require 'capybara/webkit/driver'
3
3
 
4
- describe Capybara::Driver::Webkit, "#resize_window(width, height)" do
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::Webkit.new(app, :browser => $webkit_browser)
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/webkit'
2
+ require 'capybara/webkit/driver'
3
+ require 'base64'
3
4
 
4
- describe Capybara::Driver::Webkit do
5
- subject { Capybara::Driver::Webkit.new(@app, :browser => $webkit_browser) }
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
- before(:all) do
11
- @app = lambda do |env|
12
- params = ::Rack::Utils.parse_query(env['QUERY_STRING'])
13
- if params["iframe"] == "true"
14
- # We are in an iframe request.
15
- p_id = "farewell"
16
- msg = "goodbye"
17
- iframe = nil
18
- else
19
- # We are not in an iframe request and need to make an iframe!
20
- p_id = "greeting"
21
- msg = "hello"
22
- iframe = "<iframe id=\"f\" src=\"/?iframe=true\"></iframe>"
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
- subject.within_frame(0) do
47
- subject.find("//*[contains(., 'goodbye')]").should_not be_empty
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
- subject.within_frame("f") do
53
- subject.find("//*[contains(., 'goodbye')]").should_not be_empty
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 { subject.within_frame(1) { } }.
59
- to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError)
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 { subject.within_frame("foo") { } }.
64
- to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError)
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
- subject.within_frame("f") do
69
- subject.find("//p").first["id"].should == "farewell"
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
- subject.within_frame("f") do
75
- subject.find("//p").first.text.should == "goodbye"
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
- subject.within_frame("f") do
81
- port = subject.instance_variable_get("@rack_server").port
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
- subject.within_frame("f") do
88
- subject.source.should =~ %r{<html>.*farewell.*}m
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
- subject.within_frame("f") do
94
- result = subject.evaluate_script(%<document.getElementById('farewell').innerText>)
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
- subject.within_frame("f") do
101
- subject.execute_script(%<document.getElementById('farewell').innerHTML = 'yo'>)
102
- subject.find("//p[contains(., 'yo')]").should_not be_empty
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
- before(:all) do
109
- @app = lambda do |env|
110
- if env['PATH_INFO'] == '/target'
111
- content_type = "<p>#{env['CONTENT_TYPE']}</p>"
112
- [200, {"Content-Type" => "text/html", "Content-Length" => content_type.length.to_s}, [content_type]]
113
- elsif env['PATH_INFO'] == '/form'
114
- body = <<-HTML
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
- [200, {"Content-Type" => "text/html", "Content-Length" => body.length.to_s}, [body]]
124
- else
125
- [301, {"Location" => "/target"}, [""]]
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
- subject.visit("/form")
132
- subject.find("//input").first.click
133
- subject.find("//p").first.text.should == ""
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
- subject.visit("/redirect-me")
138
- port = subject.instance_variable_get("@rack_server").port
139
- subject.execute_script("window.history.pushState({}, '', '/pushed-after-redirect')")
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
- subject.visit("/redirect-me")
145
- port = subject.instance_variable_get("@rack_server").port
146
- subject.execute_script("window.history.replaceState({}, '', '/replaced-after-redirect')")
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
- before(:all) do
153
- body = "css"
154
- @app = lambda do |env|
155
- [200, {"Content-Type" => "text/css", "Content-Length" => body.length.to_s}, [body]]
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
- subject.body.should =~ /css/
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
- subject.response_headers["Content-Type"].should == "text/css"
194
+ driver.response_headers["Content-Type"].should == "text/css"
166
195
  end
167
196
  end
168
197
 
169
198
  context "hello app" do
170
- before(:all) do
171
- @app = lambda do |env|
172
- body = <<-HTML
173
- <html>
174
- <head>
175
- <style type="text/css">
176
- #display_none { display: none }
177
- </style>
178
- </head>
179
- <body>
180
- <div class='normalize'>Spaces&nbsp;not&nbsp;normalized&nbsp;</div>
181
- <div id="display_none">
182
- <div id="invisible">Can't see me</div>
183
- </div>
184
- <input type="text" disabled="disabled"/>
185
- <input id="checktest" type="checkbox" checked="checked"/>
186
- <script type="text/javascript">
187
- document.write("<p id='greeting'>he" + "llo</p>");
188
- </script>
189
- </body>
190
- </html>
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&nbsp;not&nbsp;normalized&nbsp;</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
- subject.visit("#test")
200
- subject.find("//*[contains(., 'hello')]").should_not be_empty
201
- subject.visit("#test")
202
- subject.find("//*[contains(., 'hello')]").should_not be_empty
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
- subject.find("//*[contains(., 'hello')]").should_not be_empty
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
- subject.reset!
211
- subject.find("//*[contains(., 'hello')]").should be_empty
236
+ driver.reset!
237
+ driver.find("//*[contains(., 'hello')]").should be_empty
212
238
  end
213
239
 
214
- it "has a location of 'about:blank' after reseting" do
215
- subject.reset!
216
- subject.current_url.should == "about:blank"
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 { subject.find("totally invalid salad") }.
221
- to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError, /xpath/i)
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
- subject.find("//p").first["id"].should == "greeting"
251
+ driver.find("//p").first["id"].should == "greeting"
226
252
  end
227
253
 
228
254
  it "parses xpath with quotes" do
229
- subject.find('//*[contains(., "hello")]').should_not be_empty
255
+ driver.find('//*[contains(., "hello")]').should_not be_empty
230
256
  end
231
257
 
232
258
  it "returns a node's text" do
233
- subject.find("//p").first.text.should == "hello"
259
+ driver.find("//p").first.text.should == "hello"
234
260
  end
235
261
 
236
262
  it "normalizes a node's text" do
237
- subject.find("//div[contains(@class, 'normalize')]").first.text.should == "Spaces not normalized"
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
- port = subject.instance_variable_get("@rack_server").port
242
- subject.current_url.should == "http://127.0.0.1:#{port}/hello/world?success=true"
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
- port = subject.instance_variable_get("@rack_server").port
247
- subject.execute_script("window.history.pushState({}, '', '/pushed')")
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
- port = subject.instance_variable_get("@rack_server").port
253
- subject.execute_script("window.history.replaceState({}, '', '/replaced')")
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
- subject.visit("/hello/world?success=%25true")
259
- subject.current_url.should =~ /success=\%25true/
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
- subject.visit("/hello#display_none")
264
- subject.current_url.should =~ /hello#display_none/
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
- subject.source.should =~ %r{<html>.*greeting.*}m
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 = subject.evaluate_script(%<document.getElementById('greeting').innerText>)
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 = subject.evaluate_script(%<["hello", "world"]>)
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 = subject.evaluate_script(%<123>)
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 = subject.evaluate_script(%<1.5>)
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 = subject.evaluate_script(%<(function () {})()>)
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 = subject.evaluate_script(%<({ 'one' : 1 })>)
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 = subject.evaluate_script(%<true>)
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 = subject.evaluate_script(%<false>)
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 = subject.evaluate_script(%<'"'>)
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 = subject.evaluate_script("[1,\n2]")
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
- subject.execute_script(%<document.getElementById('greeting').innerHTML = 'yo'>)
323
- subject.find("//p[contains(., 'yo')]").should_not be_empty
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 { subject.execute_script(%<invalid salad>) }.
328
- to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError)
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 { subject.execute_script(%<(function () { "returns nothing" })()>) }.
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
- subject.find("//p").first.tag_name.should == "p"
361
+ driver.find("//p").first.tag_name.should == "p"
338
362
  end
339
363
 
340
364
  it "reads disabled property" do
341
- subject.find("//input").first.should be_disabled
365
+ driver.find("//input").first.should be_disabled
342
366
  end
343
367
 
344
368
  it "reads checked property" do
345
- subject.find("//input[@id='checktest']").first.should be_checked
369
+ driver.find("//input[@id='checktest']").first.should be_checked
346
370
  end
347
371
 
348
372
  it "finds visible elements" do
349
- subject.find("//p").first.should be_visible
350
- subject.find("//*[@id='invisible']").first.should_not be_visible
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
- before(:all) do
357
- @app = lambda do |env|
358
- body = <<-HTML
359
- <html>
360
- <head>
361
- </head>
362
- <body>
363
- <script type="text/javascript">
364
- console.log("hello");
365
- console.log("hello again");
366
- oops
367
- </script>
368
- </body>
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
- subject.console_messages.first.should include :source, :message => "hello", :line_number => 6
379
- subject.console_messages.length.should eq 3
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
- subject.error_messages.length.should eq 1
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
- before(:all) do
390
- @app = lambda do |env|
391
- body = <<-HTML
392
- <html><body>
393
- <form action="/" method="GET">
394
- <input type="text" name="foo" value="bar"/>
395
- <input type="text" name="maxlength_foo" value="bar" maxlength="10"/>
396
- <input type="text" id="disabled_input" disabled="disabled"/>
397
- <input type="checkbox" name="checkedbox" value="1" checked="checked"/>
398
- <input type="checkbox" name="uncheckedbox" value="2"/>
399
- <select name="animal">
400
- <option id="select-option-monkey">Monkey</option>
401
- <option id="select-option-capybara" selected="selected">Capybara</option>
402
- </select>
403
- <select name="toppings" multiple="multiple">
404
- <optgroup label="Mediocre Toppings">
405
- <option selected="selected" id="topping-apple">Apple</option>
406
- <option selected="selected" id="topping-banana">Banana</option>
407
- </optgroup>
408
- <optgroup label="Best Toppings">
409
- <option selected="selected" id="topping-cherry">Cherry</option>
410
- </optgroup>
411
- </select>
412
- <textarea id="only-textarea">what a wonderful area for text</textarea>
413
- <input type="radio" id="only-radio" value="1"/>
414
- <button type="reset">Reset Form</button>
415
- </form>
416
- </body></html>
417
- HTML
418
- [200,
419
- { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
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
- subject.find("//textarea").first.value.should == "what a wonderful area for text"
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
- subject.find("//input").first.value.should == "bar"
446
+ driver.find("//input").first.value.should == "bar"
430
447
  end
431
448
 
432
449
  it "returns a select's value" do
433
- subject.find("//select").first.value.should == "Capybara"
450
+ driver.find("//select").first.value.should == "Capybara"
434
451
  end
435
452
 
436
453
  it "sets an input's value" do
437
- input = subject.find("//input").first
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 = subject.find("//input[@name='maxlength_foo']").first
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 = subject.find("//input[@name='maxlength_foo']").first
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 = subject.find("//input[@name='maxlength_foo']").first
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 = subject.find("//input").first
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 = subject.find("//select").first
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 = subject.find("//textarea").first
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) { subject.find("//option[@id='select-option-monkey']").first }
479
- let(:capybara_option) { subject.find("//option[@id='select-option-capybara']").first }
480
- let(:animal_select) { subject.find("//select[@name='animal']").first }
481
- let(:apple_option) { subject.find("//option[@id='topping-apple']").first }
482
- let(:banana_option) { subject.find("//option[@id='topping-banana']").first }
483
- let(:cherry_option) { subject.find("//option[@id='topping-cherry']").first }
484
- let(:toppings_select) { subject.find("//select[@name='toppings']").first }
485
- let(:reset_button) { subject.find("//button[@type='reset']").first }
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) { subject.find("//input[@name='checkedbox']").first }
541
- let(:unchecked_box) { subject.find("//input[@name='uncheckedbox']").first }
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) { subject.find("//input[@name='foo']").first }
580
- let(:disabled_input) { subject.find("//input[@id='disabled_input']").first }
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
- before(:all) do
593
- @app = lambda do |env|
594
- body = <<-HTML
595
-
596
- <html><body>
597
- <a href='#' class='watch'>Link</a>
598
- <ul id="events"></ul>
599
- <script type="text/javascript">
600
- var events = document.getElementById("events");
601
- var recordEvent = function (event) {
602
- var element = document.createElement("li");
603
- element.innerHTML = event.type;
604
- events.appendChild(element);
605
- };
606
-
607
- var elements = document.getElementsByClassName("watch");
608
- for (var i = 0; i < elements.length; i++) {
609
- var element = elements[i];
610
- element.addEventListener("mousedown", recordEvent);
611
- element.addEventListener("mouseup", recordEvent);
612
- element.addEventListener("click", recordEvent);
613
- }
614
- </script>
615
- </body></html>
616
- HTML
617
- [200,
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
- subject.find("//a").first.click
625
- subject.find("//li").map(&:text).should == %w(mousedown mouseup click)
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
- before(:all) do
631
- @app = lambda do |env|
632
- body = <<-HTML
633
- <html><body>
634
- <form action="/" method="GET">
635
- <input class="watch" type="email"/>
636
- <input class="watch" type="number"/>
637
- <input class="watch" type="password"/>
638
- <input class="watch" type="search"/>
639
- <input class="watch" type="tel"/>
640
- <input class="watch" type="text"/>
641
- <input class="watch" type="url"/>
642
- <textarea class="watch"></textarea>
643
- <input class="watch" type="checkbox"/>
644
- <input class="watch" type="radio"/>
645
- </form>
646
- <ul id="events"></ul>
647
- <script type="text/javascript">
648
- var events = document.getElementById("events");
649
- var recordEvent = function (event) {
650
- var element = document.createElement("li");
651
- element.innerHTML = event.type;
652
- events.appendChild(element);
653
- };
654
-
655
- var elements = document.getElementsByClassName("watch");
656
- for (var i = 0; i < elements.length; i++) {
657
- var element = elements[i];
658
- element.addEventListener("focus", recordEvent);
659
- element.addEventListener("keydown", recordEvent);
660
- element.addEventListener("keypress", recordEvent);
661
- element.addEventListener("keyup", recordEvent);
662
- element.addEventListener("input", recordEvent);
663
- element.addEventListener("change", recordEvent);
664
- element.addEventListener("blur", recordEvent);
665
- element.addEventListener("mousedown", recordEvent);
666
- element.addEventListener("mouseup", recordEvent);
667
- element.addEventListener("click", recordEvent);
668
- }
669
- </script>
670
- </body></html>
671
- HTML
672
- [200,
673
- { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
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
- subject.find("//input[@type='#{field_type}']").first.set(newtext)
689
- subject.find("//li").map(&:text).should == keyevents
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
- subject.find("//textarea").first.set(newtext)
695
- subject.find("//li").map(&:text).should == keyevents
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
- subject.find("//input[@type='radio']").first.set(true)
700
- subject.find("//li").map(&:text).should == %w(mousedown mouseup change click)
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
- subject.find("//input[@type='checkbox']").first.set(true)
705
- subject.find("//li").map(&:text).should == %w(mousedown mouseup change click)
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
- before(:all) do
711
- @app =lambda do |env|
712
- body = <<-HTML
713
- <html><body>
714
- <div id="change">Change me</div>
715
- <div id="mouseup">Push me</div>
716
- <div id="mousedown">Release me</div>
717
- <form action="/" method="GET">
718
- <select id="change_select" name="change_select">
719
- <option value="1" id="option-1" selected="selected">one</option>
720
- <option value="2" id="option-2">two</option>
721
- </select>
722
- </form>
723
- <script type="text/javascript">
724
- document.getElementById("change_select").
725
- addEventListener("change", function () {
726
- this.className = "triggered";
727
- });
728
- document.getElementById("change").
729
- addEventListener("change", function () {
730
- this.className = "triggered";
731
- });
732
- document.getElementById("mouseup").
733
- addEventListener("mouseup", function () {
734
- this.className = "triggered";
735
- });
736
- document.getElementById("mousedown").
737
- addEventListener("mousedown", function () {
738
- this.className = "triggered";
739
- });
740
- </script>
741
- <a href="/next">Next</a>
742
- </body></html>
743
- HTML
744
- [200,
745
- { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
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
- subject.find("//a").first.click
752
- subject.current_url =~ %r{/next$}
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
- subject.find("//*[@id='mouseup']").first.trigger("mouseup")
757
- subject.find("//*[@class='triggered']").should_not be_empty
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
- subject.find("//*[@id='change']").first.trigger("change")
762
- subject.find("//*[@class='triggered']").should_not be_empty
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 = subject.find("//select").first
773
+ select = driver.find("//select").first
767
774
  select.value.should == "1"
768
- option = subject.find("//option[@id='option-2']").first
775
+ option = driver.find("//option[@id='option-2']").first
769
776
  option.select_option
770
777
  select.value.should == "2"
771
- subject.find("//select[@class='triggered']").should_not be_empty
778
+ driver.find("//select[@class='triggered']").should_not be_empty
772
779
  end
773
780
 
774
781
  it "fires drag events" do
775
- draggable = subject.find("//*[@id='mousedown']").first
776
- container = subject.find("//*[@id='mouseup']").first
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
- subject.find("//*[@class='triggered']").size.should == 1
787
+ driver.find("//*[@class='triggered']").size.should == 1
781
788
  end
782
789
  end
783
790
 
784
791
  context "nesting app" do
785
- before(:all) do
786
- @app = lambda do |env|
787
- body = <<-HTML
788
- <html><body>
789
- <div id="parent">
790
- <div class="find">Expected</div>
791
- </div>
792
- <div class="find">Unexpected</div>
793
- </body></html>
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 = subject.find("//*[@id='parent']").first
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
- before(:all) do
809
- @result = ""
810
- @app = lambda do |env|
811
- if env["PATH_INFO"] == "/result"
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
- @result << "finished"
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
- it "waits for a request to load" do
823
- subject.find("//a").first.click
824
- @result.should == "finished"
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
- before(:all) do
830
- @app = lambda do |env|
831
- if env['PATH_INFO'] == "/error"
832
- [404, {}, []]
833
- else
834
- body = <<-HTML
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
- subject.find("//input").first.click
852
+ driver.find("//input").first.click
849
853
  wait_for_error_to_complete
850
- subject.find("//body")
854
+ driver.find("//body")
851
855
  }.
852
- to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError, %r{/error})
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
- before(:all) do
862
- @app = lambda do |env|
863
- if env['PATH_INFO'] == "/error"
864
- body = "error"
865
+ let(:driver) do
866
+ driver_for_app do
867
+ get "/error" do
865
868
  sleep(1)
866
- [304, {}, []]
867
- else
868
- body = <<-HTML
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
- subject.find("//input").first.click
883
- expect { subject.find("//p") }.to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError)
884
- subject.visit("/")
885
- subject.find("//p").first.text.should == "hello"
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
- before(:all) do
891
- @app = lambda do |env|
892
- body = <<-HTML
893
- <html><body>
894
- <script type="text/javascript">
895
- alert("alert");
896
- confirm("confirm");
897
- prompt("prompt");
898
- </script>
899
- <p>success</p>
900
- </body></html>
901
- HTML
902
- sleep(0.5)
903
- [200,
904
- { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
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
- subject.find("//p").first.text.should == "success"
915
+ driver.find("//p").first.text.should == "success"
911
916
  end
912
917
  end
913
918
 
914
919
  context "custom header" do
915
- before(:all) do
916
- @app = lambda do |env|
917
- body = <<-HTML
918
- <html><body>
919
- <p id="user-agent">#{env['HTTP_USER_AGENT']}</p>
920
- <p id="x-capybara-webkit-header">#{env['HTTP_X_CAPYBARA_WEBKIT_HEADER']}</p>
921
- <p id="accept">#{env['HTTP_ACCEPT']}</p>
922
- <a href="/">/</a>
923
- </body></html>
924
- HTML
925
- [200,
926
- { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
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
- subject.header('user-agent', 'capybara-webkit/custom-user-agent')
933
- subject.header('x-capybara-webkit-header', 'x-capybara-webkit-header')
934
- subject.header('accept', 'text/html')
935
- subject.visit('/')
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
- subject.find('id("user-agent")').first.text.should == 'capybara-webkit/custom-user-agent'
940
- subject.evaluate_script('navigator.userAgent').should == 'capybara-webkit/custom-user-agent'
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
- subject.find("//a").first.click
945
- subject.find('id("user-agent")').first.text.should == 'capybara-webkit/custom-user-agent'
946
- subject.evaluate_script('navigator.userAgent').should == 'capybara-webkit/custom-user-agent'
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
- subject.find('id("x-capybara-webkit-header")').first.text.should == 'x-capybara-webkit-header'
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
- subject.find('id("accept")').first.text.should == 'text/html'
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
- subject.reset!
959
- subject.visit('/')
960
- subject.find('id("user-agent")').first.text.should_not == 'capybara-webkit/custom-user-agent'
961
- subject.evaluate_script('navigator.userAgent').should_not == 'capybara-webkit/custom-user-agent'
962
- subject.find('id("x-capybara-webkit-header")').first.text.should be_empty
963
- subject.find('id("accept")').first.text.should_not == 'text/html'
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
- before(:all) do
969
- @app = lambda do |env|
970
- body = <<-HTML
971
- <html><body>
972
- <form action="/error"><input type="submit"/></form>
973
- </body></html>
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
- subject.find("//body")
987
+ driver.find("//body")
985
988
  }.
986
- to raise_error(Capybara::Driver::Webkit::WebkitNoResponseError, %r{response})
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
- subject.browser.instance_variable_get(:@connection).unstub!(:gets)
992
- subject.browser.instance_variable_get(:@connection).unstub!(:puts)
993
- subject.browser.instance_variable_get(:@connection).unstub!(:print)
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
- subject.browser.instance_variable_get(:@connection).stub!(:gets).and_return(nil)
998
- subject.browser.instance_variable_get(:@connection).stub!(:puts)
999
- subject.browser.instance_variable_get(:@connection).stub!(:print)
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
- before(:all) do
1005
- @app = lambda do |env|
1006
- body = <<-HTML
1007
- <html>
1008
- <head>
1009
- <style type="text/css">
1010
- p { font-family: "Verdana"; }
1011
- </style>
1012
- </head>
1013
- <body>
1014
- <p id="text">Hello</p>
1015
- </body>
1016
- </html>
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 = subject.evaluate_script(<<-SCRIPT)
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
- before(:all) do
1035
- @cookie = 'cookie=abc; domain=127.0.0.1; path=/'
1036
- @app = lambda do |env|
1037
- request = ::Rack::Request.new(env)
1038
-
1039
- body = <<-HTML
1040
- <html><body>
1041
- <p id="cookie">#{request.cookies["cookie"] || ""}</p>
1042
- </body></html>
1043
- HTML
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
- subject.find('id("cookie")').first.text
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
- subject.visit "/"
1055
+ driver.visit "/"
1060
1056
  echoed_cookie.should == "abc"
1061
1057
  end
1062
1058
 
1063
1059
  it "uses a custom cookie" do
1064
- subject.browser.set_cookie @cookie
1065
- subject.visit "/"
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
- subject.browser.clear_cookies
1071
- subject.visit "/"
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 = subject.browser.get_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
- subject.cookies["cookie"].should == "abc"
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
- before(:all) do
1131
- @app = lambda do |env|
1132
- body = <<-HTML
1133
- <html>
1134
- <div id="parent">
1135
- <p id="removeMe">Hello</p>
1136
- </div>
1137
- </html>
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 = subject.find("//p[@id='removeMe']").first
1156
- subject.evaluate_script("document.getElementById('parent').innerHTML = 'Magic'")
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
- before(:all) do
1163
- @app = lambda do |env|
1164
- body = <<-HTML
1165
- <html>
1166
- <head>
1167
- <title>My eBook</title>
1168
- <meta class="charset" name="charset" value="utf-8" />
1169
- <meta class="author" name="author" value="Firstname Lastname" />
1170
- </head>
1171
- <body>
1172
- <div id="toc">
1173
- <table>
1174
- <thead id="head">
1175
- <tr><td class="td1">Chapter</td><td>Page</td></tr>
1176
- </thead>
1177
- <tbody>
1178
- <tr><td>Intro</td><td>1</td></tr>
1179
- <tr><td>Chapter 1</td><td class="td2">1</td></tr>
1180
- <tr><td>Chapter 2</td><td>1</td></tr>
1181
- </tbody>
1182
- </table>
1183
- </div>
1184
-
1185
- <h1 class="h1">My first book</h1>
1186
- <p class="p1">Written by me</p>
1187
- <div id="intro" class="intro">
1188
- <p>Let's try out XPath</p>
1189
- <p class="p2">in capybara-webkit</p>
1190
- </div>
1191
-
1192
- <h2 class="chapter1">Chapter 1</h2>
1193
- <p>This paragraph is fascinating.</p>
1194
- <p class="p3">But not as much as this one.</p>
1195
-
1196
- <h2 class="chapter2">Chapter 2</h2>
1197
- <p>Let's try if we can select this</p>
1198
- </body>
1199
- </html>
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 = subject.find(xpath)
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
- before(:all) do
1229
- @app = lambda do |env|
1230
- body = <<-HTML
1231
- <html>
1232
- <head>
1233
- <style type="text/css">
1234
- #overflow { overflow: hidden }
1235
- </style>
1236
- </head>
1237
- <body>
1238
- <div id="overflow">Overflow</div>
1239
- </body>
1240
- </html>
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
- subject.find("//div[@id='overflow']").first.text.should == "Overflow"
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
- before(:all) do
1255
- @app = lambda do |env|
1256
- if env['PATH_INFO'] == '/redirect'
1257
- body = <<-HTML
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 = "/next";
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
- [200,
1268
- { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
1269
- [body]]
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
- subject.visit("/redirect")
1276
- subject.find("//p").first.text.should == "finished"
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
- before(:all) do
1283
- @app = lambda do |env|
1284
- body = <<-HTML
1285
- <html>
1286
- <body>
1287
- <span id='output'></span>
1288
- <script type="text/javascript">
1289
- if (typeof localStorage !== "undefined") {
1290
- if (!localStorage.refreshCounter) {
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
- </script>
1298
- </body>
1299
- </html>
1300
- HTML
1301
- [200,
1302
- { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
1303
- [body]]
1304
- end
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
- it "builds up node paths correctly" do
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
- cases.each do |xpath, path|
1373
- nodes = subject.find(xpath)
1374
- nodes.size.should == 1
1375
- nodes[0].path.should == path
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
- before(:all) do
1382
- @app = lambda do |env|
1383
- if env["REQUEST_METHOD"] == "POST"
1384
- body = "<html><body><p>Congrats!</p></body></html>"
1385
- else
1386
- body = <<-HTML
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
- subject.find("//form")[0].submit
1406
- subject.body.should include "Congrats"
1285
+ driver.find("//form")[0].submit
1286
+ driver.body.should include "Congrats"
1407
1287
  end
1408
1288
  end
1409
1289
 
1410
- def key_app_body(event)
1411
- body = <<-HTML
1412
- <html>
1413
- <head><title>Form</title></head>
1414
- <body>
1415
- <div id="charcode_value"></div>
1416
- <div id="keycode_value"></div>
1417
- <div id="which_value"></div>
1418
- <input type="text" id="charcode" name="charcode" on#{event}="setcharcode" />
1419
- <script type="text/javascript">
1420
- var element = document.getElementById("charcode")
1421
- element.addEventListener("#{event}", setcharcode);
1422
- function setcharcode(event) {
1423
- var element = document.getElementById("charcode_value");
1424
- element.innerHTML = event.charCode;
1425
- element = document.getElementById("keycode_value");
1426
- element.innerHTML = event.keyCode;
1427
- element = document.getElementById("which_value");
1428
- element.innerHTML = event.which;
1429
- }
1430
- </script>
1431
- </body>
1432
- </html>
1433
- HTML
1434
- body
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
- subject.find("//input")[0].set(character)
1439
- subject.find("//div[@id='charcode_value']")[0].text
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
- subject.find("//input")[0].set(character)
1444
- subject.find("//div[@id='keycode_value']")[0].text
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
- subject.find("//input")[0].set(character)
1449
- subject.find("//div[@id='which_value']")[0].text
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
- before(:all) do
1454
- @app = lambda do |env|
1455
- body = key_app_body("keypress")
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
- before(:all) do
1519
- @app = lambda do |env|
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
- before(:all) do
1529
- @app = lambda do |env|
1530
- body = key_app_body("keyup")
1531
- [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]]
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
- it_behaves_like "a keyupdown app"
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
- context "null byte app" do
1539
- before(:all) do
1540
- @app = lambda do |env|
1541
- body = "Hello\0World"
1542
- [200,
1543
- { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s },
1544
- [body]]
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
- it "should include all the bytes in the source" do
1549
- subject.source.should == "Hello\0World"
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