capybara 2.4.4 → 2.5.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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +32 -5
  3. data/README.md +69 -8
  4. data/lib/capybara.rb +50 -29
  5. data/lib/capybara/driver/base.rb +4 -0
  6. data/lib/capybara/driver/node.rb +4 -0
  7. data/lib/capybara/helpers.rb +17 -5
  8. data/lib/capybara/node/actions.rb +16 -11
  9. data/lib/capybara/node/base.rb +7 -7
  10. data/lib/capybara/node/document_matchers.rb +1 -1
  11. data/lib/capybara/node/element.rb +82 -7
  12. data/lib/capybara/node/finders.rb +62 -22
  13. data/lib/capybara/node/matchers.rb +3 -3
  14. data/lib/capybara/node/simple.rb +6 -1
  15. data/lib/capybara/queries/base_query.rb +1 -1
  16. data/lib/capybara/queries/current_path_query.rb +58 -0
  17. data/lib/capybara/queries/text_query.rb +2 -11
  18. data/lib/capybara/rack_test/browser.rb +7 -2
  19. data/lib/capybara/rack_test/driver.rb +4 -0
  20. data/lib/capybara/rack_test/form.rb +2 -1
  21. data/lib/capybara/rack_test/node.rb +1 -0
  22. data/lib/capybara/result.rb +2 -2
  23. data/lib/capybara/rspec.rb +1 -0
  24. data/lib/capybara/rspec/features.rb +1 -1
  25. data/lib/capybara/rspec/matchers.rb +42 -3
  26. data/lib/capybara/selector.rb +7 -2
  27. data/lib/capybara/selenium/driver.rb +26 -12
  28. data/lib/capybara/selenium/node.rb +42 -6
  29. data/lib/capybara/server.rb +1 -1
  30. data/lib/capybara/session.rb +78 -50
  31. data/lib/capybara/session/matchers.rb +69 -0
  32. data/lib/capybara/spec/public/test.js +8 -0
  33. data/lib/capybara/spec/session/all_spec.rb +5 -0
  34. data/lib/capybara/spec/session/assert_current_path.rb +59 -0
  35. data/lib/capybara/spec/session/assert_text.rb +1 -1
  36. data/lib/capybara/spec/session/attach_file_spec.rb +2 -2
  37. data/lib/capybara/spec/session/body_spec.rb +2 -0
  38. data/lib/capybara/spec/session/click_button_spec.rb +17 -8
  39. data/lib/capybara/spec/session/click_link_spec.rb +32 -1
  40. data/lib/capybara/spec/session/current_url_spec.rb +5 -0
  41. data/lib/capybara/spec/session/fill_in_spec.rb +1 -1
  42. data/lib/capybara/spec/session/find_field_spec.rb +17 -0
  43. data/lib/capybara/spec/session/find_spec.rb +14 -5
  44. data/lib/capybara/spec/session/first_spec.rb +24 -0
  45. data/lib/capybara/spec/session/has_current_path_spec.rb +68 -0
  46. data/lib/capybara/spec/session/has_link_spec.rb +3 -0
  47. data/lib/capybara/spec/session/has_text_spec.rb +7 -0
  48. data/lib/capybara/spec/session/node_spec.rb +45 -6
  49. data/lib/capybara/spec/session/reset_session_spec.rb +18 -1
  50. data/lib/capybara/spec/session/save_and_open_page_spec.rb +19 -0
  51. data/lib/capybara/spec/session/save_page_spec.rb +12 -3
  52. data/lib/capybara/spec/session/save_screenshot_spec.rb +23 -0
  53. data/lib/capybara/spec/session/select_spec.rb +12 -0
  54. data/lib/capybara/spec/session/title_spec.rb +2 -2
  55. data/lib/capybara/spec/session/window/become_closed_spec.rb +4 -4
  56. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +8 -0
  57. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +14 -8
  58. data/lib/capybara/spec/session/window/window_spec.rb +24 -4
  59. data/lib/capybara/spec/spec_helper.rb +3 -1
  60. data/lib/capybara/spec/test_app.rb +10 -1
  61. data/lib/capybara/spec/views/form.erb +7 -1
  62. data/lib/capybara/spec/views/path.erb +12 -0
  63. data/lib/capybara/spec/views/with_html.erb +2 -0
  64. data/lib/capybara/spec/views/with_js.erb +9 -1
  65. data/lib/capybara/spec/views/with_title.erb +4 -1
  66. data/lib/capybara/spec/views/with_windows.erb +2 -2
  67. data/lib/capybara/version.rb +1 -1
  68. data/spec/basic_node_spec.rb +1 -0
  69. data/spec/capybara_spec.rb +12 -3
  70. data/spec/dsl_spec.rb +18 -6
  71. data/spec/rack_test_spec.rb +6 -5
  72. data/spec/rspec/matchers_spec.rb +62 -16
  73. data/spec/rspec/views_spec.rb +7 -0
  74. data/spec/selenium_spec.rb +38 -3
  75. data/spec/selenium_spec_chrome.rb +3 -7
  76. metadata +13 -4
