capybara-webkit 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. data/.gitignore +2 -1
  2. data/GOALS +9 -0
  3. data/Gemfile.lock +15 -12
  4. data/LICENSE +1 -1
  5. data/NEWS.md +18 -0
  6. data/README.md +81 -2
  7. data/capybara-webkit.gemspec +1 -1
  8. data/lib/capybara/webkit.rb +11 -6
  9. data/lib/capybara/{driver/webkit → webkit}/browser.rb +90 -4
  10. data/lib/capybara/{driver/webkit → webkit}/connection.rb +48 -47
  11. data/lib/capybara/{driver/webkit → webkit}/cookie_jar.rb +1 -1
  12. data/lib/capybara/webkit/driver.rb +186 -0
  13. data/lib/capybara/webkit/errors.rb +10 -0
  14. data/lib/capybara/{driver/webkit → webkit}/node.rb +12 -4
  15. data/lib/capybara/{driver/webkit → webkit}/socket_debugger.rb +4 -1
  16. data/lib/capybara/{driver/webkit → webkit}/version.rb +1 -1
  17. data/lib/capybara_webkit_builder.rb +17 -3
  18. data/spec/browser_spec.rb +95 -7
  19. data/spec/connection_spec.rb +16 -5
  20. data/spec/cookie_jar_spec.rb +3 -3
  21. data/spec/driver_rendering_spec.rb +19 -26
  22. data/spec/driver_resize_window_spec.rb +3 -3
  23. data/spec/driver_spec.rb +1200 -822
  24. data/spec/integration/driver_spec.rb +4 -3
  25. data/spec/selenium_compatibility_spec.rb +49 -0
  26. data/spec/spec_helper.rb +14 -6
  27. data/spec/support/app_runner.rb +94 -0
  28. data/src/Authenticate.cpp +18 -0
  29. data/src/Authenticate.h +12 -0
  30. data/src/Body.h +3 -5
  31. data/src/ClearCookies.cpp +3 -5
  32. data/src/ClearCookies.h +3 -5
  33. data/src/ClearPromptText.cpp +11 -0
  34. data/src/ClearPromptText.h +9 -0
  35. data/src/Command.cpp +4 -15
  36. data/src/Command.h +3 -14
  37. data/src/CommandFactory.cpp +20 -6
  38. data/src/CommandFactory.h +3 -2
  39. data/src/CommandParser.cpp +1 -1
  40. data/src/Connection.cpp +22 -21
  41. data/src/Connection.h +5 -6
  42. data/src/ConsoleMessages.cpp +2 -1
  43. data/src/ConsoleMessages.h +3 -5
  44. data/src/CurrentUrl.cpp +9 -48
  45. data/src/CurrentUrl.h +8 -8
  46. data/src/EnableLogging.cpp +10 -0
  47. data/src/EnableLogging.h +12 -0
  48. data/src/Evaluate.cpp +2 -1
  49. data/src/Evaluate.h +3 -5
  50. data/src/Execute.cpp +2 -1
  51. data/src/Execute.h +3 -5
  52. data/src/Find.cpp +3 -2
  53. data/src/Find.h +3 -5
  54. data/src/FrameFocus.cpp +3 -2
  55. data/src/FrameFocus.h +3 -4
  56. data/src/GetCookies.cpp +3 -4
  57. data/src/GetCookies.h +3 -5
  58. data/src/GetTimeout.cpp +9 -0
  59. data/src/GetTimeout.h +11 -0
  60. data/src/GetWindowHandle.cpp +11 -0
  61. data/src/GetWindowHandle.h +10 -0
  62. data/src/GetWindowHandles.cpp +20 -0
  63. data/src/GetWindowHandles.h +10 -0
  64. data/src/Header.cpp +2 -1
  65. data/src/Header.h +3 -5
  66. data/src/Headers.cpp +8 -2
  67. data/src/Headers.h +3 -5
  68. data/src/IgnoreSslErrors.cpp +4 -3
  69. data/src/IgnoreSslErrors.h +3 -5
  70. data/src/JavascriptAlertMessages.cpp +10 -0
  71. data/src/JavascriptAlertMessages.h +9 -0
  72. data/src/JavascriptConfirmMessages.cpp +10 -0
  73. data/src/JavascriptConfirmMessages.h +9 -0
  74. data/src/JavascriptInvocation.cpp +1 -1
  75. data/src/JavascriptInvocation.h +1 -1
  76. data/src/JavascriptPromptMessages.cpp +10 -0
  77. data/src/JavascriptPromptMessages.h +9 -0
  78. data/src/NetworkAccessManager.cpp +38 -5
  79. data/src/NetworkAccessManager.h +20 -0
  80. data/src/Node.cpp +6 -1
  81. data/src/Node.h +4 -5
  82. data/src/NullCommand.cpp +5 -2
  83. data/src/NullCommand.h +4 -3
  84. data/src/PageLoadingCommand.cpp +12 -7
  85. data/src/PageLoadingCommand.h +6 -9
  86. data/src/Render.cpp +2 -1
  87. data/src/Render.h +3 -5
  88. data/src/RequestedUrl.cpp +2 -1
  89. data/src/RequestedUrl.h +3 -5
  90. data/src/Reset.cpp +3 -17
  91. data/src/Reset.h +3 -8
  92. data/src/ResizeWindow.cpp +2 -1
  93. data/src/ResizeWindow.h +3 -5
  94. data/src/Response.cpp +4 -0
  95. data/src/Response.h +1 -0
  96. data/src/Server.cpp +2 -3
  97. data/src/Server.h +0 -2
  98. data/src/SetConfirmAction.cpp +11 -0
  99. data/src/SetConfirmAction.h +9 -0
  100. data/src/SetCookie.cpp +3 -4
  101. data/src/SetCookie.h +3 -5
  102. data/src/SetPromptAction.cpp +11 -0
  103. data/src/SetPromptAction.h +9 -0
  104. data/src/SetPromptText.cpp +11 -0
  105. data/src/SetPromptText.h +9 -0
  106. data/src/SetProxy.cpp +2 -1
  107. data/src/SetProxy.h +3 -5
  108. data/src/SetSkipImageLoading.cpp +12 -0
  109. data/src/SetSkipImageLoading.h +9 -0
  110. data/src/SetTimeout.cpp +19 -0
  111. data/src/SetTimeout.h +9 -0
  112. data/src/SocketCommand.cpp +21 -0
  113. data/src/SocketCommand.h +29 -0
  114. data/src/Source.cpp +3 -2
  115. data/src/Source.h +3 -4
  116. data/src/Status.cpp +2 -1
  117. data/src/Status.h +3 -5
  118. data/src/TimeoutCommand.cpp +69 -0
  119. data/src/TimeoutCommand.h +41 -0
  120. data/src/UnsupportedContentHandler.cpp +11 -17
  121. data/src/UnsupportedContentHandler.h +5 -3
  122. data/src/Url.cpp +2 -1
  123. data/src/Url.h +3 -5
  124. data/src/Visit.cpp +3 -2
  125. data/src/Visit.h +3 -5
  126. data/src/WebPage.cpp +129 -44
  127. data/src/WebPage.h +37 -11
  128. data/src/WebPageManager.cpp +127 -0
  129. data/src/WebPageManager.h +59 -0
  130. data/src/WindowFocus.cpp +32 -0
  131. data/src/WindowFocus.h +15 -0
  132. data/src/body.cpp +2 -1
  133. data/src/capybara.js +38 -10
  134. data/src/find_command.h +17 -2
  135. data/src/main.cpp +0 -2
  136. data/src/webkit_server.pro +36 -0
  137. data/templates/Command.cpp +2 -4
  138. data/templates/Command.h +3 -3
  139. metadata +106 -27
  140. data/ChangeLog +0 -70
  141. data/lib/capybara/driver/webkit.rb +0 -136
