capybara 2.4.4 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
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