capybara-webkit 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.travis.yml +19 -13
  4. data/Appraisals +8 -4
  5. data/Gemfile.lock +29 -14
  6. data/NEWS.md +4 -0
  7. data/README.md +1 -1
  8. data/Rakefile +1 -1
  9. data/capybara-webkit.gemspec +2 -1
  10. data/gemfiles/2.0.gemfile.lock +10 -6
  11. data/gemfiles/2.1.gemfile.lock +22 -9
  12. data/gemfiles/2.2.gemfile +7 -0
  13. data/gemfiles/2.2.gemfile.lock +77 -0
  14. data/gemfiles/2.3.gemfile +7 -0
  15. data/gemfiles/2.3.gemfile.lock +77 -0
  16. data/lib/capybara/webkit/browser.rb +28 -4
  17. data/lib/capybara/webkit/connection.rb +9 -24
  18. data/lib/capybara/webkit/driver.rb +40 -4
  19. data/lib/capybara/webkit/errors.rb +3 -0
  20. data/lib/capybara/webkit/version.rb +1 -1
  21. data/spec/browser_spec.rb +1 -1
  22. data/spec/connection_spec.rb +27 -5
  23. data/spec/driver_rendering_spec.rb +10 -0
  24. data/spec/driver_resize_window_spec.rb +22 -0
  25. data/spec/driver_spec.rb +117 -9
  26. data/spec/selenium_compatibility_spec.rb +3 -0
  27. data/spec/spec_helper.rb +22 -3
  28. data/spec/support/matchers/include_response.rb +24 -0
  29. data/src/CommandFactory.cpp +7 -1
  30. data/src/GoBack.cpp +12 -0
  31. data/src/GoBack.h +10 -0
  32. data/src/GoForward.cpp +12 -0
  33. data/src/GoForward.h +10 -0
  34. data/src/Render.cpp +10 -1
  35. data/src/Reset.cpp +0 -2
  36. data/src/SocketCommand.cpp +6 -0
  37. data/src/SocketCommand.h +1 -0
  38. data/src/StdinNotifier.cpp +16 -0
  39. data/src/StdinNotifier.h +20 -0
  40. data/src/WebPage.cpp +20 -5
  41. data/src/WebPage.h +4 -1
  42. data/src/WebPageManager.cpp +18 -7
  43. data/src/WebPageManager.h +2 -1
  44. data/src/WindowClose.cpp +10 -0
  45. data/src/WindowClose.h +12 -0
  46. data/src/WindowCommand.cpp +27 -0
  47. data/src/WindowCommand.h +21 -0
  48. data/src/WindowFocus.cpp +2 -25
  49. data/src/WindowFocus.h +4 -7
  50. data/src/WindowMaximize.cpp +14 -0
  51. data/src/WindowMaximize.h +12 -0
  52. data/src/WindowOpen.cpp +12 -0
  53. data/src/WindowOpen.h +10 -0
  54. data/src/WindowResize.cpp +16 -0
  55. data/src/WindowResize.h +12 -0
  56. data/src/WindowSize.cpp +17 -0
  57. data/src/WindowSize.h +12 -0
  58. data/src/capybara.js +19 -3
  59. data/src/find_command.h +7 -1
  60. data/src/main.cpp +4 -0
  61. data/src/webkit_server.pro +20 -4
  62. data/templates/Command.cpp +2 -0
  63. data/templates/Command.h +1 -3
  64. metadata +82 -54
  65. data/src/ResizeWindow.cpp +0 -17
  66. data/src/ResizeWindow.h +0 -10
@@ -102,6 +102,26 @@ module Capybara::Webkit
102
102
  command("WindowFocus", selector)
103
103
  end
104
104
 
105
+ def window_open
106
+ command("WindowOpen")
107
+ end
108
+
109
+ def window_close(selector)
110
+ command("WindowClose", selector)
111
+ end
112
+
113
+ def window_resize(handle, width, height)
114
+ command("WindowResize", handle, width.to_i, height.to_i)
115
+ end
116
+
117
+ def window_size(handle)
118
+ JSON.parse(command("WindowSize", handle))
119
+ end
120
+
121
+ def window_maximize(handle)
122
+ command("WindowMaximize", handle)
123
+ end
124
+
105
125
  def get_window_handles