data/.gitignore CHANGED
@@ -16,4 +16,5 @@ src/webkit_server.exe
16
16
  .DS_Store
17
17
  tmp
18
18
  .rvmrc
19
- src/debug
19
+ src/debug
20
+ webkit_server.pro.user
data/GOALS ADDED
@@ -0,0 +1,9 @@
1
+ capybara-webkit hits 1.0.0 when:
2
+
3
+ * All shared examples from capybara are implemented. See
4
+ capybara:lib/capybara/spec/**/*rb for the shared example groups.
5
+ * Test failures are a result of issues in the developer's code and not
6
+ capybara-webkit.
7
+ * Test failures lead to clear explanations for what failed and what can
8
+ be done to resolve them.
9
+ * It handles iframes, cookies, page loading, and other oddities.
@@ -1,13 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capybara-webkit (0.12.1)
4
+ capybara-webkit (0.13.0)
5
5
  capybara (>= 1.0.0, < 1.2)
6
6
  json
7
7
 
8
8
  GEM
9
9
  remote: http://rubygems.org/
10
10
  specs:
11
+ addressable (2.3.2)
11
12
  appraisal (0.4.0)
12
13
  bundler
13
14
  rake
@@ -18,18 +19,20 @@ GEM
18
19
  rack-test (>= 0.5.4)
