capybara 3.2.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +22 -1
  3. data/README.md +1 -1
  4. data/lib/capybara.rb +2 -0
  5. data/lib/capybara/driver/base.rb +5 -1
  6. data/lib/capybara/driver/node.rb +4 -0
  7. data/lib/capybara/helpers.rb +25 -0
  8. data/lib/capybara/minitest.rb +7 -1
  9. data/lib/capybara/minitest/spec.rb +8 -1
  10. data/lib/capybara/node/base.rb +3 -3
  11. data/lib/capybara/node/element.rb +52 -0
  12. data/lib/capybara/node/matchers.rb +33 -0
  13. data/lib/capybara/queries/selector_query.rb +4 -4
  14. data/lib/capybara/queries/style_query.rb +41 -0
  15. data/lib/capybara/rack_test/browser.rb +7 -1
  16. data/lib/capybara/rack_test/node.rb +4 -0
  17. data/lib/capybara/rspec/compound.rb +67 -65
  18. data/lib/capybara/rspec/features.rb +2 -4
  19. data/lib/capybara/rspec/matchers.rb +30 -10
  20. data/lib/capybara/selector.rb +9 -0
  21. data/lib/capybara/selector/css.rb +74 -1
  22. data/lib/capybara/selector/filters/base.rb +2 -1
  23. data/lib/capybara/selector/filters/expression_filter.rb +2 -1
  24. data/lib/capybara/selector/selector.rb +1 -1
  25. data/lib/capybara/selenium/driver.rb +34 -43
  26. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +35 -0
  27. data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +31 -0
  28. data/lib/capybara/selenium/node.rb +17 -20
  29. data/lib/capybara/selenium/nodes/marionette_node.rb +31 -0
  30. data/lib/capybara/server.rb +8 -29
  31. data/lib/capybara/server/checker.rb +38 -0
  32. data/lib/capybara/spec/public/test.js +5 -0
  33. data/lib/capybara/spec/session/all_spec.rb +4 -0
  34. data/lib/capybara/spec/session/assert_style_spec.rb +26 -0
  35. data/lib/capybara/spec/session/click_button_spec.rb +10 -0
  36. data/lib/capybara/spec/session/click_link_spec.rb +11 -0
  37. data/lib/capybara/spec/session/fill_in_spec.rb +2 -0
  38. data/lib/capybara/spec/session/find_link_spec.rb +18 -0
  39. data/lib/capybara/spec/session/find_spec.rb +1 -0
  40. data/lib/capybara/spec/session/first_spec.rb +1 -0
  41. data/lib/capybara/spec/session/has_css_spec.rb +0 -6
  42. data/lib/capybara/spec/session/has_style_spec.rb +25 -0
  43. data/lib/capybara/spec/session/node_spec.rb +34 -0
  44. data/lib/capybara/spec/session/save_page_spec.rb +4 -1
  45. data/lib/capybara/spec/session/save_screenshot_spec.rb +3 -1
  46. data/lib/capybara/spec/session/text_spec.rb +1 -0
  47. data/lib/capybara/spec/session/title_spec.rb +1 -0
  48. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
  49. data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
  50. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -0
  51. data/lib/capybara/spec/session/window/window_spec.rb +20 -0
  52. data/lib/capybara/spec/session/window/windows_spec.rb +1 -0
  53. data/lib/capybara/spec/session/window/within_window_spec.rb +1 -0
  54. data/lib/capybara/spec/session/within_spec.rb +1 -0
  55. data/lib/capybara/spec/spec_helper.rb +3 -1
  56. data/lib/capybara/spec/test_app.rb +18 -0
  57. data/lib/capybara/spec/views/form.erb +8 -0
  58. data/lib/capybara/spec/views/tables.erb +1 -1
  59. data/lib/capybara/spec/views/with_html.erb +9 -2
  60. data/lib/capybara/spec/views/with_js.erb +4 -0
  61. data/lib/capybara/spec/views/with_namespace.erb +20 -0
  62. data/lib/capybara/version.rb +1 -1
  63. data/lib/capybara/window.rb +11 -0
  64. data/spec/css_splitter_spec.rb +38 -0
  65. data/spec/dsl_spec.rb +1 -1
  66. data/spec/minitest_spec.rb +7 -1
  67. data/spec/minitest_spec_spec.rb +8 -1
  68. data/spec/rack_test_spec.rb +10 -0
  69. data/spec/rspec/shared_spec_matchers.rb +2 -0
  70. data/spec/selenium_spec_chrome.rb +28 -0
  71. data/spec/selenium_spec_chrome_remote.rb +2 -2
  72. data/spec/selenium_spec_marionette.rb +21 -1
  73. data/spec/server_spec.rb +0 -1
  74. data/spec/shared_selenium_session.rb +16 -1
  75. metadata +18 -19