106
126
  JSON.parse(command('GetWindowHandles'))
107
127
  end
@@ -195,14 +215,18 @@ module Capybara::Webkit
195
215
  command("SetProxy")
196
216
  end
197
217
 
198
- def resize_window(width, height)
199
- command("ResizeWindow", width.to_i, height.to_i)
200
- end
201
-
202
218
  def version
203
219
  command("Version")
204
220
  end
205
221
 
222
+ def go_back
223
+ command("GoBack")
224
+ end
225
+
226
+ def go_forward
227
+ command("GoForward")
228
+ end
229
+
206
230
  private
207
231
 
208
232
  def check
@@ -8,7 +8,7 @@ module Capybara::Webkit
8
8
  SERVER_PATH = File.expand_path("../../../../bin/webkit_server", __FILE__)
9
9
  WEBKIT_SERVER_START_TIMEOUT = 15
10
10
 
11
- attr_reader :port
11
+ attr_reader :port, :pid
12
12
 
13
13
  def initialize(options = {})
14
14
  @socket = nil
@@ -16,7 +16,8 @@ module Capybara::Webkit
16
16
  if options.has_key?(:stderr)
17
17
  @output_target = options[:stderr]
18
18
  elsif options.has_key?(:stdout)
19
- warn "[DEPRECATION] The `stdout` option is deprecated. Please use `stderr` instead."
19
+ warn '[DEPRECATION] The Capybara::Webkit::Connection `stdout` option ' \
20
+ 'is deprecated. Please use `stderr` instead.'
20
21
  @output_target = options[:stdout]
21
22
  else
22
23
  @output_target = $stderr
@@ -46,32 +47,12 @@ module Capybara::Webkit
46
47
  def start_server
47
48
  open_pipe
48
49
  discover_port
50
+ discover_pid
49
51
  forward_output_in_background_thread
50
52
  end
51
53
 
52
54
  def open_pipe
53
- _, @pipe_stdout, @pipe_stderr, wait_thr = Open3.popen3(SERVER_PATH)
54
- @pid = wait_thr[:pid]
55
- register_shutdown_hook
56
- end
57
-
58
- def register_shutdown_hook
59
- @owner_pid = Process.pid
60
- at_exit do
61
- if Process.pid == @owner_pid
62
- kill_process
63
- end
64
- end
65
- end
66
-
67
- def kill_process
68
- if RUBY_PLATFORM =~ /mingw32/
69
- Process.kill(9, @pid)
70
- else
71
- Process.kill("INT", @pid)
72
- end
73
- rescue Errno::ESRCH
74
- # This just means that the webkit_server process has already ended
55
+ @pipe_stdin, @pipe_stdout, @pipe_stderr, @wait_thr = Open3.popen3(SERVER_PATH)
75
56
  end
76
57
 
77
58
  def discover_port
@@ -80,6 +61,10 @@ module Capybara::Webkit
80
61
  end
81
62
  end
82
63
 
64
+ def discover_pid
65
+ @pid = @wait_thr[:pid]
66
+ end
67
+
83
68
  def forward_output_in_background_thread
84
69
  Thread.new do
85
70
  Thread.current.abort_on_exception = true
@@ -89,7 +89,15 @@ module Capybara::Webkit
89
89
  end
90
90
 
91
91
  def resize_window(width, height)
92
- browser.resize_window(width, height)
92
+ resize_window_to(current_window_handle, width, height)
93
+ end
94
+
95
+ def resize_window_to(handle, width, height)
96
+ browser.window_resize(handle, width, height)
97
+ end
98
+
99
+ def window_size(handle)
100
+ browser.window_size(handle)
93
101
  end
94
102
 
95
103
  def within_frame(selector)
@@ -102,8 +110,8 @@ module Capybara::Webkit
102
110
  end
103
111
 
104
112
  def within_window(selector)
