otherinbox-capybara-webkit 0.12.0 → 0.12.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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