@@ -84,6 +84,28 @@ Capybara::SpecHelper.spec '#click_link' do
84
84
  end
85
85
  end
86
86
 
87
+ context "with a regex :href option given" do
88
+ it "should find a link matching an all-matching regex pattern" do
89
+ @session.click_link('labore', :href => /.+/)
90
+ expect(@session).to have_content('Bar')
91
+ end
92
+
93
+ it "should find a link matching an exact regex pattern" do
94
+ @session.click_link('labore', :href => /\/with_simple_html/)
95
+ expect(@session).to have_content('Bar')
96
+ end
97
+
98
+ it "should find a link matching a partial regex pattern" do
99
+ @session.click_link('labore', :href => /\/with_simple/)
100
+ expect(@session).to have_content('Bar')
101
+ end
102
+
103
+ it "should raise an error if no link's href matched the pattern" do
104
+ expect { @session.click_link('labore', :href => /invalid_pattern/) }.to raise_error(Capybara::ElementNotFound)
105
+ expect { @session.click_link('labore', :href => /.+d+/) }.to raise_error(Capybara::ElementNotFound)
106
+ end
107
+ end
108
+
87
109
  it "should follow relative links" do
88
110
  @session.visit('/')
89
111
  @session.click_link('Relative')
@@ -100,8 +122,9 @@ Capybara::SpecHelper.spec '#click_link' do
100
122
  expect(@session).to have_content('You landed')
101
123
  end
102
124
 
103
- it "should follow redirects" do
125
+ it "should follow redirects back to itself" do
104
126
  @session.click_link('BackToMyself')
127
+ expect(@session).to have_css('#referrer', text: /\/with_html$/)
105
128
  expect(@session).to have_content('This is a test')
106
129
  end
107
130
 
@@ -116,6 +139,8 @@ Capybara::SpecHelper.spec '#click_link' do
116
139
  expect(@session.find_field("test_field").value).to eq('blah')
117
140
  @session.click_link('Blank Anchor')
118
141
  expect(@session.find_field("test_field").value).to eq('blah')
142
+ @session.click_link('Blank JS Anchor')
143
+ expect(@session.find_field("test_field").value).to eq('blah')
119
144
  end
120
145
 
121
146
  it "should do nothing on URL+anchor links for the same page" do
@@ -129,6 +154,12 @@ Capybara::SpecHelper.spec '#click_link' do
129
154
  expect(@session).to have_content('Bar')
130
155
  end
131
156
 
157
+ it "should follow link on anchor if the path has regex special characters" do
158
+ @session.visit('/with.*html')
159
+ @session.click_link('Anchor on different page')
160
+ expect(@session).to have_content('Bar')
161
+ end
162
+
132
163
  it "raise an error with links with no href" do
133
164
  expect do
134
165
  @session.click_link('No Href')
@@ -1,3 +1,5 @@
1
+ require "capybara/spec/test_app"
2
+
1
3
  Capybara::SpecHelper.spec '#current_url, #current_path, #current_host' do
2
4
  before :all do
3
5
  @servers = 2.times.map { Capybara::Server.new(TestApp.clone).boot }
@@ -11,6 +13,9 @@ Capybara::SpecHelper.spec '#current_url, #current_path, #current_host' do
11
13
  end