@@ -51,6 +51,17 @@ Capybara::SpecHelper.spec "node" do
51
51
  end
52
52
  end
53
53
 
54
+ describe "#style", requires: [:css] do
55
+ it "should return the computed style value" do
56
+ expect(@session.find(:css, '#first').style('display')).to eq('display' => 'block')
57
+ expect(@session.find(:css, '#second').style(:display)).to eq('display' => 'inline')
58
+ end
59
+
60
+ it "should return multiple style values" do
61
+ expect(@session.find(:css, '#first').style('display', :'line-height')).to eq('display' => 'block', 'line-height' => '25px')
62
+ end
63
+ end
64
+
54
65
  describe "#value" do
55
66
  it "should allow retrieval of the value" do
56
67
  expect(@session.find('//textarea[@id="normal"]').value).to eq('banana')
@@ -185,6 +196,7 @@ Capybara::SpecHelper.spec "node" do
185
196
  expect(@session.find('//option', text: 'Disabled Child Option')).to be_disabled
186
197
  end
187
198
  end
199
+
188
200
  it "should be boolean" do
189
201
  @session.visit('/form')
190
202
  expect(@session.find('//select[@id="form_disabled_select"]/option').disabled?).to be true
@@ -370,6 +382,12 @@ Capybara::SpecHelper.spec "node" do
370
382
  expect(locations[:x].to_f).to be_within(1).of(5)
371
383
  expect(locations[:y].to_f).to be_within(1).of(5)
372
384
  end
385
+
386
+ it "should be able to click a table row", requires: [:js] do
387
+ @session.visit('/tables')
388
+ tr = @session.find(:css, '#agent_table tr:first-child').click
389
+ expect(tr).to have_css('label', text: 'Clicked')
390
+ end
373
391
  end
374
392
 
375
393
  describe '#double_click', requires: [:js] do
@@ -497,9 +515,25 @@ Capybara::SpecHelper.spec "node" do
497
515
  end
498
516
  end
499
517
 
518
+ describe "#evaluate_async_script", requires: %i[js es_args] do
519
+ it "should evaluate the given script in the context of the element" do
520
+ @session.visit('/with_js')
521
+ el = @session.find(:css, '#with_change_event')
522
+ expect(el.evaluate_async_script("arguments[0](this.value)")).to eq('default value')
523
+ end
524
+
525
+ it "should support returning elements after asynchronous operation" do
526
+ @session.visit('/with_js')
527
+ change = @session.find(:css, '#change') # ensure page has loaded and element is available
528
+ el = change.evaluate_async_script("var cb = arguments[0]; setTimeout(function(el){ cb(el) }, 100, this)")
529
+ expect(el).to eq(change)
530
+ end
531
+ end
532
+
500
533
  describe '#reload', requires: [:js] do
501
534
  context "without automatic reload" do
502
535
  before { Capybara.automatic_reload = false }
536
+
503
537
  it "should reload the current context of the node" do
504
538
  @session.visit('/with_js')
505
539
  node = @session.find(:css, '#reload-me')
@@ -3,11 +3,13 @@
3
3
  Capybara::SpecHelper.spec '#save_page' do
4
4
  let(:alternative_path) { File.join(Dir.pwd, "save_and_open_page_tmp") }
