capybara 1.0.0.beta1 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -26,12 +26,12 @@ On OSX you may have to install libffi, you can install it via MacPorts with:
26
26
  == Development:
27
27
 
28
28
  * Source hosted at {GitHub}[http://github.com/jnicklas/capybara].
29
- * Please direct questions, discussions at the {mailing list}[http://groups.google.com/group/ruby-capybara].
30
- * Report issues on {GitHub Issues}[http://github.com/jnicklas/capybara/issues]
29
+ * Please direct questions, discussion or problems to the {mailing list}[http://groups.google.com/group/ruby-capybara].
30
+ * If you found a reproducible bug, open a {GitHub Issue}[http://github.com/jnicklas/capybara/issues] to submit a bug report.
31
31
 
32
- Pull requests are very welcome! Make sure your patches are well tested, Capybara is
33
- a testing tool after all. Please create a topic branch for every separate change
34
- you make.
32
+ Pull requests are very welcome (and even better than bug reports)! Make sure
33
+ your patches are well tested, Capybara is a testing tool after all. Please
34
+ create a topic branch for every separate change you make.
35
35
 
36
36
  Capybara uses bundler in development. To set up a development environment, simply do:
37
37
 
@@ -88,7 +88,7 @@ by adding the following line (typically to your <tt>spec_helper.rb</tt> file):
88
88
 
89
89
  require 'capybara/rspec'
90
90
 
91
- You can now use it in your examples:
91
+ You can now write your specs like so:
92
92
 
93
93
  describe "the signup process", :type => :request do
94
94
  before :each do
@@ -104,16 +104,21 @@ You can now use it in your examples:
104
104
  end
105
105
  end
106
106
 
107
- Capybara is only included for examples with <tt>:type => :request</tt> (or
108
- <tt>:acceptance</tt> for compatibility).
107
+ Capybara is only included in example groups tagged with
108
+ <tt>:type => :request</tt> (or <tt>:acceptance</tt> for compatibility with Steak).
109
109
 
110
- If you use the <tt>rspec-rails</tt> gem, <tt>:type => :request</tt> is
111
- automatically set on all files under <tt>spec/requests</tt>. Essentially, these
112
- are Capybara-enhanced Rails request specs, so it's a good idea to place your
113
- Capybara specs here because within request specs you gain a few additional
114
- features, such as the ability to refer to named route helpers. If you do not
115
- need these, then you may simply use <tt>spec/acceptance</tt> and you will still
116
- get access to Capybara methods.
110
+ If you are testing a Rails app and using the <tt>rspec-rails</tt> gem, these
111
+ <tt>:request</tt> example groups may look familiar to you. That's because they
112
+ are RSpec versions of Rails integration tests. So, in this case essentially what you are getting are Capybara-enhanced request specs. This means that you can
113
+ use the Capybara helpers <i>and</i> you have access to things like named route
114
+ helpers in your tests (so you are able to say, for instance, <tt>visit
115
+ edit_user_path(user)</tt>, instead of <tt>visit "/users/#{user.id}/edit"</tt>,
116
+ if you prefer that sort of thing). A good place to put these specs is
117
+ <tt>spec/requests</tt>, as <tt>rspec-rails</tt> will automatically tag them with
118
+ <tt>:type => :request</tt>. (In fact, <tt>spec/integration</tt> and
119
+ <tt>spec/acceptance</tt> will work just as well.)
120
+
121
+ <tt>rspec-rails</tt> will also automatically include Capybara in <tt>:controller</tt> and <tt>:mailer</tt> example groups.
117
122
 
118
123
  RSpec's metadata feature can be used to switch to a different driver. Use
119
124
  <tt>:js => true</tt> to switch to the javascript driver, or provide a
@@ -124,7 +129,7 @@ RSpec's metadata feature can be used to switch to a different driver. Use
124
129
  it 'will switch to one specific driver', :driver => :celerity
125
130
  end
126
131
 
127
- Capybara also comes with a built in DSL for creating descriptive acceptance tests:
132
+ Finally, Capybara also comes with a built in DSL for creating descriptive acceptance tests:
128
133
 
129
134
  feature "Signing up" do
130
135
  background do
@@ -140,11 +145,10 @@ Capybara also comes with a built in DSL for creating descriptive acceptance test
140
145
  end
141
146
  end
142
147
 
143
- Essentially, this is just a shortcut for making a request spec, where
144
- <tt>feature</tt> is a shortcut for <tt>describe ..., :type => :request</tt>,
145
- <tt>background</tt> is an alias for <tt>before :each</tt>, and <tt>scenario</tt>
146
- is an alias for <tt>it</tt>/<tt>example</tt>. Again, you are encouraged to place
147
- these within <tt>spec/requests</tt> rather than <tt>spec/acceptance</tt>.
148
+ This is, in fact, just a shortcut for making a request spec, where
149
+ <tt>feature</tt> is an alias for <tt>describe ..., :type => :request</tt>,
150
+ <tt>background</tt> is an alias for <tt>before</tt>, and <tt>scenario</tt>
151
+ is an alias for <tt>it</tt>/<tt>specify</tt>.
148
152
 
149
153
  Note that Capybara's built in RSpec support only works with RSpec 2.0 or later.
150
154
  You'll need to roll your own for earlier versions of RSpec.
@@ -407,6 +411,9 @@ method. Optionally you can specify which kind of selector to use.
407
411
  fill_in 'Name', :with => 'Jimmy'
408
412
  end
409
413
 
414
+ Note that <tt>within</tt> will scope the actions to the _first_ (not _any_)
415
+ element that matches the selector.
416
+
410
417
  There are special methods for restricting the scope to a specific fieldset,
411
418
  identified by either an id or the text of the fieldet's legend tag, and to a
412
419
  specific table, identified by either id or text of the table's caption tag.
@@ -83,7 +83,7 @@ module Capybara
83
83
  # within(:row, 3) { page.should have_content('$100.000') }
84
84
  #
85
85
  # It might be convenient to specify that the selector is automatically chosen for certain
86
- # values. This way you don't have to explicitely specify that you are looking for a row, or
86
+ # values. This way you don't have to explicitly specify that you are looking for a row, or
87
87
  # an id. Let's say we want Capybara to treat any Symbols sent into methods like find to be
88
88
  # treated as though they were element ids. We could achieve this like so:
89
89
  #
@@ -35,15 +35,22 @@ class Capybara::RackTest::Browser
35
35
  new_uri = URI.parse(path)
36
36
  current_uri = URI.parse(current_url)
37
37
 
38
- path = request_path + path if path.start_with?('?')
39
- path = current_host + path if path.start_with?('/')
40
-
41
38
  if new_uri.host
42
39
  @current_host = new_uri.scheme + '://' + new_uri.host
43
40
  end
44
-
41
+
42
+ if new_uri.relative?
43
+ path = request_path + path if path.start_with?('?')
44
+
45
+ unless path.start_with?('/')
46
+ folders = request_path.split('/')
47
+ path = (folders[0, folders.size - 1] << path).join('/')
48
+ end
49
+ path = current_host + path
50
+ end
51
+
45
52
  reset_cache!
46
- send(method, to_binary(path), to_binary( attributes ), env)
53
+ send(method, path, attributes, env)
47
54
  follow_redirects!
48
55
  end
49
56
 
@@ -81,18 +88,9 @@ class Capybara::RackTest::Browser
81
88
 
82
89
  protected
83
90
 
84
- def to_binary(object)
85
- return object unless Kernel.const_defined?(:Encoding)
86
-
87
- if object.respond_to?(:force_encoding)
88
- object.dup.force_encoding(Encoding::ASCII_8BIT)
89
- elsif object.respond_to?(:each_pair) #Hash
90
- {}.tap { |x| object.each_pair {|k,v| x[to_binary(k)] = to_binary(v) } }
91
- elsif object.respond_to?(:each) #Array
92
- object.map{|x| to_binary(x)}
93
- else
94
- object
95
- end
91
+ def build_rack_mock_session
92
+ reset_host! unless current_host
93
+ Rack::MockSession.new(app, URI.parse(current_host).host)
96
94
  end
97
95
 
98
96
  def request_path
@@ -27,6 +27,10 @@ module Capybara
27
27
  "expected #{selector_name} not to return anything"
28
28
  end
29
29
 
30
+ def description
31
+ "has #{selector_name}"
32
+ end
33
+
30
34
  def selector_name
31
35
  name = "#{normalized.name} #{normalized.locator.inspect}"
32
36
  name << " with text #{normalized.options[:text].inspect}" if normalized.options[:text]
@@ -82,6 +86,10 @@ module Capybara
82
86
  "expected #{selector_name} not to return anything"
83
87
  end
84
88
 
89
+ def description
90
+ "has #{selector_name}"
91
+ end
92
+
85
93
  def selector_name
86
94
  selector_name = "#{name} #{locator.inspect}"
87
95
  selector_name << " with text #{options[:text].inspect}" if options[:text]
@@ -13,8 +13,10 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
13
13
  def browser
14
14
  unless @browser
15
15
  @browser = Selenium::WebDriver.for(options[:browser], options.reject { |key,val| SPECIAL_OPTIONS.include?(key) })
16
+
17
+ main = Process.pid
16
18
  at_exit do
17
- @browser.quit
19
+ quit if Process.pid == main
18
20
  end
19
21
  end
20
22
  @browser
@@ -110,6 +112,12 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
110
112
  browser.switch_to.window(handle, &blk)
111
113
  end
112
114
 
115
+ def quit
116
+ @browser.quit
117
+ rescue Errno::ECONNREFUSED
118
+ # Browser must have already gone
119
+ end
120
+
113
121
  private
114
122
 
115
123
  def load_wait_for_ajax_support
@@ -4,20 +4,16 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
4
4
  end
5
5
 
6
6
  def [](name)
7
- if name == :value
8
- value
9
- else
10
- native.attribute(name.to_s)
11
- end
7
+ native.attribute(name.to_s)
12
8
  rescue Selenium::WebDriver::Error::WebDriverError
13
9
  nil
14
10
  end
15
11
 
16
12
  def value
17
13
  if tag_name == "select" and self[:multiple] and not self[:multiple] == "false"
18
- native.find_elements(:xpath, ".//option").select { |n| n.selected? }.map { |n| n.value || n.text }
14
+ native.find_elements(:xpath, ".//option").select { |n| n.selected? }.map { |n| n[:value] || n.text }
19
15
  else
20
- native.value
16
+ native[:value]
21
17
  end
22
18
  end
23
19
 
@@ -54,7 +50,7 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
54
50
  end
55
51
 
56
52
  def tag_name
57
- native.tag_name
53
+ native.tag_name.downcase
58
54
  end
59
55
 
60
56
  def visible?
@@ -12,7 +12,7 @@ module Capybara
12
12
 
13
13
  def call(env)
14
14
  if env["PATH_INFO"] == "/__identify__"
15
- [200, {}, @app.object_id.to_s]
15
+ [200, {}, [@app.object_id.to_s]]
16
16
  else
17
17
  @app.call(env)
18
18
  end
@@ -12,6 +12,22 @@ shared_examples_for "click_button" do
12
12
  end
13
13
  end
14
14
 
15
+ context "with a form that has a relative url as an action" do
16
+ it "should post to the correct url" do
17
+ @session.click_button('Relative Action')
18
+ @session.current_path.should == '/relative'
19
+ extract_results(@session)['relative'].should == 'Relative Action'
20
+ end
21
+ end
22
+
23
+ context "with a form that has no action specified" do
24
+ it "should post to the correct url" do
25
+ @session.click_button('No Action')
26
+ @session.current_path.should == '/form'
27
+ extract_results(@session)['no_action'].should == 'No Action'
28
+ end
29
+ end
30
+
15
31
  context "with value given on a submit button" do
16
32
  context "on a form with HTML5 fields" do
17
33
  before do
@@ -284,4 +300,5 @@ shared_examples_for "click_button" do
284
300
  @session.body.should include('Postback')
285
301
  end
286
302
  end
303
+
287
304
  end
@@ -47,6 +47,10 @@ class TestApp < Sinatra::Base
47
47
  '<pre id="results">' + params[:form].to_yaml + '</pre>'
48
48
  end
49
49
 
50
+ post '/relative' do
51
+ '<pre id="results">' + params[:form].to_yaml + '</pre>'
52
+ end
53
+
50
54
  get '/favicon.ico' do
51
55
  nil
52
56
  end
@@ -351,3 +351,15 @@
351
351
  <input type="submit" name="form[button]" value="Just a button"/>
352
352
  </p>
353
353
  </form>
354
+
355
+ <form action="relative" method="post">
356
+ <p>
357
+ <input type="submit" name="form[relative]" value="Relative Action" />
358
+ </p>
359
+ </form>
360
+
361
+ <form method="post">
362
+ <p>
363
+ <input type="submit" name="form[no_action]" value="No Action" />
364
+ </p>
365
+ </form>
@@ -1,3 +1,3 @@
1
1
  module Capybara
2
- VERSION = '1.0.0.beta1'
2
+ VERSION = '1.0.0.rc1'
3
3
  end
@@ -25,29 +25,6 @@ describe Capybara::RackTest::Driver do
25
25
  end.should raise_error(ArgumentError)
26
26
  end
27
27
 
28
- if '1.9'.respond_to?(:encode)
29
- describe "with non-binary parameters" do
30
-
31
- it "should convert attribute values to binary" do
32
- output = capture(:stderr) {
33
- @driver.visit('/mypage', :param => 'µ')
34
- }.should_not =~ %r{warning: regexp match /.../n against to UTF-8 string}
35
- end
36
-
37
- it "should convert attribute with Array to binary" do
38
- output = capture(:stderr) {
39
- @driver.visit('/mypage', :param => ['µ'])
40
- }.should_not =~ %r{warning: regexp match /.../n against to UTF-8 string}
41
- end
42
-
43
- it "should convert path to binary" do
44
- output = capture(:stderr) {
45
- @driver.visit('/mypage'.encode('utf-8'))
46
- }.should_not =~ %r{warning: regexp match /.../n against to UTF-8 string}
47
- end
48
- end
49
- end
50
-
51
28
  it_should_behave_like "driver"
52
29
  it_should_behave_like "driver with header support"
53
30
  it_should_behave_like "driver with status code support"
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'rbconfig'
2
3
 
3
4
  describe Capybara::Selenium::Driver do
4
5
  before do
@@ -12,4 +13,17 @@ describe Capybara::Selenium::Driver do
12
13
  it_should_behave_like "driver with support for window switching"
13
14
  it_should_behave_like "driver without status code support"
14
15
  it_should_behave_like "driver with cookies support"
16
+
17
+ unless Config::CONFIG['host_os'] =~ /mswin|mingw/
18
+ it "should not interfere with forking child processes" do
19
+ # Launch a browser, which registers the at_exit hook
20
+ browser = Capybara::Selenium::Driver.new(TestApp).browser
21
+
22
+ # Fork an unrelated child process. This should not run the code in the at_exit hook.
23
+ pid = fork { "child" }
24
+ Process.wait2(pid)[1].exitstatus.should == 0
25
+
26
+ browser.quit
27
+ end
28
+ end
15
29
  end
@@ -9,6 +9,10 @@ describe Capybara::RSpecMatchers do
9
9
  include Capybara::RSpecMatchers
10
10
 
11
11
  describe "have_css matcher" do
12
+ it "gives proper description" do
13
+ have_css('h1').description.should == "has css \"h1\""
14
+ end
15
+
12
16
  context "on a string" do
13
17
  context "with should" do
14
18
  it "passes if has_css? returns true" do
@@ -87,6 +91,10 @@ describe Capybara::RSpecMatchers do
87
91
  end
88
92
 
89
93
  describe "have_xpath matcher" do
94
+ it "gives proper description" do
95
+ have_xpath('//h1').description.should == "has xpath \"\/\/h1\""
96
+ end
97
+
90
98
  context "on a string" do
91
99
  context "with should" do
92
100
  it "passes if has_css? returns true" do
@@ -145,6 +153,10 @@ describe Capybara::RSpecMatchers do
145
153
  end
146
154
 
147
155
  describe "have_selector matcher" do
156
+ it "gives proper description" do
157
+ have_selector('//h1').description.should == "has xpath \"//h1\""
158
+ end
159
+
148
160
  context "on a string" do
149
161
  context "with should" do
150
162
  it "passes if has_css? returns true" do
@@ -229,6 +241,10 @@ describe Capybara::RSpecMatchers do
229
241
  end
230
242
 
231
243
  describe "have_content matcher" do
244
+ it "gives proper description" do
245
+ have_content('Text').description.should == "has content \"Text\""
246
+ end
247
+
232
248
  context "on a string" do
233
249
  context "with should" do
234
250
  it "passes if has_css? returns true" do
@@ -299,6 +315,10 @@ describe Capybara::RSpecMatchers do
299
315
  describe "have_link matcher" do
300
316
  let(:html) { '<a href="#">Just a link</a>' }
301
317
 
318
+ it "gives proper description" do
319
+ have_link('Just a link').description.should == "has link \"Just a link\""
320
+ end
321
+
302
322
  it "passes if there is such a button" do
303
323
  html.should have_link('Just a link')
304
324
  end
@@ -313,6 +333,10 @@ describe Capybara::RSpecMatchers do
313
333
  describe "have_button matcher" do
314
334
  let(:html) { '<button>A button</button><input type="submit" value="Another button"/>' }
315
335
 
336
+ it "gives proper description" do
337
+ have_button('A button').description.should == "has button \"A button\""
338
+ end
339
+
316
340
  it "passes if there is such a button" do
317
341
  html.should have_button('A button')
318
342
  end
@@ -327,6 +351,10 @@ describe Capybara::RSpecMatchers do
327
351
  describe "have_field matcher" do
328
352
  let(:html) { '<p><label>Text field<input type="text"/></label></p>' }
329
353
 
354
+ it "gives proper description" do
355
+ have_field('Text field').description.should == "has field \"Text field\""
356
+ end
357
+
330
358
  it "passes if there is such a field" do
331
359
  html.should have_field('Text field')
332
360
  end
@@ -344,6 +372,10 @@ describe Capybara::RSpecMatchers do
344
372
  <label>unchecked field<input type="checkbox"/></label>'
345
373
  end
346
374
 
375
+ it "gives proper description" do
376
+ have_checked_field('it is checked').description.should == "has checked_field \"it is checked\""
377
+ end
378
+
347
379
  context "with should" do
348
380
  it "passes if there is such a field and it is checked" do
349
381
  html.should have_checked_field('it is checked')
@@ -385,6 +417,10 @@ describe Capybara::RSpecMatchers do
385
417
  <label>unchecked field<input type="checkbox"/></label>'
386
418
  end
387
419
 
420
+ it "gives proper description" do
421
+ have_unchecked_field('unchecked field').description.should == "has unchecked_field \"unchecked field\""
422
+ end
423
+
388
424
  context "with should" do
389
425
  it "passes if there is such a field and it is not checked" do
390
426
  html.should have_unchecked_field('unchecked field')
@@ -423,6 +459,10 @@ describe Capybara::RSpecMatchers do
423
459
  describe "have_select matcher" do
424
460
  let(:html) { '<label>Select Box<select></select></label>' }
425
461
 
462
+ it "gives proper description" do
463
+ have_select('Select Box').description.should == "has select \"Select Box\""
464
+ end
465
+
426
466
  it "passes if there is such a select" do
427
467
  html.should have_select('Select Box')
428
468
  end
@@ -437,6 +477,10 @@ describe Capybara::RSpecMatchers do
437
477
  describe "have_table matcher" do
438
478
  let(:html) { '<table><caption>Lovely table</caption></table>' }
439
479
 
480
+ it "gives proper description" do
481
+ have_table('Lovely table').description.should == "has table \"Lovely table\""
482
+ end
483
+
440
484
  it "passes if there is such a select" do
441
485
  html.should have_table('Lovely table')
442
486
  end
@@ -5,6 +5,15 @@ require "bundler/setup"
5
5
 
6
6
  require 'rspec'
7
7
  require 'capybara'
8
+
9
+ RSpec.configure do |config|
10
+ config.before do
11
+ Capybara.configure do |config|
12
+ config.default_selector = :xpath
13
+ end
14
+ end
15
+ end
16
+
8
17
  require 'capybara/spec/driver'
9
18
  require 'capybara/spec/session'
10
19
 
@@ -15,12 +24,4 @@ Capybara.default_wait_time = 0 # less timeout so tests run faster
15
24
  module TestSessions
16
25
  RackTest = Capybara::Session.new(:rack_test, TestApp)
17
26
  Selenium = Capybara::Session.new(:selenium, TestApp)
18
- end
19
-
20
- RSpec.configure do |config|
21
- config.before do
22
- Capybara.configure do |config|
23
- config.default_selector = :xpath
24
- end
25
- end
26
- end
27
+ end
metadata CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
6
6
  - 1
7
7
  - 0
8
8
  - 0
9
- - beta1
10
- version: 1.0.0.beta1
9
+ - rc1
10
+ version: 1.0.0.rc1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jonas Nicklas
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-04-25 00:00:00 +02:00
18
+ date: 2011-06-07 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -53,13 +53,13 @@ dependencies:
53
53
  requirement: &id003 !ruby/object:Gem::Requirement
54
54
  none: false
55
55
  requirements:
56
- - - ">="
56
+ - - ~>
57
57
  - !ruby/object:Gem::Version
58
58
  segments:
59
59
  - 0
60
+ - 2
60
61
  - 0
61
- - 27
62
- version: 0.0.27
62
+ version: 0.2.0
63
63
  type: :runtime
64
64
  version_requirements: *id003
65
65
  - !ruby/object:Gem::Dependency