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
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.
data/README.md CHANGED
@@ -51,7 +51,7 @@ Set your Capybara Javascript driver to webkit:
51
51
 
52
52
  In cucumber, tag scenarios with @javascript to run them using a headless WebKit browser.
53
53
 
54
- In RSpec, use the :js => true flag.
54
+ 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
55
 
56
56
  Take note of the transactional fixtures section of the [capybara README](https://github.com/jnicklas/capybara/blob/master/README.md).
57
57
 
@@ -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 = "otherinbox-capybara-webkit"
@@ -1,11 +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
- browser = Capybara::Driver::Webkit::Browser.new(:socket_class => Capybara::Driver::Webkit::SocketDebugger)
10
- Capybara::Driver::Webkit.new(app, :browser => browser)
15
+ driver = Capybara::Webkit::Driver.new(app)
16
+ driver.enable_logging
17
+ driver
11
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
@@ -81,6 +89,22 @@ class Capybara::Driver::Webkit
81
89
  command("SetSkipImageLoading", skip_image_loading)
82
90
  end
83
91
 
92
+ def window_focus(selector)
93
+ command("WindowFocus", selector)
94
+ end
95
+
96
+ def get_window_handles
97
+ JSON.parse(command('GetWindowHandles'))
98
+ end
99
+
100
+ alias_method :window_handles, :get_window_handles
101
+
102
+ def get_window_handle
103
+ command('GetWindowHandle')
104
+ end
105
+
106
+ alias_method :window_handle, :get_window_handle
107
+
84
108
  def command(name, *args)
85
109
  @connection.puts name
86
110
  @connection.puts args.size
@@ -137,9 +161,9 @@ class Capybara::Driver::Webkit
137
161
  result.strip! if result
138
162
 
139
163
  if result.nil?
140
- raise WebkitNoResponseError, "No response received from the server."
164
+ raise NoResponseError, "No response received from the server."
141
165
  elsif result != 'ok'
142
- raise WebkitInvalidResponseError, read_response
166
+ raise InvalidResponseError, read_response
143
167
  end
144
168
 
145
169
  result
@@ -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?
@@ -102,19 +114,5 @@ class Capybara::Driver::Webkit
102
114
  @socket = @socket_class.open("127.0.0.1", @port)
103
115
  rescue Errno::ECONNREFUSED
104
116
  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?
117
- end
118
- end
119
117
  end
120
118
  end
@@ -3,7 +3,7 @@ require 'webrick'
3
3
  # A simple cookie jar implementation.
4
4
  # Does not take special cookie attributes
5
5
  # into account like expire, max-age, httponly, secure
6
- class Capybara::Driver::Webkit::CookieJar
6
+ class Capybara::Webkit::CookieJar
7
7
  attr_reader :browser
8
8
 
9
9
  def initialize(browser)
@@ -0,0 +1,150 @@
1
+ require "capybara"
2
+ require "capybara/webkit/version"
3
+ require "capybara/webkit/node"
4
+ require "capybara/webkit/connection"
5
+ require "capybara/webkit/browser"
6
+ require "capybara/webkit/socket_debugger"
7
+ require "capybara/webkit/cookie_jar"
8
+ require "capybara/webkit/errors"
9
+
10
+ module Capybara::Webkit
11
+ class Driver
12
+ attr_reader :browser
13
+
14
+ def initialize(app, options={})
15
+ @app = app
16
+ @options = options
17
+ @rack_server = Capybara::Server.new(@app)
18
+ @rack_server.boot if Capybara.run_server
19
+ @browser = options[:browser] || Browser.new(Connection.new(options))
20
+ end
21
+
22
+ def enable_logging
23
+ browser.enable_logging
24
+ end
25
+
26
+ def current_url
27
+ browser.current_url
28
+ end
29
+
30
+ def requested_url
31
+ browser.requested_url
32
+ end
33
+
34
+ def visit(path)
35
+ browser.visit(url(path))
36
+ end
37
+
38
+ def find(query)
39
+ browser.find(query).map { |native| Node.new(self, native) }
40
+ end
41
+
42
+ def source
43
+ browser.source
44
+ end
45
+
46
+ def body
47
+ browser.body
48
+ end
49
+
50
+ def header(key, value)
51
+ browser.header(key, value)
52
+ end
53
+
54
+ def execute_script(script)
55
+ value = browser.execute_script script
56
+ value.empty? ? nil : value
57
+ end
58
+
59
+ def evaluate_script(script)
60
+ browser.evaluate_script script
61
+ end
62
+
63
+ def console_messages
64
+ browser.console_messages
65
+ end
66
+
67
+ def error_messages
68
+ browser.error_messages
69
+ end
70
+
71
+ def response_headers
72
+ browser.response_headers
73
+ end
74
+
75
+ def status_code
76
+ browser.status_code
77
+ end
78
+
79
+ def resize_window(width, height)
80
+ browser.resize_window(width, height)
81
+ end
82
+
83
+ def within_frame(frame_id_or_index)
84
+ browser.frame_focus(frame_id_or_index)
85
+ begin
86
+ yield
87
+ ensure
88
+ browser.frame_focus
89
+ end
90
+ end
91
+
92
+ def within_window(selector)
93
+ current_window = window_handle
94
+ browser.window_focus(selector)
95
+ begin
96
+ yield
97
+ ensure
98
+ browser.window_focus(current_window)
99
+ end
100
+ end
101
+
102
+ def window_handles
103
+ browser.get_window_handles
104
+ end
105
+
106
+ def window_handle
107
+ browser.get_window_handle
108
+ end
109
+
110
+ def wait?
111
+ true
112
+ end
113
+
114
+ def wait_until(*args)
115
+ end
116
+
117
+ def reset!
118
+ browser.reset!
119
+ end
120
+
121
+ def has_shortcircuit_timeout?
122
+ false
123
+ end
124
+
125
+ def render(path, options={})
126
+ options[:width] ||= 1000
127
+ options[:height] ||= 10
128
+
129
+ browser.render path, options[:width], options[:height]
130
+ end
131
+
132
+ def server_port
133
+ @rack_server.port
134
+ end
135
+
136
+ def cookies
137
+ @cookie_jar ||= CookieJar.new(browser)
138
+ end
139
+
140
+ def invalid_element_errors
141
+ []
142
+ end
143
+
144
+ private
145
+
146
+ def url(path)
147
+ @rack_server.url(path)
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,10 @@
1
+ module Capybara::Webkit
2
+ class InvalidResponseError < StandardError
3
+ end
4
+
5
+ class NoResponseError < StandardError
6
+ end
7
+
8
+ class NodeNotAttachedError < Capybara::ElementNotFound
9
+ end
10
+ end
@@ -1,4 +1,4 @@
1
- class Capybara::Driver::Webkit
1
+ module Capybara::Webkit
2
2
  class Node < Capybara::Driver::Node
3
3
  NBSP = "\xC2\xA0"
4
4
  NBSP.force_encoding("UTF-8") if NBSP.respond_to?(:force_encoding)
@@ -91,7 +91,7 @@ class Capybara::Driver::Webkit
91
91
  if allow_unattached_nodes? || attached?
92
92
  browser.command "Node", name, native, *args
93
93
  else
94
- raise Capybara::Driver::Webkit::NodeNotAttachedError
94
+ raise Capybara::Webkit::NodeNotAttachedError
95
95
  end
96
96
  end
97
97
 
@@ -1,6 +1,6 @@
1
1
  # Wraps the TCP socket and prints data sent and received. Used for debugging
2
2
  # the wire protocol. You can use this by passing a :socket_class to Browser.
3
- class Capybara::Driver::Webkit
3
+ module Capybara::Webkit
4
4
  class SocketDebugger
5
5
  def self.open(host, port)
6
6
  real_socket = TCPSocket.open(host, port)