12
14
 
13
15
  def should_be_on server_index, path="/host", scheme="http"
16
+ #This delay is to give fully async drivers (selenium w/chromedriver) time for the browser
17
+ #to get to its destination - should be removed when we have a waiting current_url matcher
18
+ sleep 0.1 # remove and adjust tests when a waiting current_url/path matcher is implemented
14
19
  # Check that we are on /host on the given server
15
20
  s = @servers[server_index]
16
21
  expect(@session.current_url.chomp('?')).to eq("#{scheme}://#{s.host}:#{s.port}#{path}")
@@ -100,7 +100,7 @@ Capybara::SpecHelper.spec "#fill_in" do
100
100
  end
101
101
 
102
102
  it "should throw an exception if a hash containing 'with' is not provided" do
103
- expect {@session.fill_in 'Name', 'ignu'}.to raise_error
103
+ expect {@session.fill_in 'Name', 'ignu'}.to raise_error(RuntimeError, /with/)
104
104
  end
105
105
 
106
106
  it "should wait for asynchronous load", :requires => [:js] do
@@ -61,4 +61,21 @@ Capybara::SpecHelper.spec '#find_field' do
61
61
  end.to raise_error(Capybara::ElementNotFound)
62
62
  end
63
63
  end
64
+
65
+
66
+ context 'with :readonly option' do
67
+ it "should find readonly fields when true" do
68
+ expect(@session.find_field('form[readonly_test]', readonly: true)[:id]).to eq 'readonly'
69
+ end
70
+
71
+ it "should not find readonly fields when false" do
72
+ expect(@session.find_field('form[readonly_test]', readonly: false)[:id]).to eq 'not_readonly'
73
+ end
74
+
75
+ it "should ignore readonly by default" do
76
+ expect do
77
+ @session.find_field('form[readonly_test]')
78
+ end.to raise_error(Capybara::Ambiguous, /found 2 elements/)
79
+ end
80
+ end
64
81
  end
@@ -58,11 +58,20 @@ Capybara::SpecHelper.spec '#find' do
58
58
  end
59
59
 
60
60
  context "with frozen time", :requires => [:js] do
61
- it "raises an error suggesting that Capybara is stuck in time" do
62
- @session.visit('/with_js')
63
- now = Time.now
64
- allow(Time).to receive(:now).and_return(now)
65
- expect { @session.find('//isnotthere') }.to raise_error(Capybara::FrozenInTime)
61
+ if defined?(Process::CLOCK_MONOTONIC)
62
+ it "will time out even if time is frozen" do
63
+ @session.visit('/with_js')
64
+ now = Time.now
65
+ allow(Time).to receive(:now).and_return(now)
66
+ expect { @session.find('//isnotthere') }.to raise_error(Capybara::ElementNotFound)
67
+ end
68
+ else
69
+ it "raises an error suggesting that Capybara is stuck in time" do
70
+ @session.visit('/with_js')
71
+ now = Time.now
72
+ allow(Time).to receive(:now).and_return(now)
73
+ expect { @session.find('//isnotthere') }.to raise_error(Capybara::FrozenInTime)
74
+ end
66
75
  end
67
76
  end
68
77
 
@@ -85,4 +85,28 @@ Capybara::SpecHelper.spec '#first' do
85
85
  end
86
86
  end
87
87
  end
88
+
89
+ context "with Capybara.wait_on_first_by_default", requires: [:js] do
90
+ before do
91
+ @session.visit('/with_js')
92
+ end
93
+
94
+ it "should not wait if false" do
95
+ Capybara.wait_on_first_by_default = false
96
+ @session.click_link('clickable')
97
+ expect(@session.first(:css, 'a#has-been-clicked')).to be_nil
98
+ end
99
+
100
+ it "should wait for at least one match if true" do
101
+ Capybara.wait_on_first_by_default = true
102
+ @session.click_link('clickable')
103
+ expect(@session.first(:css, 'a#has-been-clicked')).not_to be_nil
104
+ end
105
+
106
+ it "should return nil after waiting if no match" do
107
+ Capybara.wait_on_first_by_default = true
108
+ @session.click_link('clickable')
109
+ expect(@session.first(:css, 'a#not-a-real-link')).to be_nil
110
+ end
111
+ end
88
112
  end