5
5
  before do
6
+ @old_save_path = Capybara.save_path
7
+ Capybara.save_path = nil
6
8
  @session.visit("/foo")
7
9
  end
8
10
 
9
11
  after do
10
- Capybara.save_path = nil
12
+ Capybara.save_path = @old_save_path
11
13
  Dir.glob("capybara-*.html").each do |file|
12
14
  FileUtils.rm(file)
13
15
  end
@@ -67,6 +69,7 @@ Capybara::SpecHelper.spec '#save_page' do
67
69
 
68
70
  context "asset_host contains a string" do
69
71
  before { Capybara.asset_host = "http://example.com" }
72
+
70
73
  after { Capybara.asset_host = nil }
71
74
 
72
75
  it "prepends base tag with value from asset_host to the head" do
@@ -3,11 +3,13 @@
3
3
  Capybara::SpecHelper.spec '#save_screenshot', requires: [:screenshot] do
4
4
  let(:alternative_path) { File.join(Dir.pwd, "save_screenshot_tmp") }
5
5
  before do
6
+ @old_save_path = Capybara.save_path
7
+ Capybara.save_path = nil
6
8
  @session.visit '/foo'
7
9
  end
8
10
 
9
11
  after do
10
- Capybara.save_path = nil
12
+ Capybara.save_path = @old_save_path
11
13
  FileUtils.rm_rf alternative_path
12
14
  end
13
15
 
@@ -44,6 +44,7 @@ Capybara::SpecHelper.spec '#text' do
44
44
 
45
45
  context "with css as default selector" do
46
46
  before { Capybara.default_selector = :css }
47
+
47
48
  it "should print the text of the page" do
48
49
  @session.visit('/with_simple_html')
49
50
  expect(@session.text).to eq('Bar')
@@ -8,6 +8,7 @@ Capybara::SpecHelper.spec '#title' do
8
8
 
9
9
  context "with css as default selector" do
10
10
  before { Capybara.default_selector = :css }
11
+
11
12
  it "should get the title of the page" do
12
13
  @session.visit('/with_title')
13
14
  expect(@session.title).to eq('Test Title')
@@ -5,6 +5,7 @@ Capybara::SpecHelper.spec '#current_window', requires: [:windows] do
5
5
  @window = @session.current_window
6
6
  @session.visit('/with_windows')
7
7
  end
8
+
8
9
  after do
9
10
  (@session.windows - [@window]).each do |w|
10
11
  @session.switch_to_window w
@@ -5,6 +5,7 @@ Capybara::SpecHelper.spec '#open_new_window', requires: [:windows] do
5
5
  @window = @session.current_window
6
6
  @session.visit('/with_windows')
7
7
  end
8
+
8
9
  after do
9
10
  (@session.windows - [@window]).each do |w|
10
11
  @session.switch_to_window w
@@ -6,6 +6,7 @@ Capybara::SpecHelper.spec '#window_opened_by', requires: [:windows] do
6
6
  @session.visit('/with_windows')
7
7
  @session.assert_selector(:css, 'body.loaded')
8
8
  end
9
+
9
10
  after do
10
11
  (@session.windows - [@window]).each do |w|
11
12
  @session.switch_to_window w
@@ -5,6 +5,7 @@ Capybara::SpecHelper.spec Capybara::Window, requires: [:windows] do
5
5
  @window = @session.current_window
6
6
  @session.visit('/with_windows')
7
7
  end
8
+
8
9
  after do
9
10
  (@session.windows - [@window]).each do |w|
10
11
  @session.switch_to_window w
@@ -112,6 +113,7 @@ Capybara::SpecHelper.spec Capybara::Window, requires: [:windows] do
112
113
  before do
113
114
  @initial_size = @session.current_window.size
114
115
  end
116
+
115
117
  after do
116
118
  @session.current_window.resize_to(*@initial_size)
117
119
  sleep 0.5
@@ -143,6 +145,7 @@ Capybara::SpecHelper.spec Capybara::Window, requires: [:windows] do
143
145
  before do