19
20
  selenium-webdriver (~> 2.0)
20
21
  xpath (~> 0.1.4)
21
- childprocess (0.3.1)
22
- ffi (~> 1.0.6)
22
+ childprocess (0.3.6)
23
+ ffi (~> 1.0, >= 1.0.6)
23
24
  diff-lcs (1.1.2)
24
- ffi (1.0.11)
25
- json (1.7.1)
26
- mime-types (1.18)
25
+ ffi (1.1.5)
26
+ json (1.7.5)
27
+ libwebsocket (0.1.5)
28
+ addressable
29
+ mime-types (1.19)
27
30
  mini_magick (3.2.1)
28
31
  subexec (~> 0.0.4)
29
- multi_json (1.3.2)
30
- nokogiri (1.5.2)
32
+ multi_json (1.3.6)
33
+ nokogiri (1.5.5)
31
34
  rack (1.3.2)
32
- rack-test (0.6.1)
35
+ rack-test (0.6.2)
33
36
  rack (>= 1.0)
34
37
  rake (0.9.2)
35
38
  rspec (2.6.0)
@@ -40,10 +43,10 @@ GEM
40
43
  rspec-expectations (2.6.0)
41
44
  diff-lcs (~> 1.1.2)
42
45
  rspec-mocks (2.6.0)
43
- rubyzip (0.9.7)
44
- selenium-webdriver (2.20.0)
46
+ rubyzip (0.9.9)
47
+ selenium-webdriver (2.25.0)
45
48
  childprocess (>= 0.2.5)
46
- ffi (~> 1.0)
49
+ libwebsocket (~> 0.1.3)
47
50
  multi_json (~> 1.0)
48
51
  rubyzip
49
52
  sinatra (1.1.2)
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 thoughtbot, inc.
1
+ Copyright (c) 2010-2012 thoughtbot, inc.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/NEWS.md CHANGED
@@ -1,3 +1,21 @@
1
+ New for HEAD:
2
+
3
+ * Better detect page load success, and better handle load failures.
4
+ * HTTP Basic Auth support.
5
+ * within_window support.
6
+ * More useful and detailed debugging output.
7
+ * Catch up with recent capybara releases.
8
+ * Ignore errors from canceled requests.
9
+ * Follow how Selenium treats focus and blur form events.
10
+ * Control JavaScript prompts from Ruby.
11
+ * Each command has a configurable timeout.
12
+ * Performance improvements on Linux.
13
+ * Support empty `multiple` attributes.
14
+
15
+ New for 0.12.1:
16
+
17
+ * Fix integration with newer capybara for the debugging driver.
18
+
1
19
  New for 0.12.0:
2
20
  * Better windows support
3
21
  * Support for localStorage
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  capybara-webkit
2
2
  ===============
3
3
 
