capybara 2.10.2 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +15 -0
  3. data/README.md +48 -29
  4. data/lib/capybara.rb +8 -9
  5. data/lib/capybara/node/actions.rb +39 -48
  6. data/lib/capybara/node/document.rb +4 -0
  7. data/lib/capybara/node/document_matchers.rb +13 -14
  8. data/lib/capybara/node/element.rb +21 -0
  9. data/lib/capybara/node/finders.rb +3 -3
  10. data/lib/capybara/node/matchers.rb +38 -31
  11. data/lib/capybara/node/simple.rb +3 -0
  12. data/lib/capybara/queries/selector_query.rb +4 -2
  13. data/lib/capybara/rack_test/node.rb +1 -1
  14. data/lib/capybara/result.rb +3 -1
  15. data/lib/capybara/rspec/matchers.rb +53 -95
  16. data/lib/capybara/selector.rb +7 -7
  17. data/lib/capybara/selector/selector.rb +10 -5
  18. data/lib/capybara/selenium/driver.rb +34 -7
  19. data/lib/capybara/selenium/node.rb +5 -1
  20. data/lib/capybara/session.rb +22 -27
  21. data/lib/capybara/session/matchers.rb +12 -14
  22. data/lib/capybara/spec/public/test.js +4 -0
  23. data/lib/capybara/spec/session/accept_alert_spec.rb +1 -1
  24. data/lib/capybara/spec/session/attach_file_spec.rb +1 -1
  25. data/lib/capybara/spec/session/check_spec.rb +8 -0
  26. data/lib/capybara/spec/session/choose_spec.rb +5 -0
  27. data/lib/capybara/spec/session/click_link_or_button_spec.rb +5 -0
  28. data/lib/capybara/spec/session/click_link_spec.rb +5 -0
  29. data/lib/capybara/spec/session/element/assert_match_selector.rb +5 -0
  30. data/lib/capybara/spec/session/element/match_css_spec.rb +6 -0
  31. data/lib/capybara/spec/session/element/matches_selector_spec.rb +2 -0
  32. data/lib/capybara/spec/session/fill_in_spec.rb +5 -0
  33. data/lib/capybara/spec/session/find_spec.rb +1 -1
  34. data/lib/capybara/spec/session/first_spec.rb +10 -0
  35. data/lib/capybara/spec/session/has_selector_spec.rb +11 -0
  36. data/lib/capybara/spec/session/node_spec.rb +3 -3
  37. data/lib/capybara/spec/session/text_spec.rb +3 -4
  38. data/lib/capybara/spec/views/with_js.erb +3 -1
  39. data/lib/capybara/version.rb +1 -1
  40. data/lib/capybara/window.rb +18 -2
  41. data/spec/basic_node_spec.rb +1 -1
  42. data/spec/capybara_spec.rb +4 -1
  43. data/spec/fixtures/selenium_driver_rspec_failure.rb +4 -1
  44. data/spec/fixtures/selenium_driver_rspec_success.rb +4 -1
  45. data/spec/result_spec.rb +28 -2
  46. data/spec/rspec/{matchers_spec.rb → shared_spec_matchers.rb} +4 -3
  47. data/spec/selector_spec.rb +1 -1
  48. data/spec/selenium_spec_chrome.rb +36 -5
  49. data/spec/selenium_spec_firefox.rb +67 -0
  50. data/spec/selenium_spec_marionette.rb +114 -0
  51. data/spec/shared_selenium_session.rb +6 -4
  52. metadata +13 -6
  53. data/spec/selenium_firefox_spec.rb +0 -44
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 21fdd89225cd5ecf58f6e1eb72da29832f70ba9a
4
- data.tar.gz: edada38839bc4b98461a27b02f196ec2e2e58ac7
3
+ metadata.gz: b4d75941bdc33b8e4b3d26aa8beb1a6d063fabca
4
+ data.tar.gz: 692a680d4d550e566e6c558bfe53608a024b4e49
5
5
  SHA512:
6
- metadata.gz: 4f2ed74c7e278e93c5dcf3f92ab35b51a2b31578bff67e25c83076f65ab8e7edd50a2b63afd41ddd65e0a7bc438e6d27adcaae17fcafad6f0e4cd52b241e5797
7
- data.tar.gz: a97567024d5a9d18858e8b4b1b9920819a6655708f87206ad5c281de9bb39cb5e2185dd1f710618e745483c925ba6e09bbba143d17f7ded222c80acab7be9ce2
6
+ metadata.gz: e9eee2dae8d51f3bff73da658a08d2aeefd6383c16cec7b269abbb2c99203239c996c83b0145946d473cc0d3d1076abd623f672dfa07dd4ad0ed9a74ea2ef001
7
+ data.tar.gz: 2fef0e0fb22d31ccbd4879df37100feb6c717508c57266539245d07a3ba74c3849ae02cab2dfc735054b6344effb2c4f6783658e95a3513737aa81cabb39f83e
data/History.md CHANGED
@@ -1,3 +1,18 @@
1
+ #2.11.0
2
+ Release date: 2016-12-05
3
+
4
+ ### Added
5
+ * Options for clearing session/local storage on reset added to the Selenium driver
6
+ * Window size changes wait for the size to stabilize
7
+ * Defined return value for most actions
8
+ * Ignore specific error when qutting selenium driver instance - Issue #1773 [Dylan Reichstadt, Thomas Walpole]
9
+ * Warn on selenium unknown errors rather than raising when quitting driver [Adam Pohorecki, Thomas Walpole]
10
+ * Capybara::Result#each now returns an `Enumerator` when called without a block - Issue #1777 [Thomas Walpole]
11
+
12
+ ### Fixed
13
+ * Selenium driver with Chrome should support multiple file upload [Thomas Walpole]
14
+ * Fix visible: :hidden with :text option behavior [Thomas Walpole]
15
+
1
16
  #2.10.2
2
17
  Release date: 2016-11-30