105
- current_window = window_handle
106
- browser.window_focus(selector)
113
+ current_window = current_window_handle
114
+ switch_to_window(selector)
107
115
  begin
108
116
  yield
109
117
  ensure
@@ -111,14 +119,30 @@ module Capybara::Webkit
111
119
  end
112
120
  end
113
121
 
122
+ def switch_to_window(selector)
123
+ browser.window_focus(selector)
124
+ end
125
+
114
126
  def window_handles
115
127
  browser.get_window_handles
116
128
  end
117
129
 
118
- def window_handle
130
+ def current_window_handle
119
131
  browser.get_window_handle
120
132
  end
121
133
 
134
+ def open_new_window
135
+ browser.window_open
136
+ end
137
+
138
+ def close_window(selector)
139
+ browser.window_close(selector)
140
+ end
141
+
142
+ def maximize_window(selector)
143
+ browser.window_maximize(selector)
144
+ end
145
+
122
146
  def accept_js_confirms!
123
147
  browser.accept_js_confirms
124
148
  end
@@ -143,6 +167,14 @@ module Capybara::Webkit
143
167
  end
144
168
  end
145
169
 
170
+ def go_back
171
+ browser.go_back
172
+ end
173
+
174
+ def go_forward
175
+ browser.go_forward
176
+ end
177
+
146
178
  def wait?
147
179
  true
148
180
  end
@@ -174,6 +206,10 @@ module Capybara::Webkit
174
206
  [Capybara::Webkit::ClickFailed]
175
207
  end
176
208
 
209
+ def no_such_window_error
210
+ Capybara::Webkit::NoSuchWindowError
211
+ end
212
+
177
213
  def version