144
146
  @initial_size = @session.current_window.size
145
147
  end
148
+
146
149
  after do
147
150
  @session.current_window.resize_to(*@initial_size)
148
151
  sleep 0.5
@@ -181,4 +184,21 @@ Capybara::SpecHelper.spec Capybara::Window, requires: [:windows] do
181
184
  expect(ow_height).to be > 300
182
185
  end
183
186
  end
187
+
188
+ describe '#fullscreen' do
189
+ before do
190
+ @initial_size = @session.current_window.size
191
+ end
192
+
193
+ after do
194
+ @session.current_window.resize_to(*@initial_size)
195
+ sleep 0.5
196
+ end
197
+
198
+ it "should be able to fullscreen the window" do
199
+ expect do
200
+ @session.current_window.fullscreen
201
+ end.not_to raise_error
202
+ end
203
+ end
184
204
  end
@@ -10,6 +10,7 @@ Capybara::SpecHelper.spec '#windows', requires: [:windows] do
10
10
  raise Capybara::CapybaraError if @session.windows.size != 3
11
11
  end
12
12
  end
13
+
13
14
  after do
14
15
  (@session.windows - [@window]).each(&:close)
15
16
  @session.switch_to_window(@window)
@@ -10,6 +10,7 @@ Capybara::SpecHelper.spec '#within_window', requires: [:windows] do
10
10
  raise Capybara::CapybaraError if @session.windows.size != 3
11
11
  end
12
12
  end
13
+
13
14
  after do
14
15
  (@session.windows - [@window]).each do |w|
15
16
  @session.switch_to_window w
@@ -59,6 +59,7 @@ Capybara::SpecHelper.spec '#within' do
59
59
 
60
60
  context "with the default selector set to CSS" do
61
61
  before { Capybara.default_selector = :css }
62
+
62
63
  it "should use CSS" do
63
64
  @session.within("#for_bar li", text: 'With Simple HTML') do
64
65
  @session.click_link('Go')
@@ -7,6 +7,8 @@ require "capybara/rspec" # Required here instead of in rspec_spec to avoid RSpec
7
7
  require "capybara/spec/test_app"
8
8
  require "nokogiri"
9
9
 
10
+ Capybara.save_path = File.join(Dir.pwd, 'save_path_tmp')
11
+
10
12
  module Capybara
11
13
  module SpecHelper
12
14
  class << self
@@ -15,7 +17,7 @@ module Capybara
15
17
  config.before { Capybara::SpecHelper.reset! }
16
18
  config.after { Capybara::SpecHelper.reset! }
17
19
  # Test in 3.5+ where metadata doesn't autotrigger shared context inclusion - will be only behavior in RSpec 4
18
- config.shared_context_metadata_behavior = :apply_to_host_groups if RSpec::Core::Version::STRING.to_f >= 3.5
20
+ config.shared_context_metadata_behavior = :apply_to_host_groups if config.respond_to?(:shared_context_metadata_behavior=)
19
21
  end
20
22
 
21
23
  def reset!
@@ -38,6 +38,14 @@ class TestApp < Sinatra::Base
38
38
  redirect '/landed'
39
39
  end
40
40
 
41
+ post '/redirect_307' do
42
+ redirect '/landed', 307
43
+ end
44
+
45
+ post '/redirect_308' do
46
+ redirect '/landed', 308
47
+ end
48
+
41
49
  get '/referer_base' do
42
50
  '<a href="/get_referer">direct link</a>' \
43
51
  '<a href="/redirect_to_get_referer">link via redirect</a>' \
@@ -69,6 +77,10 @@ class TestApp < Sinatra::Base
69
77
  "You landed"
70
78
  end
71
79
 
80
+ post '/landed' do
81
+ "You post landed: #{params.dig(:form, 'data')}"
82
+ end
83
+
72
84
  get '/with-quotes' do
73
85
  %q("No," he said, "you can't do that.")
74
86
  end
@@ -153,6 +165,12 @@ class TestApp < Sinatra::Base
153
165
  HTML