3
18
 
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Capybara
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/jnicklas/capybara.svg)](https://travis-ci.org/jnicklas/capybara)
4
- [![Dependency Status](https://gemnasium.com/jnicklas/capybara.svg)](https://gemnasium.com/jnicklas/capybara)
5
- [![Code Climate](https://codeclimate.com/github/jnicklas/capybara.svg)](https://codeclimate.com/github/jnicklas/capybara)
3
+ [![Build Status](https://secure.travis-ci.org/teamcapybara/capybara.svg)](https://travis-ci.org/teamcapybara/capybara)
4
+ [![Dependency Status](https://gemnasium.com/teamcapybara/capybara.svg)](https://gemnasium.com/teamcapybara/capybara)
5
+ [![Code Climate](https://codeclimate.com/github/teamcapybara/capybara.svg)](https://codeclimate.com/github/teamcapybara/capybara)
6
6
  [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jnicklas/capybara?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
7
7
 
8
8
  Capybara helps you test web applications by simulating how a real user would
@@ -13,7 +13,21 @@ through an external gem.
13
13
  **Need help?** Ask on the mailing list (please do not open an issue on
14
14
  GitHub): http://groups.google.com/group/ruby-capybara
15
15
 
16
- **Note: Firefox 48+** If you're using Firefox with selenium-webdriver, stay on either Firefox [45.0esr](https://ftp.mozilla.org/pub/firefox/releases/45.0esr/) or [47.0.1](https://ftp.mozilla.org/pub/firefox/releases/47.0.1/) and selenium-webdriver 2.53.4. Firefox 48+ requires geckodriver and selenium-webdriver v3, the combo of which currently has multiple issues and is feature incomplete.
16
+ **Note: Firefox 48+** If you're using Firefox with selenium-webdriver and want full functionality stay on either Firefox [45.0esr](https://ftp.mozilla.org/pub/firefox/releases/45.0esr/) or [47.0.1](https://ftp.mozilla.org/pub/firefox/releases/47.0.1/).
17
+ If using selenium-webdriver 3.0+ this will require configuring your driver with the `marionette: false` option as shown below
18
+
19
+ ```ruby
20
+ Capybara.register_driver :selenium do |app|
21
+ Capybara::Selenium::Driver.new(
22
+ app,
23
+ browser: :firefox,
24
+ desired_capabilities: Selenium::WebDriver::Remote::Capabilities.firefox(marionette: false)
25
+ )
26
+ end
27
+ ```
28
+
29
+ Using Firefox 48+ requires geckodriver and selenium-webdriver v3, the combo of which currently has multiple issues and is feature incomplete.
30
+ You can read more about the missing features [here](https://github.com/teamcapybara/capybara/issues/1710).
17
31
 
18
32
  ## Table of contents
19
33
 
@@ -129,7 +143,7 @@ tags set up for you.
129
143
 
130
144
  ## <a name="using-capybara-with-rspec"></a>Using Capybara with RSpec
131
145
 
132
- Load RSpec 2.x support by adding the following line (typically to your
146
+ Load RSpec 2+ support by adding the following line (typically to your
133
147
  `spec_helper.rb` file):
134
148
 
135
149
  ```ruby
@@ -392,7 +406,7 @@ any Javascript errors that happen within the page.
392
406
  ## <a name="the-dsl"></a>The DSL
393
407
 
394
408
  *A complete reference is available at
395
- [rubydoc.info](http://rubydoc.info/github/jnicklas/capybara/master)*.
409
+ [rubydoc.info](http://rubydoc.info/github/teamcapybara/capybara/master)*.
396
410
 
397
411
  **Note: By default Capybara will only locate visible elements. This is because
398
412
  a real user would not be able to interact with non-visible elements.**
@@ -403,7 +417,7 @@ Capybara heavily uses XPath, which doesn't support case insensitivity.
403
417
  ### <a name="navigating"></a>Navigating
404
418
 
405
419
  You can use the
406
- <tt>[visit](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session#visit-instance_method)</tt>
420
+ <tt>[visit](http://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Session#visit-instance_method)</tt>
407
421
  method to navigate to other pages:
408
422
 
409
423
  ```ruby
@@ -414,8 +428,8 @@ visit(post_comments_path(post))
414
428
  The visit method only takes a single parameter, the request method is **always**
415
429
  GET.
416
430
 
417
- You can get the [current path](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session#current_path-instance_method)
418
- of the browsing session, and test it using the [`have_current_path`](http://www.rubydoc.info/github/jnicklas/capybara/master/Capybara/RSpecMatchers#have_current_path-instance_method) matcher:
431
+ You can get the [current path](http://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Session#current_path-instance_method)
432
+ of the browsing session, and test it using the [`have_current_path`](http://www.rubydoc.info/github/teamcapybara/capybara/master/Capybara/RSpecMatchers#have_current_path-instance_method) matcher:
419
433
 
420
434
  ```ruby
421
435
  expect(page).to have_current_path(post_comments_path(post))
@@ -428,7 +442,7 @@ to ensure that preceding actions (such as a `click_link`) have completed.
428
442
 
429
443
  ### <a name="clicking-links-and-buttons"></a>Clicking links and buttons
430
444
 
431
- *Full reference: [Capybara::Node::Actions](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Actions)*
445
+ *Full reference: [Capybara::Node::Actions](http://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Actions)*
432
446
 
433
447
  You can interact with the webapp by following links and buttons. Capybara
434
448
  automatically follows any redirects, and submits forms associated with buttons.
@@ -443,7 +457,7 @@ click_on('Button Value')
443
457
 
444
458
  ### <a name="interacting-with-forms"></a>Interacting with forms
445
459
 
446
- *Full reference: [Capybara::Node::Actions](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Actions)*
460
+ *Full reference: [Capybara::Node::Actions](http://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Actions)*
447
461
 
448
462
  There are a number of tools for interacting with form elements:
449
463
 
@@ -460,16 +474,16 @@ select('Option', from: 'Select Box')
460
474
 
461
475
  ### <a name="querying"></a>Querying
462
476
 
463
- *Full reference: [Capybara::Node::Matchers](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Matchers)*
477
+ *Full reference: [Capybara::Node::Matchers](http://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Matchers)*
464
478
 
465
479
  Capybara has a rich set of options for querying the page for the existence of
466
480
  certain elements, and working with and manipulating those elements.
467
481
 
468
482
  ```ruby
469
483
  page.has_selector?('table tr')
470
- page.has_selector?(:xpath, '//table/tr')
484
+ page.has_selector?(:xpath, './/table/tr')
471
485
 
472
- page.has_xpath?('//table/tr')
486
+ page.has_xpath?('.//table/tr')
473
487
  page.has_css?('table tr.foo')
474
488
  page.has_content?('foo')
475
489
  ```
@@ -481,34 +495,39 @@ You can use these with RSpec's magic matchers:
481
495
 
482
496
  ```ruby
483
497
  expect(page).to have_selector('table tr')
484
- expect(page).to have_selector(:xpath, '//table/tr')
498
+ expect(page).to have_selector(:xpath, './/table/tr')
485
499
 
486
- expect(page).to have_xpath('//table/tr')
500
+ expect(page).to have_xpath('.//table/tr')
487
501
  expect(page).to have_css('table tr.foo')
488
502
  expect(page).to have_content('foo')
489
503
  ```
490
504
 
491
505
  ### <a name="finding"></a>Finding
492
506
 
493
- _Full reference: [Capybara::Node::Finders](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Finders)_
507
+ _Full reference: [Capybara::Node::Finders](http://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Node/Finders)_
494
508
 
495
509
  You can also find specific elements, in order to manipulate them:
496
510
 
497
511
  ```ruby
498
512
  find_field('First Name').value
513
+ find_field(id: 'my_field').value
499
514
  find_link('Hello', :visible => :all).visible?
515
+ find_link(class: ['some_class', 'some_other_class'], :visible => :all).visible?
516
+
500
517
  find_button('Send').click
518
+ find_button(value: '1234').click
501
519
 
502
- find(:xpath, "//table/tr").click
520
+ find(:xpath, ".//table/tr").click
503
521
  find("#overlay").find("h1").click
504
522
  all('a').each { |a| a[:href] }
505
523
  ```
506
524
 
507
525
  If you need to find elements by additional attributes/properties you can also pass a filter block, which will be checked inside the normal waiting behavior.
508
- If you find yourself needing to use this a lot you may be better off adding a [custom selector](http://www.rubydoc.info/github/jnicklas/capybara/Capybara#add_selector-class_method) or [adding a filter to an existing selector](http://www.rubydoc.info/github/jnicklas/capybara/Capybara#modify_selector-class_method).
526
+ If you find yourself needing to use this a lot you may be better off adding a [custom selector](http://www.rubydoc.info/github/teamcapybara/capybara/Capybara#add_selector-class_method) or [adding a filter to an existing selector](http://www.rubydoc.info/github/teamcapybara/capybara/Capybara#modify_selector-class_method).
509
527
 
510
528
  ```ruby
511
529
  find_field('First Name'){ |el| el['data-xyz'] == '123' }
530
+ find("#img_loading"){ |img| img['complete'] == true }
512
531
  ````
513
532
 
514
533
  **Note**: `find` will wait for an element to appear on the page, as explained in the
@@ -527,7 +546,7 @@ expect(find('#navigation')).to have_button('Sign out')
527
546
  Capybara makes it possible to restrict certain actions, such as interacting with
528
547
  forms or clicking links and buttons, to within a specific area of the page. For
529
548
  this purpose you can use the generic
530
- <tt>[within](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session#within-instance_method)</tt>
549
+ <tt>[within](http://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Session#within-instance_method)</tt>
531
550
  method. Optionally you can specify which kind of selector to use.
532
551
 
533
552
  ```ruby
@@ -535,7 +554,7 @@ within("li#employee") do
535
554
  fill_in 'Name', with: 'Jimmy'
536
555
  end
537
556
 
538
- within(:xpath, "//li[@id='employee']") do
557
+ within(:xpath, ".//li[@id='employee']") do
539
558
  fill_in 'Name', with: 'Jimmy'
540
559
  end
541
560
  ```
@@ -632,7 +651,7 @@ save_and_open_page
632
651
  ```
633
652
 
634
653
  You can also retrieve the current state of the DOM as a string using
635
- <tt>[page.html](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session#html-instance_method)</tt>.
654
+ <tt>[page.html](http://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Session#html-instance_method)</tt>.
636
655
 
637
656
  ```ruby
638
657
  print page.html
@@ -788,7 +807,7 @@ module MyModule
788
807
  include Capybara::DSL
789
808
 
790
809
  def login!
791
- within(:xpath, "//form[@id='session']") do
810
+ within(:xpath, ".//form[@id='session']") do
792
811
  fill_in 'Email', with: 'user@example.com'
793
812
  fill_in 'Password', with: 'password'
794
813
  end
@@ -852,7 +871,7 @@ Capybara.session_name = "some other session"
852
871
  ### <a name="using-sessions-manually"></a>Using sessions manually
853
872
 
854
873
  For ultimate control, you can instantiate and use a
855
- [Session](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session)
874
+ [Session](http://rubydoc.info/github/teamcapybara/capybara/master/Capybara/Session)
856
875
  manually.
857
876
 
858
877
  ```ruby
@@ -873,16 +892,16 @@ and will always use CSS by default. If you want to use XPath, you'll need to
873
892
  do:
874
893
 
875
894
  ```ruby
876
- within(:xpath, '//ul/li') { ... }
877
- find(:xpath, '//ul/li').text
878
- find(:xpath, '//li[contains(.//a[@href = "#"]/text(), "foo")]').value
895
+ within(:xpath, './/ul/li') { ... }
896
+ find(:xpath, './/ul/li').text
897
+ find(:xpath, './/li[contains(.//a[@href = "#"]/text(), "foo")]').value
879
898
  ```
880
899
 
881
900
  Alternatively you can set the default selector to XPath:
882
901
 
883
902
  ```ruby
884
903
  Capybara.default_selector = :xpath
885
- find('//ul/li').text
904
+ find('.//ul/li').text
886
905
  ```
887
906
 
888
907
  Capybara allows you to add custom selectors, which can be very useful if you
@@ -1010,5 +1029,5 @@ bundle exec rake # run the test suite
1010
1029
  ```
1011
1030
 
1012
1031
  See
1013
- [CONTRIBUTING.md](https://github.com/jnicklas/capybara/blob/master/CONTRIBUTING.md)
1032
+ [CONTRIBUTING.md](https://github.com/teamcapybara/capybara/blob/master/CONTRIBUTING.md)
1014
1033
  for how to send issues and pull requests.
@@ -25,7 +25,8 @@ module Capybara
25
25
  attr_accessor :server_port, :exact, :match, :exact_options, :visible_text_only, :enable_aria_label
26
26
  attr_accessor :default_selector, :default_max_wait_time, :ignore_hidden_elements
27
27
  attr_accessor :save_path, :wait_on_first_by_default, :automatic_label_click, :automatic_reload
28
- attr_accessor :reuse_server, :raise_server_errors, :server_errors
28
+ attr_reader :reuse_server
29
+ attr_accessor :raise_server_errors, :server_errors
29
30
  attr_writer :default_driver, :current_driver, :javascript_driver, :session_name, :server_host
30
31
  attr_reader :save_and_open_page_path
31
32
  attr_accessor :app
@@ -331,7 +332,7 @@ module Capybara
331
332
  #
332
333
  def reset_sessions!
333
334
  #reset in reverse so sessions that started servers are reset last
334
- session_pool.reverse_each { |mode, session| session.reset! }
335
+ session_pool.reverse_each { |_mode, session| session.reset! }
335
336
  end
336
337
  alias_method :reset!, :reset_sessions!
337
338
 
@@ -391,12 +392,12 @@ module Capybara
391
392
  end
392
393
 
393
394
  def app_host=(url)
394
- raise ArgumentError.new("Capybara.app_host should be set to a url (http://www.example.com)") unless url.nil? || (url =~ URI::regexp)
395
+ raise ArgumentError.new("Capybara.app_host should be set to a url (http://www.example.com)") unless url.nil? || (url =~ URI::Parser.new.make_regexp)
395
396
  @app_host = url
396
397
  end
397
398
 
398
399
  def default_host=(url)
399
- raise ArgumentError.new("Capybara.default_host should be set to a url (http://www.example.com)") unless url.nil? || (url =~ URI::regexp)
400
+ raise ArgumentError.new("Capybara.default_host should be set to a url (http://www.example.com)") unless url.nil? || (url =~ URI::Parser.new.make_regexp)
400
401
  @default_host = url
401
402
  end
402
403
 
@@ -469,7 +470,7 @@ module Capybara
469
470
  require 'capybara/selenium/driver'
470
471
  end
471
472
 
472
- Capybara.register_server :default do |app, port, host|
473
+ Capybara.register_server :default do |app, port, _host|
473
474
  Capybara.run_default_server(app, port)
474
475
  end
475
476
 
@@ -479,10 +480,8 @@ Capybara.register_server :webrick do |app, port, host|
479
480
  end
480
481
 
481
482
  Capybara.register_server :puma do |app, port, host|
482
- require 'puma'
483
- Puma::Server.new(app).tap do |s|
484
- s.add_tcp_listener host, port
485
- end.run.join
483
+ require 'rack/handler/puma'
484
+ Rack::Handler::Puma.run(app, Host: host, Port: port, Threads: "0:4")
486
485
  end
487
486
 
488
487
  Capybara.configure do |config|
@@ -18,6 +18,8 @@ module Capybara
18
18
  #
19
19
  # @param [String] locator Text, id or value of link or button
20
20
  #
21
+ # @return [Capybara::Node::Element] The element clicked
22
+ #
21
23
  def click_link_or_button(locator=nil, options={})
22
24
  locator, options = nil, locator if locator.is_a? Hash
23
25
  find(:link_or_button, locator, options).click
@@ -35,6 +37,7 @@ module Capybara
35
37
  # @param [String] locator text, id, title or nested image's alt attribute
36
38
  # @param options See {Capybara::Node::Finders#find_link}
37
39
  #
40
+ # @return [Capybara::Node::Element] The element clicked
38
41
  def click_link(locator=nil, options={})
39
42
  locator, options = nil, locator if locator.is_a? Hash
40
43
  find(:link, locator, options).click
@@ -52,6 +55,7 @@ module Capybara
52
55
  # @overload click_button([locator], options)
53
56
  # @param [String] locator Which button to find
54
57
  # @param options See {Capybara::Node::Finders#find_button}
58
+ # @return [Capybara::Node::Element] The element clicked
55
59
  def click_button(locator=nil, options={})
56
60
  locator, options = nil, locator if locator.is_a? Hash
57
61
  find(:button, locator, options).click
@@ -77,6 +81,7 @@ module Capybara
77
81
  # @option options [String] :placeholder Match fields that match the placeholder attribute
78
82
  # @option options [String, Array<String>] :class Match links that match the class(es) provided
79
83
  #
84
+ # @return [Capybara::Node::Element] The element filled_in
80
85
  def fill_in(locator, options={})
81
86
  locator, options = nil, locator if locator.is_a? Hash
82
87
  raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with)
@@ -104,23 +109,10 @@ module Capybara
104
109
  # @option options [String, Array<String>] :class Match links that match the class(es) provided
105
110
  # @macro waiting_behavior
106
111
  # @macro label_click
112
+ #
113
+ # @return [Capybara::Node::Element] The element chosen or the label clicked
107
114
  def choose(locator, options={})
108
- locator, options = nil, locator if locator.is_a? Hash
109
- allow_label_click = options.delete(:allow_label_click) { Capybara.automatic_label_click }
110
-
111
- begin
112
- radio = find(:radio_button, locator, options)
113
- radio.set(true)
114
- rescue => e
115
- raise unless allow_label_click && catch_error?(e)
116
- begin
117
- radio ||= find(:radio_button, locator, options.merge({wait: 0, visible: :all}))
118
- label = find(:label, for: radio, wait: 0, visible: true)
119
- label.click unless radio.checked?
120
- rescue
121
- raise e
122
- end
123
- end
115
+ _check_with_label(:radio_button, true, locator, options)
124
116
  end
125
117
 
126
118
  ##
@@ -141,23 +133,9 @@ module Capybara
141
133
  # @macro label_click
142
134
  # @macro waiting_behavior
143
135
  #
136
+ # @return [Capybara::Node::Element] The element checked or the label clicked
144
137
  def check(locator, options={})
145
- locator, options = nil, locator if locator.is_a? Hash
146
- allow_label_click = options.delete(:allow_label_click) { Capybara.automatic_label_click }
147
-
148
- begin
149
- cbox = find(:checkbox, locator, options)
150
- cbox.set(true)
151
- rescue => e
152
- raise unless allow_label_click && catch_error?(e)
153
- begin
154
- cbox ||= find(:checkbox, locator, options.merge({wait: 0, visible: :all}))
155
- label = find(:label, for: cbox, wait: 0, visible: true)
156
- label.click unless cbox.checked?
157
- rescue
158
- raise e
159
- end
160
- end
138
+ _check_with_label(:checkbox, true, locator, options)
161
139
  end
162
140
 
163
141
  ##
@@ -178,23 +156,9 @@ module Capybara
178
156
  # @macro label_click
179
157
  # @macro waiting_behavior
180
158
  #
159
+ # @return [Capybara::Node::Element] The element unchecked or the label clicked
181
160
  def uncheck(locator, options={})
182
- locator, options = nil, locator if locator.is_a? Hash
183
- allow_label_click = options.delete(:allow_label_click) { Capybara.automatic_label_click }
184
-
185
- begin
186
- cbox = find(:checkbox, locator, options)
187
- cbox.set(false)
188
- rescue => e
189
- raise unless allow_label_click && catch_error?(e)
190
- begin
191
- cbox ||= find(:checkbox, locator, options.merge({wait: 0, visible: :all}))
192
- label = find(:label, for: cbox, wait: 0, visible: true)
193
- label.click if cbox.checked?
194
- rescue
195
- raise e
196
- end
197
- end
161
+ _check_with_label(:checkbox, false, locator, options)
198
162
  end
199
163
 
200
164
  ##
@@ -213,6 +177,7 @@ module Capybara
213
177
  # @param [String] value Which option to select
214
178
  # @option options [String] :from The id, name or label of the select box
215
179
  #
180
+ # @return [Capybara::Node::Element] The option element selected
216
181
  def select(value, options={})
217
182
  if options.has_key?(:from)
218
183
  from = options.delete(:from)
@@ -235,6 +200,7 @@ module Capybara
235
200
  # @param [String] value Which option to unselect
236
201
  # @param [Hash{:from => String}] options The id, name or label of the select box
237
202
  #
203
+ # @return [Capybara::Node::Element] The option element unselected
238
204
  def unselect(value, options={})
239
205
  if options.has_key?(:from)
240
206
  from = options.delete(:from)
@@ -263,6 +229,7 @@ module Capybara
263
229
  # @option options [String] name Match fields that match the name attribute
264
230
  # @option options [String, Array<String>] :class Match links that match the class(es) provided
265
231
  #
232
+ # @return [Capybara::Node::Element] The file field element
266
233
  def attach_file(locator, path, options={})
267
234
  locator, path, options = nil, locator, path if path.is_a? Hash
268
235
  Array(path).each do |p|
@@ -270,6 +237,30 @@ module Capybara
270
237
  end
271
238
  find(:file_field, locator, options).set(path)
272
239
  end
240
+
241
+ private
242
+
243
+ def _check_with_label(selector, checked, locator, options)
244
+ locator, options = nil, locator if locator.is_a? Hash
245
+ allow_label_click = options.delete(:allow_label_click) { Capybara.automatic_label_click }
246
+
247
+ synchronize(Capybara::Queries::BaseQuery::wait(options)) do
248
+ begin
249
+ el = find(selector, locator, options)
250
+ el.set(checked)
251
+ rescue => e
252
+ raise unless allow_label_click && catch_error?(e)
253
+ begin
254
+ el ||= find(selector, locator, options.merge(visible: :all))
255
+ label = find(:label, for: el, visible: true)
256
+ label.click unless (el.checked? == checked)
257
+ rescue
258
+ raise e
259
+ end
260
+ end
261
+ end
262
+ end
263
+
273
264
  end
274
265
  end
275
266
  end