@@ -0,0 +1,68 @@
1
+ Capybara::SpecHelper.spec '#has_current_path?' do
2
+ before do
3
+ @session.visit('/with_js')
4
+ end
5
+
6
+ it "should be true if the page has the given current path" do
7
+ expect(@session).to have_current_path('/with_js')
8
+ end
9
+
10
+ it "should allow regexp matches" do
11
+ expect(@session).to have_current_path(/w[a-z]{3}_js/)
12
+ expect(@session).not_to have_current_path(/monkey/)
13
+ end
14
+
15
+ it "should wait for current_path", :requires => [:js] do
16
+ @session.click_link("Change page")
17
+ expect(@session).to have_current_path("/with_html")
18
+ end
19
+
20
+ it "should be false if the page has not the given current_path" do
21
+ expect(@session).not_to have_current_path('/with_html')
22
+ end
23
+
24
+ it "should check query options" do
25
+ @session.visit('/with_js?test=test')
26
+ expect(@session).to have_current_path('/with_js?test=test')
27
+ end
28
+
29
+ it "should compare the full url" do
30
+ expect(@session).to have_current_path(%r{\Ahttp://[^/]*/with_js\Z}, url: true)
31
+ end
32
+
33
+ it "should ignore the query" do
34
+ @session.visit('/with_js?test=test')
35
+ expect(@session).to have_current_path('/with_js?test=test')
36
+ expect(@session).to have_current_path('/with_js', only_path: true)
37
+ end
38
+
39
+ it "should not allow url and only_path at the same time" do
40
+ expect {
41
+ expect(@session).to have_current_path('/with_js', url: true, only_path: true)
42
+ }. to raise_error ArgumentError
43
+ end
44
+ end
45
+
46
+ Capybara::SpecHelper.spec '#has_no_current_path?' do
47
+ before do
48
+ @session.visit('/with_js')
49
+ end
50
+
51
+ it "should be false if the page has the given current_path" do
52
+ expect(@session).not_to have_no_current_path('/with_js')
53
+ end
54
+
55
+ it "should allow regexp matches" do
56
+ expect(@session).not_to have_no_current_path(/w[a-z]{3}_js/)
57
+ expect(@session).to have_no_current_path(/monkey/)
58
+ end
59
+
60
+ it "should wait for current_path to disappear", :requires => [:js] do
61
+ @session.click_link("Change page")
62
+ expect(@session).to have_no_current_path('/with_js')
63
+ end
64
+
65
+ it "should be true if the page has not the given current_path" do
66
+ expect(@session).to have_no_current_path('/with_html')
67
+ end
68
+ end
@@ -8,11 +8,13 @@ Capybara::SpecHelper.spec '#has_link?' do
8
8
  expect(@session).to have_link('awesome title')
9
9
  expect(@session).to have_link('A link', :href => '/with_simple_html')
10
10
  expect(@session).to have_link(:'A link', :href => :'/with_simple_html')
11
+ expect(@session).to have_link('A link', :href => /\/with_simple_html/)
11
12
  end
12
13
 
13
14
  it "should be false if the given link is not on the page" do
14
15
  expect(@session).not_to have_link('monkey')
15
16
  expect(@session).not_to have_link('A link', :href => '/non-existant-href')
17
+ expect(@session).not_to have_link('A link', :href => /non-existant/)
16
18
  end
17
19
  end
18
20
 
@@ -30,5 +32,6 @@ Capybara::SpecHelper.spec '#has_no_link?' do
30
32
  it "should be true if the given link is not on the page" do
31
33
  expect(@session).to have_no_link('monkey')
32
34
  expect(@session).to have_no_link('A link', :href => '/non-existant-href')
35
+ expect(@session).to have_no_link('A link', :href => /\/non-existant-href/)
33
36
  end
34
37
  end
@@ -200,6 +200,13 @@ Capybara::SpecHelper.spec '#has_text?' do
200
200
  end
201
201
  end
202
202
  end
203
+
204
+ it "should raise an error if an invalid option is passed" do
205
+ @session.visit('/with_html')
206
+ expect do
207
+ expect(@session).to have_text('Lorem', exact: true)
208
+ end.to raise_error(ArgumentError)
209
+ end
203
210
  end
204
211
 
205
212
  Capybara::SpecHelper.spec '#has_no_text?' do
@@ -67,7 +67,7 @@ Capybara::SpecHelper.spec "node" do
67
67
  @session.find('//textarea[1]').set("some <em>html</em> here")
68
68
  expect(@session.find('//textarea[1]').value).to eq("some <em>html</em> here")
69
69
  end
70
-
70
+
71
71
  it "defaults to 'on' for checkbox" do
72
72
  @session.visit('/form')
73
73
  expect(@session.find('//input[@id="valueless_checkbox"]').value).to eq('on')
@@ -76,7 +76,7 @@ Capybara::SpecHelper.spec "node" do
76
76
  it "defaults to 'on' for radio buttons" do
77
77
  @session.visit('/form')
78
78
  expect(@session.find('//input[@id="valueless_radio"]').value).to eq('on')
79
- end
79
+ end
80
80
  end
81
81
 
82
82
  describe "#set" do
@@ -97,7 +97,7 @@ Capybara::SpecHelper.spec "node" do
97
97
  @session.first('//input[@readonly]').set('changed')
98
98
  expect(@session.first('//input[@readonly]').value).to eq('should not change')
99
99
  end
100
-
100
+
101
101
  it "should raise if the text field is readonly" do
102
102
  expect(@session.first('//input[@readonly]').set('changed')).to raise_error(Capybara::ReadOnlyElementError)
103
103
  end if Capybara::VERSION.to_f > 3.0
@@ -202,6 +202,19 @@ Capybara::SpecHelper.spec "node" do
202
202
  end
203
203
  end
204
204
 
205
+ describe "#path" do
206
+ # Testing for specific XPaths here doesn't make sense since there
207
+ # are many that can refer to the same element
208
+ before :each do
209
+ @session.visit('/path')
210
+ end
211
+
212
+ it "returns xpath which points to itself" do
213
+ element = @session.find(:link, 'Second Link')
214
+ expect(@session.find(:xpath, element.path)).to eq(element)
215
+ end
216
+ end
217
+
205
218
  describe "#trigger", :requires => [:js, :trigger] do
206
219
  it "should allow triggering of custom JS events" do
207
220
  @session.visit('/with_js')
@@ -228,14 +241,14 @@ Capybara::SpecHelper.spec "node" do
228
241
  expect(@session.find(:css, '.hidden_until_hover', :visible => false)).to be_visible
229
242
  end
230
243
  end
231
-
244
+
232
245
  describe '#click' do
233
246
  it "should not follow a link if no href" do
234
247
  @session.find(:css, '#link_placeholder').click
235
248
  expect(@session.current_url).to match(%r{/with_html$})
236
249
  end
237
250
  end
238
-
251
+
239
252
  describe '#double_click', :requires => [:js] do
240
253
  it "should double click an element" do
241
254
  @session.visit('/with_js')
@@ -250,7 +263,33 @@ Capybara::SpecHelper.spec "node" do
250
263
  @session.find(:css, '#click-test').right_click
251
264
  expect(@session.find(:css, '#has-been-right-clicked')).to be
252
265
  end
253
- end
266
+ end
267
+
268
+ describe '#send_keys', requires: [:send_keys] do
269
+ it "should send a string of keys to an element" do
270
+ @session.visit('/form')
271
+ @session.find(:css, '#address1_city').send_keys('Oceanside')
272
+ expect(@session.find(:css, '#address1_city').value).to eq 'Oceanside'
273
+ end
274
+
275
+ it "should send special characters" do
276
+ @session.visit('/form')
277
+ @session.find(:css, '#address1_city').send_keys('Ocean', :space, 'sie', :left, 'd')
278
+ expect(@session.find(:css, '#address1_city').value).to eq 'Ocean side'
279
+ end
280
+
281
+ it "should allow for multiple simultaneous keys" do
282
+ @session.visit('/form')
283
+ @session.find(:css, '#address1_city').send_keys([:shift, 'o'], 'ceanside')
284
+ expect(@session.find(:css, '#address1_city').value).to eq 'Oceanside'
285
+ end
286
+
287
+ it "should generate key events", requires: [:send_keys, :js] do
288
+ @session.visit('/with_js')
289
+ @session.find(:css, '#with-key-events').send_keys([:shift,'t'], [:shift,'w'])
290
+ expect(@session.find(:css, '#key-events-output')).to have_text('keydown:16 keydown:84 keydown:16 keydown:87')
291
+ end
292
+ end
254
293
 
255
294
  describe '#reload', :requires => [:js] do
256
295
  context "without automatic reload" do
@@ -37,7 +37,7 @@ Capybara::SpecHelper.spec '#reset_session!' do
37
37
  expect(@session).to have_no_selector :xpath, "/html/body/*", wait: false
38
38
  end
39
39
 
40
- it "raises any errors caught inside the server", :requires => [:server] do
40
+ it "raises any standard errors caught inside the server", :requires => [:server] do
41
41
  quietly { @session.visit("/error") }
42
42
  expect do
43
43
  @session.reset_session!
@@ -46,6 +46,23 @@ Capybara::SpecHelper.spec '#reset_session!' do
46
46
  expect(@session.current_path).to eq("/")
47
47
  end
48
48
 
49
+ it "raises configured errors caught inside the server", :requires => [:server] do
50
+ prev_errors = Capybara.server_errors
51
+
52
+ Capybara.server_errors = [LoadError]
53
+ quietly { @session.visit("/error") }
54
+ expect do
55
+ @session.reset_session!
56
+ end.not_to raise_error
57
+
58
+ quietly { @session.visit("/load_error") }
59
+ expect do
60
+ @session.reset_session!
61
+ end.to raise_error(LoadError)
62
+
63
+ Capybara.server_errors = prev_errors
64
+ end
65
+
49
66
  it "ignores server errors when `Capybara.raise_server_errors = false`", :requires => [:server] do
50
67
  Capybara.raise_server_errors = false
51
68
  quietly { @session.visit("/error") }
@@ -0,0 +1,19 @@
1
+ require 'launchy'
2
+
3
+ Capybara::SpecHelper.spec '#save_and_open_page' do
4
+ before do
5
+ @session.visit '/foo'
6
+ end
7
+
8
+ after do
9
+ Dir.glob("capybara-*.html").each do |file|
10
+ FileUtils.rm(file)
11
+ end
12
+ end
13
+
14
+ it "sends open method to launchy" do
15
+ allow(Launchy).to receive(:open)
16
+ @session.save_and_open_page
17
+ expect(Launchy).to have_received(:open).with(/capybara-\d+\.html/)
18
+ end
19
+ end
@@ -20,9 +20,8 @@ Capybara::SpecHelper.spec '#save_page' do
20
20
 
21
21
  it "generates a sensible filename" do
22
22
  @session.save_page
23
- path = Dir.glob("capybara-*.html").first
24
- filename = path.split("/").last
25
- expect(filename).to match /^capybara-\d+\.html$/
23
+ filename = Dir.glob("capybara-*.html").first
24
+ expect(filename).to match(/^capybara-\d+\.html$/)
26
25
  end
27
26
 
28
27
  it "can store files in a specified directory" do
@@ -68,6 +67,7 @@ Capybara::SpecHelper.spec '#save_page' do
68
67
  path = @session.save_page
69
68
 
70
69
  result = File.read(path)
70
+ expect(result).to include('<html')
71
71
  expect(result).not_to include("http://example.com")
72
72
  end
73
73
 
@@ -76,7 +76,16 @@ Capybara::SpecHelper.spec '#save_page' do
76
76
  path = @session.save_page
77
77
 
78
78
  result = File.read(path)
79
+ expect(result).to include('<html')
79
80
  expect(result).not_to include("http://example.com")
80
81
  end
82
+
83
+ it "executes successfully even if the page is missing a <head>" do
84
+ @session.visit("/with_simple_html")
85
+ path = @session.save_page
86
+
87
+ result = File.read(path)
88
+ expect(result).to include("Bar")
89
+ end
81
90
  end
82
91
  end