154
166
  end
155
167
 
168
+ get '/download.csv' do
169
+ content_type "text/csv"
170
+ 'This, is, comma, separated' \
171
+ 'Thomas, Walpole, was , here'
172
+ end
173
+
156
174
  get '/:view' do |view|
157
175
  erb view.to_sym, locals: { referrer: request.referrer }
158
176
  end
@@ -552,6 +552,14 @@ New line after and before textarea tag
552
552
  <p>
553
553
  <input type="submit" value="Go FAR"/>
554
554
  </p>
555
+
556
+ <input type="hidden" name="form[data]" value="TWTW"/>
557
+ <p>
558
+ <button formaction='/redirect_307'>Go 307</button>
559
+ </p>
560
+ <p>
561
+ <button formaction='/redirect_308'>Go 308</button>
562
+ </p>
555
563
  </form>
556
564
 
557
565
  <form action="/form" method="post">
@@ -3,7 +3,7 @@
3
3
  <table id="agent_table">
4
4
  <caption>Agent</caption>
5
5
 
6
- <tr>
6
+ <tr onclick="this.querySelector('td label').innerHTML = 'Clicked'">
7
7
  <td>
8
8
  <label for="form_agent_name">Name</label>
9
9
  </td>
@@ -1,4 +1,8 @@
1
1
 
2
+ <style>
3
+ p { display: block; }
4
+ </style>
5
+
2
6
  <div id="referrer"><%= referrer %></div>
3
7
  <h1>This is a test</h1>
4
8
 
@@ -13,7 +17,7 @@
13
17
  <span class="number">42</span>
14
18
  <span>Other span</span>
15
19
 
16
- <p class="para" id="first" data-random="abc\def">
20
+ <p class="para" id="first" data-random="abc\def" style="line-height: 25px;">
17
21
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
18
22
  tempor incididunt ut <a href="/with_simple_html" title="awesome title" class="simple">labore</a>
19
23
  et dolore magna aliqua. Ut enim ad minim veniam,
@@ -22,7 +26,7 @@
22
26
  <a href="/with_simple_html" aria-label="Go to simple"><img id="first_image" width="20" height="20" alt="awesome image" /></a>
23
27
  </p>
24
28
 
25
- <p class="para" id="second">
29
+ <p class="para" id="second" style="display: inline;">
26
30
  Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
27
31
  dolore eu fugiat <a href="/redirect" id="red">Redirect</a> pariatur. Excepteur sint occaecat cupidatat non proident,
28
32
  sunt in culpa qui officia
@@ -173,3 +177,6 @@ banana</textarea>
173
177
  <div id="ws">
174
178
  &#x20;&#x1680;&#x2000;&#x2001;&#x2002; &#x2003;&#x2004;&nbsp;&#x2005; &#x2006;&#x2007;&#x2008;&#x2009;&#x200A;&#x202F;&#x205F;&#x3000;
175
179
  </div>
180
+
181
+ <a href="/download.csv" download>Download Me</a>
182
+ <a href="/download.csv" download="other.csv">Download Other</a>
@@ -72,6 +72,10 @@
72
72
  <a href="#" id="change-title">Change title</a>
73
73
  </p>
74
74
 
75
+ <p>
76
+ <a href="#" id="change-size">Change size</a>
77
+ </p>
78
+
75
79
  <p id="click-test">Click me</p>
76
80
 
77
81
  <p>
@@ -0,0 +1,20 @@
1
+ <html xmlns="http://www.w3.org/1999/xhtml">
2
+ <head>
3
+ <title>Namespace</title>
4
+ </head>
5
+ <body id="body">
6
+ <div>
7
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1"
8
+ viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice"
9
+ style="width:100%; height:100%; position:absolute; top:0; left:0; z-index:-1;">
10
+ <linearGradient id="gradient">
11
+ <stop class="begin" offset="0%"/>
12
+ <stop class="end" offset="100%"/>
13
+ </linearGradient>
14
+ <rect x="0" y="0" width="100" height="100" style="fill:url(#gradient)" />
15
+ <rect x="150" y="150" width="25" height="25" style="fill:url(#gradient)" />
16
+ <circle cx="50" cy="50" r="30" style="fill:url(#gradient)" />
17
+ </svg>
18
+ <div>
19
+ </body>
20
+ </html>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Capybara
4
- VERSION = '3.2.1'
4
+ VERSION = '3.3.0'
5
5
  end