4
+ [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/thoughtbot/capybara-webkit)
5
+
4
6
  A [capybara](https://github.com/jnicklas/capybara) driver that uses [WebKit](http://webkit.org) via [QtWebKit](http://doc.qt.nokia.com/4.7/qtwebkit.html).
5
7
 
6
8
  Qt Dependency and Installation Issues
@@ -51,7 +53,7 @@ Set your Capybara Javascript driver to webkit:
51
53
 
52
54
  In cucumber, tag scenarios with @javascript to run them using a headless WebKit browser.
53
55
 
54
- In RSpec, use the :js => true flag.
56
+ In RSpec, use the :js => true flag. See the [capybara documention](http://rubydoc.info/gems/capybara#Using_Capybara_with_RSpec) for more information about using capybara with RSpec.
55
57
 
56
58
  Take note of the transactional fixtures section of the [capybara README](https://github.com/jnicklas/capybara/blob/master/README.md).
57
59
 
@@ -77,6 +79,20 @@ capybara-webkit supports a few methods that are not part of the standard capybar
77
79
  page.driver.error_messages
78
80
  => {:source=>"http://example.com", :line_number=>1, :message=>"SyntaxError: Parse error"}
79
81
 
82
+ **alert_messages, confirm_messages, prompt_messages**: returns arrays of Javascript dialog messages for each dialog type
83
+
84
+ # In Javascript:
85
+ alert("HI");
86
+ confirm("Ok?");
87
+ prompt("Number?", "42");
88
+ # In Ruby:
89
+ page.driver.alert_messages
90
+ => ["Hi"]
91
+ page.driver.confirm_messages
92
+ => ["Ok?"]
93
+ page.driver.prompt_messages
94
+ => ["Number?"]
95
+
80
96
  **resize_window**: change the viewport size to the given width and height
81
97
 
82
98
  page.driver.resize_window(500, 300)
@@ -92,6 +108,69 @@ capybara-webkit supports a few methods that are not part of the standard capybar
92
108
  page.driver.cookies["alpha"]
93
109
  => "abc"
94
110
 
111
+ **accept_js_confirms!**: accept any Javascript confirm that is triggered by the page's Javascript
112
+
113
+ # In Javascript:
114
+ if (confirm("Ok?"))
115
+ console.log("Hi");
116
+ else
117
+ console.log("Bye");
118
+ # In Ruby:
119
+ page.driver.accept_js_confirms!
120
+ visit "/"
121
+ page.driver.console_messages.first[:message]
122
+ => "Hi"
123
+
124
+ **dismiss_js_confirms!**: dismiss any Javascript confirm that is triggered by the page's Javascript
125
+
126
+ # In Javascript:
127
+ if (confirm("Ok?"))
128
+ console.log("Hi");
129
+ else
130
+ console.log("Bye");
131
+ # In Ruby:
132
+ page.driver.dismiss_js_confirms!
133
+ visit "/"
134
+ page.driver.console_messages.first[:message]
135
+ => "Bye"
136
+
137
+ **accept_js_prompts!**: accept any Javascript prompt that is triggered by the page's Javascript
138
+
139
+ # In Javascript:
140
+ var a = prompt("Number?", "0")
141
+ console.log(a);
142
+ # In Ruby:
143
+ page.driver.accept_js_prompts!
144
+ visit "/"
145
+ page.driver.console_messages.first[:message]
146
+ => "0"
147
+
148
+ **dismiss_js_prompts!**: dismiss any Javascript prompt that is triggered by the page's Javascript
149
+
150
+ # In Javascript:
151
+ var a = prompt("Number?", "0")
152
+ if (a != null)
153
+ console.log(a);
154
+ else
155
+ console.log("you said no"));
156
+ # In Ruby:
157
+ page.driver.dismiss_js_prompts!
158
+ visit "/"
159
+ page.driver.console_messages.first[:message]
160
+ => "you said no"
161
+
162
+ **js_prompt_input=(value)**: set the text to use if a Javascript prompt is encountered and accepted
163
+
164
+ # In Javascript:
165
+ var a = prompt("Number?", "0")
166
+ console.log(a);
167
+ # In Ruby:
168
+ page.driver.js_prompt_input = "42"
169
+ page.driver.accept_js_prompts!
170
+ visit "/"
171
+ page.driver.console_messages.first[:message]
172
+ => "42"
173
+
95
174
  Contributing
96
175
  ------------
97
176
 
@@ -111,4 +190,4 @@ The names and logos for thoughtbot are trademarks of thoughtbot, inc.
111
190
  License
112
191
  -------
113
192
 
114
- capybara-webkit is Copyright (c) 2011 thoughtbot, inc. It is free software, and may be redistributed under the terms specified in the LICENSE file.
193
+ capybara-webkit is Copyright (c) 2010-2012 thoughtbot, inc. It is free software, and may be redistributed under the terms specified in the LICENSE file.
@@ -1,5 +1,5 @@
1
1
  $:.push File.expand_path("../lib", __FILE__)
2
- require "capybara/driver/webkit/version"
2
+ require "capybara/webkit/version"
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "capybara-webkit"
@@ -1,13 +1,18 @@
1
1
  require "capybara"
2
- require "capybara/driver/webkit"
2
+
3
+ module Capybara
4
+ module Webkit
5
+ end
6
+ end
7
+
8
+ require "capybara/webkit/driver"
3
9
 
4
10
  Capybara.register_driver :webkit do |app|
5
- Capybara::Driver::Webkit.new(app)
11
+ Capybara::Webkit::Driver.new(app)
6
12
  end
7
13
 
8
14
  Capybara.register_driver :webkit_debug do |app|
9
- connection = Capybara::Driver::Webkit::Connection.new(
10
- :socket_class => Capybara::Driver::Webkit::SocketDebugger)
11
- browser = Capybara::Driver::Webkit::Browser.new(connection)
12
- Capybara::Driver::Webkit.new(app, :browser => browser)
15
+ driver = Capybara::Webkit::Driver.new(app)
16
+ driver.enable_logging
17
+ driver
13
18
  end
@@ -1,11 +1,19 @@
1
1
  require 'json'
2
2
 
3
- class Capybara::Driver::Webkit
3
+ module Capybara::Webkit
4
4
  class Browser
5
5
  def initialize(connection)
6
6
  @connection = connection
7
7
  end
8
8
 
9
+ def authenticate(username, password)
10
+ command("Authenticate", username, password)
11
+ end
12
+
13
+ def enable_logging
14
+ command "EnableLogging"
15
+ end
16
+
9
17
  def visit(url)
10
18
  command "Visit", url
11
19
  end
@@ -47,6 +55,18 @@ class Capybara::Driver::Webkit
47
55
  end
48
56
  end
49
57
 
58
+ def alert_messages
59
+ command("JavascriptAlertMessages").split("\n")
60
+ end
61
+
62
+ def confirm_messages
63
+ command("JavascriptConfirmMessages").split("\n")
64
+ end
65
+
66
+ def prompt_messages
67
+ command("JavascriptPromptMessages").split("\n")
68
+ end
69
+
50
70
  def response_headers
51
71
  Hash[command("Headers").split("\n").map { |header| header.split(": ") }]
52
72
  end
@@ -77,6 +97,50 @@ class Capybara::Driver::Webkit
77
97
  command("IgnoreSslErrors")
78
98
  end
79
99
 
100
+ def set_skip_image_loading(skip_image_loading)
101
+ command("SetSkipImageLoading", skip_image_loading)
102
+ end
103
+
104
+ def window_focus(selector)
105
+ command("WindowFocus", selector)
106
+ end
107
+
108
+ def get_window_handles
109
+ JSON.parse(command('GetWindowHandles'))
110
+ end
111
+
112
+ alias_method :window_handles, :get_window_handles
113
+
114
+ def get_window_handle
115
+ command('GetWindowHandle')
116
+ end
117
+
118
+ alias_method :window_handle, :get_window_handle
119
+
120
+ def accept_js_confirms
121
+ command("SetConfirmAction", "Yes")
122
+ end
123
+
124
+ def reject_js_confirms
125
+ command("SetConfirmAction", "No")
126
+ end
127
+
128
+ def accept_js_prompts
129
+ command("SetPromptAction", "Yes")
130
+ end
131
+
132
+ def reject_js_prompts
133
+ command("SetPromptAction", "No")
134
+ end
135
+
136
+ def set_prompt_text_to(string)
137
+ command("SetPromptText", string)
138
+ end
139
+
140
+ def clear_prompt_text
141
+ command("ClearPromptText")
142
+ end
143
+
80
144
  def command(name, *args)
81
145
  @connection.puts name
82
146
  @connection.puts args.size
@@ -101,6 +165,14 @@ class Capybara::Driver::Webkit
101
165
  command "Render", path, width, height
102
166
  end
103
167
 
168
+ def timeout=(timeout_in_seconds)
169
+ command "SetTimeout", timeout_in_seconds
170
+ end
171
+
172
+ def timeout
173
+ command("GetTimeout").to_i
174
+ end
175
+
104
176
  def set_cookie(cookie)
105
177
  command "SetCookie", cookie
106
178
  end
@@ -133,14 +205,28 @@ class Capybara::Driver::Webkit
133
205
  result.strip! if result
134
206
 
135
207
  if result.nil?
136
- raise WebkitNoResponseError, "No response received from the server."
137
- elsif result != 'ok'
138
- raise WebkitInvalidResponseError, read_response
208
+ raise NoResponseError, "No response received from the server."
209
+ elsif result != 'ok'
210
+ case response = read_response
211
+ when "timeout"
212
+ raise Capybara::TimeoutError, "Request timed out after #{timeout_seconds}"
213
+ else
214
+ raise InvalidResponseError, response
215
+ end
139
216
  end
140
217
 
141
218
  result
142
219
  end
143
220
 
221
+ def timeout_seconds
222
+ seconds = timeout
223
+ if seconds > 1
224
+ "#{seconds} seconds"
225
+ else
226
+ "1 second"
227
+ end
228
+ end
229
+
144
230
  def read_response
145
231
  response_length = @connection.gets.to_i
146
232
  if response_length > 0
@@ -2,17 +2,17 @@ require 'socket'
2
2
  require 'timeout'
3
3
  require 'thread'
4
4
 
5
- class Capybara::Driver::Webkit
5
+ module Capybara::Webkit
6
6
  class Connection
7
+ SERVER_PATH = File.expand_path("../../../../bin/webkit_server", __FILE__)
7
8
  WEBKIT_SERVER_START_TIMEOUT = 15
8
9
 
9
10
  attr_reader :port
10
11
 
11
12
  def initialize(options = {})
12
13
  @socket_class = options[:socket_class] || TCPSocket
13
- @stdout = options.has_key?(:stdout) ?
14
- options[:stdout] :
15
- $stdout
14
+ @stdout = options.has_key?(:stdout) ? options[:stdout] : $stdout
15
+ @command = options[:command] || SERVER_PATH
16
16
  start_server
17
17
  connect
18
18
  end
@@ -36,52 +36,50 @@ class Capybara::Driver::Webkit
36
36
  private
37
37
 
38
38
  def start_server
39
- pipe = fork_server
40
- @port = discover_port(pipe)
41
- @stdout_thread = Thread.new do
42
- Thread.current.abort_on_exception = true
43
- forward_stdout(pipe)
44
- end
39
+ open_pipe
40
+ discover_port
41
+ forward_stdout_in_background_thread
45
42
  end
46
43
 
47
- def fork_server
48
- server_path = File.expand_path("../../../../../bin/webkit_server", __FILE__)
49
- pipe, @pid = server_pipe_and_pid(server_path)
44
+ def open_pipe
45
+ @pipe = IO.popen(@command)
46
+ @pid = @pipe.pid
50
47
  register_shutdown_hook
51
- pipe
52
- end
53
-
54
- def kill_process(pid)
55
- if RUBY_PLATFORM =~ /mingw32/
56
- Process.kill(9, pid)
57
- else
58
- Process.kill("INT", pid)
59
- end
60
48
  end
61
49
 
62
50
  def register_shutdown_hook
63
51
  @owner_pid = Process.pid
64
52
  at_exit do
65
53
  if Process.pid == @owner_pid
66
- kill_process(@pid)
54
+ kill_process
67
55
  end
68
56
  end
69
57
  end
70
58
 
71
- def server_pipe_and_pid(server_path)
72
- cmdline = [server_path]
73
- pipe = IO.popen(cmdline.join(" "))
74
- [pipe, pipe.pid]
59
+ def kill_process
60
+ if RUBY_PLATFORM =~ /mingw32/
61
+ Process.kill(9, @pid)
62
+ else
63
+ Process.kill("INT", @pid)
64
+ end
75
65
  end
76
66
 
77
- def discover_port(read_pipe)
78
- return unless IO.select([read_pipe], nil, nil, WEBKIT_SERVER_START_TIMEOUT)
79
- ((read_pipe.first || '').match(/listening on port: (\d+)/) || [])[1].to_i
67
+ def discover_port
68
+ if IO.select([@pipe], nil, nil, WEBKIT_SERVER_START_TIMEOUT)
69
+ @port = ((@pipe.first || '').match(/listening on port: (\d+)/) || [])[1].to_i
70
+ end
80
71
  end
81
72
 
82
- def forward_stdout(pipe)
83
- while pipe_readable?(pipe)
84
- line = pipe.readline
73
+ def forward_stdout_in_background_thread
74
+ @stdout_thread = Thread.new do
75
+ Thread.current.abort_on_exception = true
76
+ forward_stdout
77
+ end
78
+ end
79
+
80
+ def forward_stdout
81
+ while pipe_readable?
82
+ line = @pipe.readline
85
83
  if @stdout
86
84
  @stdout.write(line)
87
85
  @stdout.flush
@@ -90,6 +88,20 @@ class Capybara::Driver::Webkit
90
88
  rescue EOFError
91
89
  end
92
90
 
91
+ if !defined?(RUBY_ENGINE) || (RUBY_ENGINE == "ruby" && RUBY_VERSION <= "1.8")
92
+ # please note the use of IO::select() here, as it is used specifically to
93
+ # preserve correct signal handling behavior in ruby 1.8.
94
+ # https://github.com/thibaudgg/rb-fsevent/commit/d1a868bf8dc72dbca102bedbadff76c7e6c2dc21
95
+ # https://github.com/thibaudgg/rb-fsevent/blob/1ca42b987596f350ee7b19d8f8210b7b6ae8766b/ext/fsevent/fsevent_watch.c#L171
96
+ def pipe_readable?
97
+ IO.select([@pipe])
98
+ end
99
+ else
100
+ def pipe_readable?
101
+ !@pipe.eof?
102
+ end
103
+ end
104
+
93
105
  def connect
94
106
  Timeout.timeout(5) do
95
107
  while @socket.nil?
@@ -100,21 +112,10 @@ class Capybara::Driver::Webkit
100
112
 
101
113
  def attempt_connect
102
114
  @socket = @socket_class.open("127.0.0.1", @port)
103
- rescue Errno::ECONNREFUSED
104
- end
105
-
106
- if !defined?(RUBY_ENGINE) || (RUBY_ENGINE == "ruby" && RUBY_VERSION <= "1.8")
107
- # please note the use of IO::select() here, as it is used specifically to
108
- # preserve correct signal handling behavior in ruby 1.8.
109
- # https://github.com/thibaudgg/rb-fsevent/commit/d1a868bf8dc72dbca102bedbadff76c7e6c2dc21
110
- # https://github.com/thibaudgg/rb-fsevent/blob/1ca42b987596f350ee7b19d8f8210b7b6ae8766b/ext/fsevent/fsevent_watch.c#L171
111
- def pipe_readable?(pipe)
112
- IO.select([pipe])
113
- end
114
- else
115
- def pipe_readable?(pipe)
116
- !pipe.eof?
115
+ if defined?(Socket::TCP_NODELAY)
116
+ @socket.setsockopt(:IPPROTO_TCP, :TCP_NODELAY, 1)
117
117
  end
118
+ rescue Errno::ECONNREFUSED
118
119
  end
119
120
  end
120
121
  end