178
214
  [
179
215
  "Capybara: #{Capybara::VERSION}",
@@ -14,6 +14,9 @@ module Capybara::Webkit
14
14
  class TimeoutError < Timeout::Error
15
15
  end
16
16
 
17
+ class NoSuchWindowError < StandardError
18
+ end
19
+
17
20
  class JsonError
18
21
  def initialize(response)
19
22
  error = JSON.parse response
@@ -1,7 +1,7 @@
1
1
  module Capybara
2
2
  module Driver
3
3
  class Webkit
4
- VERSION = '1.1.1'.freeze
4
+ VERSION = '1.2.0'.freeze
5
5
  end
6
6
  end
7
7
  end
data/spec/browser_spec.rb CHANGED
@@ -148,7 +148,7 @@ describe Capybara::Webkit::Browser do
148
148
  end
149
149
  end
150
150
 
151
- describe "forking", :skip_on_windows => true do
151
+ describe "forking", skip_on_windows: true, skip_on_jruby: true do
152
152
  it "only shuts down the server from the main process" do
153
153
  browser.reset!
154
154
  pid = fork {}
@@ -2,6 +2,27 @@ require 'spec_helper'
2
2
  require 'capybara/webkit/connection'
3
3
 
4
4
  describe Capybara::Webkit::Connection do
5
+ it "kills the process when the parent process dies", skip_on_windows: true, skip_on_jruby: true do
6
+ read_io, write_io = IO.pipe
7
+
8
+ fork_pid = fork do
9
+ read_io.close
10
+ connection = Capybara::Webkit::Connection.new
11
+ write_io.write(connection.pid)
12
+ write_io.close
13
+ Process.wait(connection.pid)
14
+ end
15
+
16
+ write_io.close
17
+
18
+ webkit_pid = read_io.read.to_i
19
+ webkit_pid.should be > 1
20
+ read_io.close
21
+ Process.kill(9, fork_pid)
22
+ sleep 1
23
+ expect { Process.getpgid(webkit_pid) }.to raise_error Errno::ESRCH
24
+ end
25
+
5
26
  it "boots a server to talk to" do
6
27
  url = "http://#{@rack_server.host}:#{@rack_server.port}/"
7
28
  connection.puts "Visit"
@@ -19,17 +40,18 @@ describe Capybara::Webkit::Connection do
19
40
  end
20
41
 
21
42
  it 'forwards stderr to the given IO object' do
22
- io = StringIO.new
23
- redirected_connection = Capybara::Webkit::Connection.new(:stderr => io)
24
- script = 'console.log("hello world")'
43
+ read_io, write_io = IO.pipe
44
+ redirected_connection = Capybara::Webkit::Connection.new(:stderr => write_io)
25
45
  redirected_connection.puts "EnableLogging"
26
46
  redirected_connection.puts 0
47
+
48
+ script = 'console.log("hello world")'
27
49
  redirected_connection.puts "Execute"
28
50
  redirected_connection.puts 1
29
51
  redirected_connection.puts script.to_s.bytesize
30
52
  redirected_connection.print script
31
- sleep(0.5)
32
- io.string.should =~ /hello world $/
53
+
54
+ expect(read_io).to include_response "\nhello world"
33
55
  end
34
56
 
35
57
  it 'does not forward stderr to nil' do
@@ -90,4 +90,14 @@ describe Capybara::Webkit::Driver, "rendering an image" do
90
90
  driver.evaluate_script('window.innerHeight').should eq 600
91
91
  end
92
92
  end
93
+
94
+ context "with invalid filepath" do
95
+ before do
96
+ @file_name = File.dirname(@file_name)
97
+ end
98
+
99
+ it "raises an InvalidResponseError" do
100
+ expect { render({}) }.to raise_error(Capybara::Webkit::InvalidResponseError)
101
+ end
102
+ end
93
103
  end
@@ -45,4 +45,26 @@ describe Capybara::Webkit::Driver, "#resize_window(width, height)" do
45
45
  driver.visit("#{AppRunner.app_host}/")
46
46
  driver.html.should include(DEFAULT_DIMENTIONS)
47
47
  end
48
+
49
+ it "resizes windows by handle" do
50
+ driver.visit("#{AppRunner.app_host}/")
51
+ driver.open_new_window
52
+ driver.visit("#{AppRunner.app_host}/")
53
+
54
+ driver.resize_window_to(driver.window_handles.first, 800, 600)
55
+ driver.resize_window_to(driver.window_handles.last, 400, 300)
56
+
57
+ driver.window_size(driver.window_handles.first).should eq [800, 600]
58
+ driver.window_size(driver.window_handles.last).should eq [400, 300]
59
+ end
60
+
61
+ it "maximizes a window" do
62
+ driver.visit("#{AppRunner.app_host}/")
63
+ driver.resize_window(400, 300)
64
+ driver.maximize_window(driver.current_window_handle)
65
+ width, height = *driver.window_size(driver.current_window_handle)
66
+
67
+ width.should be > 400
68
+ height.should be > 300
69
+ end
48
70
  end
data/spec/driver_spec.rb CHANGED
@@ -341,6 +341,9 @@ describe Capybara::Webkit::Driver do
341
341
  <div id="hidden-text">
342
342
  Some of this text is <em style="display:none">hidden!</em>
343
343
  </div>
344
+ <div id="hidden-ancestor" style="display: none">
345
+ <div>Hello</div>
346
+ </div>
344
347
  <input type="text" disabled="disabled"/>
345
348
  <input id="checktest" type="checkbox" checked="checked"/>
346
349
  <script type="text/javascript">
@@ -353,6 +356,12 @@ describe Capybara::Webkit::Driver do
353
356
 
354
357
  before { visit("/") }
355
358
 
359
+ it "doesn't return text if the ancestor is hidden" do
360
+ visit("/")
361
+
362
+ driver.find_css("#hidden-ancestor div").first.text.should eq ''
363
+ end
364
+
356
365
  it "handles anchor tags" do
357
366
  visit("#test")
358
367
  driver.find_xpath("//*[contains(., 'hello')]").should_not be_empty
@@ -1081,7 +1090,7 @@ describe Capybara::Webkit::Driver do
1081
1090
  <input class="watch" type="password"/>
1082
1091
  <input class="watch" type="search"/>
1083
1092
  <input class="watch" type="tel"/>
1084
- <input class="watch" type="text"/>
1093
+ <input class="watch" type="text" value="original"/>
1085
1094
  <input class="watch" type="url"/>
1086
1095
  <textarea class="watch"></textarea>
1087
1096
  <input class="watch" type="checkbox"/>
@@ -1117,7 +1126,7 @@ describe Capybara::Webkit::Driver do
1117
1126
 
1118
1127
  before { visit("/") }
1119
1128
 
1120
- let(:newtext) { 'newvalue' }
1129
+ let(:newtext) { '12345' }
1121
1130
 
1122
1131
  let(:keyevents) do
1123
1132
  (%w{focus} +
@@ -1125,13 +1134,22 @@ describe Capybara::Webkit::Driver do
1125
1134
  ).flatten
1126
1135
  end
1127
1136
 
1137
+ let(:textevents) { keyevents + %w(change blur) }
1138
+
1128
1139
  %w(email number password search tel text url).each do | field_type |
1129
1140
  it "triggers text input events on inputs of type #{field_type}" do
1130
1141
  driver.find_xpath("//input[@type='#{field_type}']").first.set(newtext)
1131
- driver.find_xpath("//li").map(&:visible_text).should eq keyevents
1142
+ driver.find_xpath("//body").first.click
1143
+ driver.find_xpath("//li").map(&:visible_text).should eq textevents
1132
1144
  end
1133
1145
  end
1134
1146
 
1147
+ it "triggers events for cleared inputs" do
1148
+ driver.find_xpath("//input[@type='text']").first.set('')
1149
+ driver.find_xpath("//body").first.click
1150
+ driver.find_xpath("//li").map(&:visible_text).should include('change')
1151
+ end
1152
+
1135
1153
  it "triggers textarea input events" do
1136
1154
  driver.find_xpath("//textarea").first.set(newtext)
1137
1155
  driver.find_xpath("//li").map(&:visible_text).should eq keyevents
@@ -1925,6 +1943,42 @@ describe Capybara::Webkit::Driver do
1925
1943
  end
1926
1944
  end
1927
1945
 
1946
+ it "can switch to another window" do
1947
+ visit("/new_window")
1948
+ driver.switch_to_window(driver.window_handles.last)
1949
+ driver.find_xpath("//p").first.visible_text.should eq "finished"
1950
+ end
1951
+
1952
+ it "knows the current window handle" do
1953
+ visit("/new_window")
1954
+ driver.within_window(driver.window_handles.last) do
1955
+ driver.current_window_handle.should eq driver.window_handles.last
1956
+ end
1957
+ end
1958
+
1959
+ it "can close the current window" do
1960
+ visit("/new_window")
1961
+ original_handle = driver.current_window_handle
1962
+ driver.switch_to_window(driver.window_handles.last)
1963
+ driver.close_window(driver.current_window_handle)
1964
+
1965
+ driver.current_window_handle.should eq(original_handle)
1966
+ end
1967
+
1968
+ it "can close an unfocused window" do
1969
+ visit("/new_window")
1970
+ driver.close_window(driver.window_handles.last)
1971
+ driver.window_handles.size.should eq(1)
1972
+ end
1973
+
1974
+ it "can close the last window" do
1975
+ visit("/new_window")
1976
+ handles = driver.window_handles
1977
+ handles.each { |handle| driver.close_window(handle) }
1978
+ driver.html.should be_empty
1979
+ handles.should_not include(driver.current_window_handle)
1980
+ end
1981
+
1928
1982
  it "waits for the new window to load" do
1929
1983
  visit("/new_window?sleep=1")
1930
1984
  driver.within_window(driver.window_handles.last) do
@@ -1969,7 +2023,7 @@ describe Capybara::Webkit::Driver do
1969
2023
 
1970
2024
  it "raises an error if the window is not found" do
1971
2025
  expect { driver.within_window('myWindowDoesNotExist') }.
1972
- to raise_error(Capybara::Webkit::InvalidResponseError)
2026
+ to raise_error(Capybara::Webkit::NoSuchWindowError)
1973
2027
  end
1974
2028
 
1975
2029
  it "has a number of window handles equal to the number of open windows" do
@@ -1978,12 +2032,35 @@ describe Capybara::Webkit::Driver do
1978
2032
  driver.window_handles.size.should eq 2
1979
2033
  end
1980
2034
 
2035
+ it "removes windows when closed via JavaScript" do
2036
+ visit("/new_window")
2037
+ driver.execute_script('console.log(window.document.title); window.close()')
2038
+ sleep 2
2039
+ driver.window_handles.size.should eq 1
2040
+ end
2041
+
1981
2042
  it "closes new windows on reset" do
1982
2043
  visit("/new_window")
1983
2044
  last_handle = driver.window_handles.last
1984
2045
  driver.reset!
1985
2046
  driver.window_handles.should_not include(last_handle)
1986
2047
  end
2048
+
2049
+ it "leaves the old window focused when opening a new window" do
2050
+ visit("/new_window")
2051
+ current_window = driver.current_window_handle
2052
+ driver.open_new_window
2053
+
2054
+ driver.current_window_handle.should eq current_window
2055
+ driver.window_handles.size.should eq 3
2056
+ end
2057
+
2058
+ it "opens blank windows" do
2059
+ visit("/new_window")
2060
+ driver.open_new_window
2061
+ driver.switch_to_window(driver.window_handles.last)
2062
+ driver.html.should be_empty
2063
+ end
1987
2064
  end
1988
2065
 
1989
2066
  it "preserves cookies across windows" do
@@ -2246,28 +2323,31 @@ describe Capybara::Webkit::Driver do
2246
2323
  describe "logger app" do
2247
2324
  it "logs nothing before turning on the logger" do
2248
2325
  visit("/")
2326
+ @write.close
2249
2327
  log.should_not include logging_message
2250
2328
  end
2251
2329
 
2252
2330
  it "logs its commands after turning on the logger" do
2253
2331
  driver.enable_logging
2254
2332
  visit("/")
2333
+ @write.close
2255
2334
  log.should include logging_message
2256
2335
  end
2257
2336
 
2337
+ before do
2338
+ @read, @write = IO.pipe
2339
+ end
2340
+
2258
2341
  let(:logging_message) { 'Wrote response true' }
2259
2342
 
2260
2343
  let(:driver) do
2261
- connection = Capybara::Webkit::Connection.new(:stderr => output)
2344
+ connection = Capybara::Webkit::Connection.new(:stderr => @write)
2262
2345
  browser = Capybara::Webkit::Browser.new(connection)
2263
2346
  Capybara::Webkit::Driver.new(AppRunner.app, :browser => browser)
2264
2347
  end
2265
2348
 
2266
- let(:output) { StringIO.new }
2267
-
2268
2349
  def log
2269
- output.rewind
2270
- output.read
2350
+ @read.read
2271
2351
  end
2272
2352
  end
2273
2353
 
@@ -2383,6 +2463,34 @@ describe Capybara::Webkit::Driver do
2383
2463
  end
2384
2464
  end
2385
2465
 
2466
+ context "history" do
2467
+ let(:driver) do
2468
+ driver_for_app do
2469
+ get "/:param" do |param|
2470
+ <<-HTML
2471
+ <html>
2472
+ <body>
2473
+ <p>#{param}</p>
2474
+ <a href="/navigated">Navigate</a>
2475
+ </body>
2476
+ </html>
2477
+ HTML
2478
+ end
2479
+ end
2480
+ end
2481
+
2482
+ it "can navigate in history" do
2483
+ visit("/first")
2484
+ driver.find_xpath("//p").first.text.should eq('first')
2485
+ driver.find_xpath("//a").first.click
2486
+ driver.find_xpath("//p").first.text.should eq('navigated')
2487
+ driver.go_back
2488
+ driver.find_xpath("//p").first.text.should eq('first')
2489
+ driver.go_forward
2490
+ driver.find_xpath("//p").first.text.should eq('navigated')
2491
+ end
2492
+ end
2493
+
2386
2494
  def driver_url(driver, path)
2387
2495
  URI.parse(driver.current_url).merge(path).to_s
2388
2496
  end