@@ -101,6 +101,17 @@ module Capybara
101
101
  wait_for_stable_size { @driver.maximize_window(handle) }
102
102
  end
103
103
 
104
+ ##
105
+ # Fullscreen window.
106
+ #
107
+ # If a particular driver doesn't have concept of fullscreen it may not support this method.
108
+ #
109
+ # @macro about_current
110
+ #
111
+ def fullscreen
112
+ @driver.fullscreen_window(handle)
113
+ end
114
+
104
115
  def eql?(other)
105
116
  other.is_a?(self.class) && @session == other.session && @handle == other.handle
106
117
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Capybara::Selector::CSS::Splitter do
6
+ let :splitter do
7
+ ::Capybara::Selector::CSS::Splitter.new
8
+ end
9
+
10
+ context "split not needed" do
11
+ it "normal CSS selector" do
12
+ css = 'div[id="abc"]'
13
+ expect(splitter.split(css)).to eq [css]
14
+ end
15
+
16
+ it "comma in strings" do
17
+ css = 'div[id="a,bc"]'
18
+ expect(splitter.split(css)).to eq [css]
19
+ end
20
+
21
+ it "comma in pseudo-selector" do
22
+ css = 'div.class1:not(.class1, .class2)'
23
+ expect(splitter.split(css)).to eq [css]
24
+ end
25
+ end
26
+
27
+ context "split needed" do
28
+ it "root level comma" do
29
+ css = 'div.class1, span, p.class2'
30
+ expect(splitter.split(css)).to eq ['div.class1', 'span', 'p.class2']
31
+ end
32
+
33
+ it "root level comma when quotes and pseudo selectors" do
34
+ css = 'div.class1[id="abc\\"def,ghi"]:not(.class3, .class4), span[id=\'a"c\\\'de\'], section, #abc\\,def'
35
+ expect(splitter.split(css)).to eq ['div.class1[id="abc\\"def,ghi"]:not(.class3, .class4)', 'span[id=\'a"c\\\'de\']', 'section', '#abc\\,def']
36
+ end
37
+ end
38
+ end
@@ -8,7 +8,7 @@ class TestClass
8
8
  end
9
9
 
10
10
  Capybara::SpecHelper.run_specs TestClass.new, "DSL", capybara_skip: %i[
11
- js modals screenshot frames windows send_keys server hover about_scheme psc
11
+ js modals screenshot frames windows send_keys server hover about_scheme psc download css
12
12
  ]
13
13
 
14
14
  RSpec.describe Capybara::DSL do
@@ -112,6 +112,12 @@ class MinitestTest < Minitest::Test
112
112
  assert_matches_xpath(find(:select, 'form_title'), './/select[@id="form_title"]')
113
113
  refute_matches_xpath(find(:select, 'form_title'), './/select[@id="form_other_title"]')
114
114
  end
115
+
116
+ def test_assert_style
117
+ skip "Rack test doesn't support style" if Capybara.current_driver == :rack_test
118
+ visit('/with_html')
119
+ assert_style(find(:css, '#second'), display: 'inline')
120
+ end
115
121
  end
116
122
 
117
123
  RSpec.describe 'capybara/minitest' do
@@ -126,6 +132,6 @@ RSpec.describe 'capybara/minitest' do
126
132
  reporter.start
127
133
  MinitestTest.run reporter, {}
128
134
  reporter.report
129
- expect(output.string).to include("17 runs, 44 assertions, 0 failures, 0 errors, 0 skips")
135
+ expect(output.string).to include("18 runs, 44 assertions, 0 failures, 0 errors, 1 skips")
130
136
  end
131
137
  end