capybara 2.5.0 → 2.18.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 (205) hide show
  1. checksums.yaml +5 -5
  2. data/.yard/templates_custom/default/class/html/selectors.erb +38 -0
  3. data/.yard/templates_custom/default/class/html/setup.rb +17 -0
  4. data/.yard/yard_extensions.rb +78 -0
  5. data/.yardopts +1 -0
  6. data/History.md +413 -10
  7. data/License.txt +1 -1
  8. data/README.md +237 -130
  9. data/lib/capybara/config.rb +132 -0
  10. data/lib/capybara/cucumber.rb +3 -1
  11. data/lib/capybara/driver/base.rb +27 -6
  12. data/lib/capybara/driver/node.rb +14 -5
  13. data/lib/capybara/dsl.rb +2 -3
  14. data/lib/capybara/helpers.rb +13 -65
  15. data/lib/capybara/minitest/spec.rb +177 -0
  16. data/lib/capybara/minitest.rb +278 -0
  17. data/lib/capybara/node/actions.rb +180 -24
  18. data/lib/capybara/node/base.rb +17 -5
  19. data/lib/capybara/node/document.rb +5 -0
  20. data/lib/capybara/node/document_matchers.rb +15 -14
  21. data/lib/capybara/node/element.rb +55 -7
  22. data/lib/capybara/node/finders.rb +179 -67
  23. data/lib/capybara/node/matchers.rb +301 -105
  24. data/lib/capybara/node/simple.rb +15 -4
  25. data/lib/capybara/queries/ancestor_query.rb +25 -0
  26. data/lib/capybara/queries/base_query.rb +69 -3
  27. data/lib/capybara/queries/current_path_query.rb +17 -8
  28. data/lib/capybara/queries/match_query.rb +19 -0
  29. data/lib/capybara/queries/selector_query.rb +251 -0
  30. data/lib/capybara/queries/sibling_query.rb +25 -0
  31. data/lib/capybara/queries/text_query.rb +67 -16
  32. data/lib/capybara/queries/title_query.rb +4 -2
  33. data/lib/capybara/query.rb +3 -131
  34. data/lib/capybara/rack_test/browser.rb +14 -5
  35. data/lib/capybara/rack_test/css_handlers.rb +1 -0
  36. data/lib/capybara/rack_test/driver.rb +15 -8
  37. data/lib/capybara/rack_test/form.rb +34 -12
  38. data/lib/capybara/rack_test/node.rb +29 -12
  39. data/lib/capybara/rails.rb +3 -3
  40. data/lib/capybara/result.rb +104 -9
  41. data/lib/capybara/rspec/compound.rb +95 -0
  42. data/lib/capybara/rspec/features.rb +17 -6
  43. data/lib/capybara/rspec/matcher_proxies.rb +45 -0
  44. data/lib/capybara/rspec/matchers.rb +199 -80
  45. data/lib/capybara/rspec.rb +4 -2
  46. data/lib/capybara/selector/css.rb +30 -0
  47. data/lib/capybara/selector/filter.rb +20 -0
  48. data/lib/capybara/selector/filter_set.rb +74 -0
  49. data/lib/capybara/selector/filters/base.rb +33 -0
  50. data/lib/capybara/selector/filters/expression_filter.rb +40 -0
  51. data/lib/capybara/selector/filters/node_filter.rb +27 -0
  52. data/lib/capybara/selector/selector.rb +276 -0
  53. data/lib/capybara/selector.rb +452 -157
  54. data/lib/capybara/selenium/driver.rb +282 -81
  55. data/lib/capybara/selenium/node.rb +144 -46
  56. data/lib/capybara/server.rb +59 -16
  57. data/lib/capybara/session/config.rb +114 -0
  58. data/lib/capybara/session/matchers.rb +29 -19
  59. data/lib/capybara/session.rb +378 -143
  60. data/lib/capybara/spec/fixtures/no_extension +1 -0
  61. data/lib/capybara/spec/public/jquery-ui.js +13 -791
  62. data/lib/capybara/spec/public/jquery.js +4 -9045
  63. data/lib/capybara/spec/public/test.js +45 -11
  64. data/lib/capybara/spec/session/accept_alert_spec.rb +30 -7
  65. data/lib/capybara/spec/session/accept_confirm_spec.rb +14 -2
  66. data/lib/capybara/spec/session/accept_prompt_spec.rb +35 -6
  67. data/lib/capybara/spec/session/all_spec.rb +45 -32
  68. data/lib/capybara/spec/session/ancestor_spec.rb +85 -0
  69. data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +110 -0
  70. data/lib/capybara/spec/session/assert_current_path.rb +15 -2
  71. data/lib/capybara/spec/session/assert_selector.rb +29 -28
  72. data/lib/capybara/spec/session/assert_text.rb +59 -20
  73. data/lib/capybara/spec/session/assert_title.rb +25 -11
  74. data/lib/capybara/spec/session/attach_file_spec.rb +42 -4
  75. data/lib/capybara/spec/session/body_spec.rb +1 -0
  76. data/lib/capybara/spec/session/check_spec.rb +90 -14
  77. data/lib/capybara/spec/session/choose_spec.rb +31 -5
  78. data/lib/capybara/spec/session/click_button_spec.rb +20 -9
  79. data/lib/capybara/spec/session/click_link_or_button_spec.rb +15 -9
  80. data/lib/capybara/spec/session/click_link_spec.rb +39 -15
  81. data/lib/capybara/spec/session/current_scope_spec.rb +2 -1
  82. data/lib/capybara/spec/session/current_url_spec.rb +12 -3
  83. data/lib/capybara/spec/session/dismiss_confirm_spec.rb +6 -5
  84. data/lib/capybara/spec/session/dismiss_prompt_spec.rb +4 -3
  85. data/lib/capybara/spec/session/element/assert_match_selector.rb +36 -0
  86. data/lib/capybara/spec/session/element/match_css_spec.rb +23 -0
  87. data/lib/capybara/spec/session/element/match_xpath_spec.rb +23 -0
  88. data/lib/capybara/spec/session/element/matches_selector_spec.rb +106 -0
  89. data/lib/capybara/spec/session/evaluate_async_script_spec.rb +22 -0
  90. data/lib/capybara/spec/session/evaluate_script_spec.rb +23 -1
  91. data/lib/capybara/spec/session/execute_script_spec.rb +22 -3
  92. data/lib/capybara/spec/session/fill_in_spec.rb +50 -32
  93. data/lib/capybara/spec/session/find_button_spec.rb +43 -2
  94. data/lib/capybara/spec/session/find_by_id_spec.rb +3 -2
  95. data/lib/capybara/spec/session/find_field_spec.rb +42 -6
  96. data/lib/capybara/spec/session/find_link_spec.rb +22 -3
  97. data/lib/capybara/spec/session/find_spec.rb +103 -57
  98. data/lib/capybara/spec/session/first_spec.rb +34 -18
  99. data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +103 -0
  100. data/lib/capybara/spec/session/{within_frame_spec.rb → frame/within_frame_spec.rb} +44 -2
  101. data/lib/capybara/spec/session/go_back_spec.rb +2 -1
  102. data/lib/capybara/spec/session/go_forward_spec.rb +2 -1
  103. data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
  104. data/lib/capybara/spec/session/has_button_spec.rb +17 -8
  105. data/lib/capybara/spec/session/has_css_spec.rb +85 -73
  106. data/lib/capybara/spec/session/has_current_path_spec.rb +91 -7
  107. data/lib/capybara/spec/session/has_field_spec.rb +93 -58
  108. data/lib/capybara/spec/session/has_link_spec.rb +9 -8
  109. data/lib/capybara/spec/session/has_none_selectors_spec.rb +76 -0
  110. data/lib/capybara/spec/session/has_select_spec.rb +159 -59
  111. data/lib/capybara/spec/session/has_selector_spec.rb +64 -28
  112. data/lib/capybara/spec/session/has_table_spec.rb +1 -0
  113. data/lib/capybara/spec/session/has_text_spec.rb +27 -12
  114. data/lib/capybara/spec/session/has_title_spec.rb +22 -4
  115. data/lib/capybara/spec/session/has_xpath_spec.rb +32 -29
  116. data/lib/capybara/spec/session/headers.rb +2 -1
  117. data/lib/capybara/spec/session/html_spec.rb +4 -3
  118. data/lib/capybara/spec/session/node_spec.rb +198 -38
  119. data/lib/capybara/spec/session/refresh_spec.rb +28 -0
  120. data/lib/capybara/spec/session/reset_session_spec.rb +46 -5
  121. data/lib/capybara/spec/session/response_code.rb +2 -1
  122. data/lib/capybara/spec/session/save_and_open_page_spec.rb +1 -0
  123. data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +6 -5
  124. data/lib/capybara/spec/session/save_page_spec.rb +34 -2
  125. data/lib/capybara/spec/session/save_screenshot_spec.rb +31 -1
  126. data/lib/capybara/spec/session/screenshot_spec.rb +4 -2
  127. data/lib/capybara/spec/session/select_spec.rb +34 -32
  128. data/lib/capybara/spec/session/selectors_spec.rb +65 -0
  129. data/lib/capybara/spec/session/sibling_spec.rb +52 -0
  130. data/lib/capybara/spec/session/text_spec.rb +4 -4
  131. data/lib/capybara/spec/session/title_spec.rb +2 -1
  132. data/lib/capybara/spec/session/uncheck_spec.rb +42 -2
  133. data/lib/capybara/spec/session/unselect_spec.rb +17 -16
  134. data/lib/capybara/spec/session/visit_spec.rb +77 -2
  135. data/lib/capybara/spec/session/window/become_closed_spec.rb +12 -11
  136. data/lib/capybara/spec/session/window/current_window_spec.rb +1 -0
  137. data/lib/capybara/spec/session/window/open_new_window_spec.rb +1 -0
  138. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +16 -11
  139. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +7 -4
  140. data/lib/capybara/spec/session/window/window_spec.rb +36 -29
  141. data/lib/capybara/spec/session/window/windows_spec.rb +1 -0
  142. data/lib/capybara/spec/session/window/within_window_spec.rb +31 -7
  143. data/lib/capybara/spec/session/within_spec.rb +14 -6
  144. data/lib/capybara/spec/spec_helper.rb +37 -4
  145. data/lib/capybara/spec/test_app.rb +15 -3
  146. data/lib/capybara/spec/views/buttons.erb +1 -0
  147. data/lib/capybara/spec/views/fieldsets.erb +2 -1
  148. data/lib/capybara/spec/views/form.erb +169 -9
  149. data/lib/capybara/spec/views/frame_child.erb +10 -2
  150. data/lib/capybara/spec/views/frame_one.erb +2 -1
  151. data/lib/capybara/spec/views/frame_parent.erb +3 -2
  152. data/lib/capybara/spec/views/frame_two.erb +2 -1
  153. data/lib/capybara/spec/views/header_links.erb +1 -0
  154. data/lib/capybara/spec/views/host_links.erb +1 -0
  155. data/lib/capybara/spec/views/initial_alert.erb +10 -0
  156. data/lib/capybara/spec/views/path.erb +1 -0
  157. data/lib/capybara/spec/views/popup_one.erb +1 -0
  158. data/lib/capybara/spec/views/popup_two.erb +1 -0
  159. data/lib/capybara/spec/views/postback.erb +2 -1
  160. data/lib/capybara/spec/views/tables.erb +1 -0
  161. data/lib/capybara/spec/views/with_base_tag.erb +1 -0
  162. data/lib/capybara/spec/views/with_count.erb +2 -1
  163. data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
  164. data/lib/capybara/spec/views/with_hover.erb +7 -1
  165. data/lib/capybara/spec/views/with_html.erb +40 -2
  166. data/lib/capybara/spec/views/with_html_entities.erb +1 -0
  167. data/lib/capybara/spec/views/with_js.erb +32 -1
  168. data/lib/capybara/spec/views/with_scope.erb +1 -0
  169. data/lib/capybara/spec/views/with_simple_html.erb +2 -1
  170. data/lib/capybara/spec/views/with_slow_unload.erb +17 -0
  171. data/lib/capybara/spec/views/with_title.erb +2 -1
  172. data/lib/capybara/spec/views/with_unload_alert.erb +14 -0
  173. data/lib/capybara/spec/views/with_windows.erb +7 -0
  174. data/lib/capybara/spec/views/within_frames.erb +3 -2
  175. data/lib/capybara/version.rb +2 -1
  176. data/lib/capybara/window.rb +20 -3
  177. data/lib/capybara.rb +189 -93
  178. data/spec/basic_node_spec.rb +7 -6
  179. data/spec/capybara_spec.rb +90 -4
  180. data/spec/dsl_spec.rb +3 -1
  181. data/spec/filter_set_spec.rb +28 -0
  182. data/spec/fixtures/capybara.csv +1 -0
  183. data/spec/fixtures/selenium_driver_rspec_failure.rb +5 -1
  184. data/spec/fixtures/selenium_driver_rspec_success.rb +5 -1
  185. data/spec/minitest_spec.rb +130 -0
  186. data/spec/minitest_spec_spec.rb +135 -0
  187. data/spec/per_session_config_spec.rb +67 -0
  188. data/spec/rack_test_spec.rb +50 -7
  189. data/spec/result_spec.rb +76 -0
  190. data/spec/rspec/features_spec.rb +21 -8
  191. data/spec/rspec/scenarios_spec.rb +21 -0
  192. data/spec/rspec/{matchers_spec.rb → shared_spec_matchers.rb} +160 -54
  193. data/spec/rspec/views_spec.rb +5 -0
  194. data/spec/rspec_matchers_spec.rb +46 -0
  195. data/spec/rspec_spec.rb +79 -1
  196. data/spec/selector_spec.rb +199 -0
  197. data/spec/selenium_spec_chrome.rb +54 -9
  198. data/spec/selenium_spec_firefox.rb +68 -0
  199. data/spec/selenium_spec_marionette.rb +127 -0
  200. data/spec/server_spec.rb +102 -14
  201. data/spec/session_spec.rb +54 -0
  202. data/spec/shared_selenium_session.rb +215 -0
  203. data/spec/spec_helper.rb +7 -0
  204. metadata +140 -15
  205. data/spec/selenium_spec.rb +0 -128
data/spec/rspec_spec.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  RSpec.describe 'capybara/rspec', :type => :feature do
@@ -6,6 +7,10 @@ RSpec.describe 'capybara/rspec', :type => :feature do
6
7
  expect(page.body).to include('Another World')
7
8
  end
8
9
 
10
+ it "should include RSpec matcher proxies" do
11
+ expect(self.class.ancestors).to include Capybara::RSpecMatcherProxies
12
+ end
13
+
9
14
  context "resetting session" do
10
15
  it "sets a cookie in one example..." do
11
16
  visit('/set_cookie')
@@ -28,13 +33,86 @@ RSpec.describe 'capybara/rspec', :type => :feature do
28
33
  end
29
34
  end
30
35
 
31
- it "switches to the javascript driver when giving it as metadata", :js => true do
36
+ it "switches to the javascript driver when giving it as metadata", js: true do
32
37
  expect(Capybara.current_driver).to eq(Capybara.javascript_driver)
33
38
  end
34
39
 
35
40
  it "switches to the given driver when giving it as metadata", :driver => :culerity do
36
41
  expect(Capybara.current_driver).to eq(:culerity)
37
42
  end
43
+
44
+ context "#all" do
45
+ it "allows access to the Capybara finder" do
46
+ visit('/with_html')
47
+ expect(all(:css, 'h2.head').size).to eq(5)
48
+ end
49
+
50
+ it "allows access to the RSpec matcher" do
51
+ skip "RSpec < 3 doesn't have an `all` matcher" if rspec2?
52
+
53
+ visit('/with_html')
54
+ expect(["test1", "test2"]).to all(be_a(String))
55
+ end
56
+ end
57
+
58
+ context "#within" do
59
+ it "allows access to the Capybara scoper" do
60
+ visit('/with_html')
61
+ expect do
62
+ within(:css, "#does_not_exist") { click_link "Go to simple" }
63
+ end.to raise_error(Capybara::ElementNotFound)
64
+ end
65
+
66
+ it "allows access to the RSpec matcher" do
67
+ skip "RSpec version doesn't have a 'within' matcher" unless ::RSpec::Matchers.instance_methods.include?(:within)
68
+ visit('/with_html')
69
+ # This reads terribly, but must call #within
70
+ expect(find(:css, 'span.number').text.to_i).to within(1).of(41)
71
+ end
72
+ end
73
+ end
74
+
75
+ RSpec.describe 'capybara/rspec', :type => :other do
76
+ context "when RSpec::Matchers is included after Capybara::DSL" do
77
+ before do
78
+ class DSL_MatchersTest
79
+ include Capybara::DSL
80
+ include RSpec::Matchers
81
+ end
82
+
83
+ @test_class_instance = DSL_MatchersTest.new
84
+ end
85
+
86
+ context "#all" do
87
+ it "allows access to the Capybara finder" do
88
+ @test_class_instance.visit('/with_html')
89
+ expect(@test_class_instance.all(:css, 'h2.head').size).to eq(5)
90
+ end
91
+
92
+ it "allows access to the RSpec matcher" do
93
+ skip "RSpec < 3 doesn't have an `all` matcher" if rspec2?
94
+
95
+ @test_class_instance.visit('/with_html')
96
+ expect(["test1", "test2"]).to @test_class_instance.all(be_a(String))
97
+ end
98
+ end
99
+
100
+ context "#within" do
101
+ it "allows access to the Capybara scoper" do
102
+ @test_class_instance.visit('/with_html')
103
+ expect do
104
+ @test_class_instance.within(:css, "#does_not_exist") { @test_class_instance.click_link "Go to simple" }
105
+ end.to raise_error(Capybara::ElementNotFound)
106
+ end
107
+
108
+ it "allows access to the RSpec matcher" do
109
+ skip "RSpec version doesn't have a 'within' matcher" unless ::RSpec::Matchers.instance_methods.include?(:within)
110
+ @test_class_instance.visit('/with_html')
111
+ # This reads terribly, but must call #within
112
+ expect(@test_class_instance.find(:css, 'span.number').text.to_i).to @test_class_instance.within(1).of(41)
113
+ end
114
+ end
115
+ end
38
116
  end
39
117
 
40
118
  RSpec.describe 'capybara/rspec', :type => :other do
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ RSpec.describe Capybara do
5
+ describe 'Selectors' do
6
+ let :string do
7
+ Capybara.string <<-STRING
8
+ <html>
9
+ <head>
10
+ <title>selectors</title>
11
+ </head>
12
+ <body>
13
+ <div class="a" id="page">
14
+ <div class="b" id="content">
15
+ <h1 class="a">Totally awesome</h1>
16
+ <p>Yes it is</p>
17
+ </div>
18
+ <p class="b">Some Content</p>
19
+ <p class="b"></p>
20
+ </div>
21
+ <div id="#special">
22
+ </div>
23
+ <input id="2checkbox" class="2checkbox" type="checkbox"/>
24
+ <input type="radio"/>
25
+ <label for="my_text_input">My Text Input</label>
26
+ <input type="text" name="form[my_text_input]" placeholder="my text" id="my_text_input"/>
27
+ <input type="file" id="file" class=".special file"/>
28
+ <input type="hidden" id="hidden_field" value="this is hidden"/>
29
+ <a href="#">link</a>
30
+ <fieldset></fieldset>
31
+ <select id="select">
32
+ <option value="a">A</option>
33
+ <option value="b" disabled>B</option>
34
+ <option value="c" selected>C</option>
35
+ </select>
36
+ <table>
37
+ <tr><td></td></tr>
38
+ </table
39
+ </body>
40
+ </html>
41
+ STRING
42
+ end
43
+
44
+ before do
45
+ Capybara.add_selector :custom_selector do
46
+ css { |css_class| "div.#{css_class}" }
47
+ filter(:not_empty, boolean: true, default: true, skip_if: :all) { |node, value| value ^ (node.text == '') }
48
+ end
49
+
50
+ Capybara.add_selector :custom_css_selector do
51
+ css { |selector| selector }
52
+ end
53
+ end
54
+
55
+ describe "adding a selector" do
56
+ it "can set default visiblity" do
57
+ Capybara.add_selector :hidden_field do
58
+ visible :hidden
59
+ css { |sel| 'input[type="hidden"]' }
60
+ end
61
+
62
+ expect(string).to have_no_css('input[type="hidden"]')
63
+ expect(string).to have_selector(:hidden_field)
64
+ end
65
+ end
66
+
67
+ describe "modify_selector" do
68
+ it "allows modifying a selector" do
69
+ el = string.find(:custom_selector, 'a')
70
+ expect(el.tag_name).to eq 'div'
71
+ Capybara.modify_selector :custom_selector do
72
+ css { |css_class| "h1.#{css_class}" }
73
+ end
74
+ el = string.find(:custom_selector, 'a')
75
+ expect(el.tag_name).to eq 'h1'
76
+ end
77
+
78
+ it "doesn't change existing filters" do
79
+ Capybara.modify_selector :custom_selector do
80
+ css { |css_class| "p.#{css_class}"}
81
+ end
82
+ expect(string).to have_selector(:custom_selector, 'b', count: 1)
83
+ expect(string).to have_selector(:custom_selector, 'b', not_empty: false, count: 1)
84
+ expect(string).to have_selector(:custom_selector, 'b', not_empty: :all, count: 2)
85
+ end
86
+ end
87
+
88
+ describe "builtin selectors" do
89
+ context "when locator is nil" do
90
+ it "devolves to just finding element types" do
91
+ selectors = {
92
+ field: ".//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]",
93
+ fieldset: ".//fieldset",
94
+ link: ".//a[./@href]",
95
+ link_or_button: ".//a[./@href] | .//input[./@type = 'submit' or ./@type = 'reset' or ./@type = 'image' or ./@type = 'button'] | .//button" ,
96
+ fillable_field: ".//*[self::input | self::textarea][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'radio' or ./@type = 'checkbox' or ./@type = 'hidden' or ./@type = 'file')]",
97
+ radio_button: ".//input[./@type = 'radio']",
98
+ checkbox: ".//input[./@type = 'checkbox']",
99
+ select: ".//select",
100
+ option: ".//option",
101
+ file_field: ".//input[./@type = 'file']",
102
+ table: ".//table"
103
+ }
104
+ selectors.each do |selector, xpath|
105
+ results = string.all(selector,nil).to_a.map(&:native)
106
+ expect(results.size).to be > 0
107
+ expect(results).to eq string.all(:xpath, xpath).to_a.map(&:native)
108
+ end
109
+ end
110
+ end
111
+
112
+ context "with :id option" do
113
+ it "works with compound css selectors" do
114
+ expect(string.all(:custom_css_selector, "div, h1", id: 'page').size).to eq 1
115
+ expect(string.all(:custom_css_selector, "h1, div", id: 'page').size).to eq 1
116
+ end
117
+
118
+ it "works with 'special' characters" do
119
+ skip "We support old Nokogiris but they have their limits" if Gem::Version.new(Nokogiri::VERSION) < Gem::Version.new('1.6.8')
120
+ expect(string.find(:custom_css_selector, "div", id: "#special")[:id]).to eq '#special'
121
+ expect(string.find(:custom_css_selector, "input", id: "2checkbox")[:id]).to eq '2checkbox'
122
+ end
123
+ end
124
+
125
+ context "with :class option" do
126
+ it "works with compound css selectors" do
127
+ expect(string.all(:custom_css_selector, "div, h1", class: 'a').size).to eq 2
128
+ expect(string.all(:custom_css_selector, "h1, div", class: 'a').size).to eq 2
129
+ end
130
+
131
+ it "works with 'special' characters" do
132
+ skip "We support old Nokogiris but they have their limits" if Gem::Version.new(Nokogiri::VERSION) < Gem::Version.new('1.6.8')
133
+ expect(string.find(:custom_css_selector, "input", class: ".special")[:id]).to eq 'file'
134
+ expect(string.find(:custom_css_selector, "input", class: "2checkbox")[:id]).to eq '2checkbox'
135
+ end
136
+ end
137
+
138
+ # :css, :xpath, :id, :field, :fieldset, :link, :button, :link_or_button, :fillable_field, :radio_button, :checkbox, :select,
139
+ # :option, :file_field, :label, :table, :frame
140
+
141
+ describe ":css selector" do
142
+ it "finds by CSS locator" do
143
+ expect(string.find(:css, "input#my_text_input")[:name]).to eq 'form[my_text_input]'
144
+ end
145
+ end
146
+
147
+ describe ":xpath selector" do
148
+ it "finds by XPath locator" do
149
+ expect(string.find(:xpath, './/input[@id="my_text_input"]')[:name]).to eq 'form[my_text_input]'
150
+ end
151
+ end
152
+
153
+ describe ":id selector" do
154
+ it "finds by locator" do
155
+ expect(string.find(:id, "my_text_input")[:name]).to eq 'form[my_text_input]'
156
+ end
157
+ end
158
+
159
+ describe ":field selector" do
160
+ it "finds by locator" do
161
+ expect(string.find(:field, 'My Text Input')[:id]).to eq 'my_text_input'
162
+ expect(string.find(:field, 'my_text_input')[:id]).to eq 'my_text_input'
163
+ expect(string.find(:field, 'form[my_text_input]')[:id]).to eq 'my_text_input'
164
+ end
165
+
166
+ it "finds by id" do
167
+ expect(string.find(:field, id: 'my_text_input')[:name]).to eq 'form[my_text_input]'
168
+ end
169
+
170
+ it "finds by name" do
171
+ expect(string.find(:field, name: 'form[my_text_input]')[:id]).to eq 'my_text_input'
172
+ end
173
+
174
+ it "finds by placeholder" do
175
+ expect(string.find(:field, placeholder: 'my text')[:id]).to eq 'my_text_input'
176
+ end
177
+
178
+ it "finds by type" do
179
+ expect(string.find(:field, type: 'file')[:id]).to eq 'file'
180
+ expect(string.find(:field, type: 'select')[:id]).to eq 'select'
181
+ end
182
+ end
183
+
184
+ describe ":option selector" do
185
+ it "finds disabled options" do
186
+ expect(string.find(:option, disabled: true).value).to eq 'b'
187
+ end
188
+
189
+ it "finds selected options" do
190
+ expect(string.find(:option, selected: true).value).to eq 'c'
191
+ end
192
+
193
+ it "finds not selected and not disabled options" do
194
+ expect(string.find(:option, disabled: false, selected: false).value).to eq 'a'
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
@@ -1,17 +1,62 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
  require 'selenium-webdriver'
4
+ require 'shared_selenium_session'
3
5
 
4
- Capybara.register_driver :selenium_chrome do |app|
5
- args = ENV['TRAVIS'] ? ['no-sandbox' ] : []
6
- Capybara::Selenium::Driver.new(app, :browser => :chrome, :args => args)
6
+ CHROME_DRIVER = if ENV['HEADLESS'] then :selenium_chrome_headless else :selenium_chrome end
7
+
8
+ # if ENV['HEADLESS'] && ENV['TRAVIS']
9
+ # Selenium::WebDriver::Chrome.path='/usr/bin/google-chrome-beta'
10
+ # end
11
+
12
+ Capybara.register_driver :selenium_chrome_clear_storage do |app|
13
+ chrome_options = {
14
+ browser: :chrome,
15
+ options: ::Selenium::WebDriver::Chrome::Options.new()
16
+ }
17
+ chrome_options[:options].args << 'headless' if ENV['HEADLESS']
18
+ Capybara::Selenium::Driver.new(app, chrome_options.merge(clear_local_storage: true, clear_session_storage: true))
7
19
  end
8
20
 
9
21
  module TestSessions
10
- Chrome = Capybara::Session.new(:selenium_chrome, TestApp)
22
+ Chrome = Capybara::Session.new(CHROME_DRIVER, TestApp)
11
23
  end
12
24
 
13
- Capybara::SpecHelper.run_specs TestSessions::Chrome, "selenium_chrome", :capybara_skip => [
14
- :response_headers,
15
- :status_code,
16
- :trigger
17
- ] unless ENV['TRAVIS'] && (RUBY_PLATFORM == 'java')
25
+ skipped_tests = [:response_headers, :status_code, :trigger]
26
+ # skip window tests when headless for now - closing a window not supported by chromedriver/chrome
27
+ skipped_tests << :windows if ENV['TRAVIS'] && (ENV['SKIP_WINDOW'] || ENV['HEADLESS'])
28
+
29
+ Capybara::SpecHelper.run_specs TestSessions::Chrome, CHROME_DRIVER.to_s, capybara_skip: skipped_tests
30
+
31
+ RSpec.describe "Capybara::Session with chrome" do
32
+ include Capybara::SpecHelper
33
+ include_examples "Capybara::Session", TestSessions::Chrome, CHROME_DRIVER
34
+
35
+ context "storage" do
36
+ describe "#reset!" do
37
+ it "does not clear either storage by default" do
38
+ @session = TestSessions::Chrome
39
+ @session.visit('/with_js')
40
+ @session.find(:css, '#set-storage').click
41
+ @session.reset!
42
+ @session.visit('/with_js')
43
+ # expect(@session.driver.browser.local_storage.keys).not_to be_empty
44
+ # expect(@session.driver.browser.session_storage.keys).not_to be_empty
45
+ expect(@session.evaluate_script('Object.keys(localStorage)')).not_to be_empty
46
+ expect(@session.evaluate_script('Object.keys(sessionStorage)')).not_to be_empty
47
+ end
48
+
49
+ it "clears storage when set" do
50
+ @session = Capybara::Session.new(:selenium_chrome_clear_storage, TestApp)
51
+ @session.visit('/with_js')
52
+ @session.find(:css, '#set-storage').click
53
+ @session.reset!
54
+ @session.visit('/with_js')
55
+ # expect(@session.driver.browser.local_storage.keys).to be_empty
56
+ # expect(@session.driver.browser.session_storage.keys).to be_empty
57
+ expect(@session.evaluate_script('Object.keys(localStorage)')).to be_empty
58
+ expect(@session.evaluate_script('Object.keys(sessionStorage)')).to be_empty
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+ require "selenium-webdriver"
4
+ require 'shared_selenium_session'
5
+ require 'rspec/shared_spec_matchers'
6
+
7
+ Capybara.register_driver :selenium_firefox do |app|
8
+ Capybara::Selenium::Driver.new(
9
+ app,
10
+ browser: :firefox,
11
+ desired_capabilities: Selenium::WebDriver::Remote::Capabilities.firefox(marionette: false)
12
+ )
13
+ end
14
+
15
+ Capybara.register_driver :selenium_firefox_cant_clear_storage do |app|
16
+ Capybara::Selenium::Driver.new(
17
+ app,
18
+ browser: :firefox,
19
+ desired_capabilities: Selenium::WebDriver::Remote::Capabilities.firefox(marionette: false),
20
+ clear_local_storage: true,
21
+ clear_session_storage: true
22
+ )
23
+ end
24
+
25
+ module TestSessions
26
+ Selenium = Capybara::Session.new(:selenium_firefox, TestApp)
27
+ end
28
+
29
+ skipped_tests = [
30
+ :response_headers,
31
+ :status_code,
32
+ :trigger
33
+ ]
34
+ skipped_tests << :windows if ENV['TRAVIS'] && ENV['SKIP_WINDOW']
35
+
36
+ Capybara::SpecHelper.run_specs TestSessions::Selenium, "selenium", capybara_skip: skipped_tests
37
+
38
+ RSpec.describe "Capybara::Session with legacy firefox" do
39
+ include Capybara::SpecHelper
40
+ include_examples "Capybara::Session", TestSessions::Selenium, :selenium_firefox
41
+ include_examples Capybara::RSpecMatchers, TestSessions::Selenium, :selenium_firefox
42
+
43
+ context "storage" do
44
+ it "warns storage clearing isn't available" do
45
+ @session = Capybara::Session.new(:selenium_firefox_cant_clear_storage, TestApp)
46
+ expect_any_instance_of(Kernel).to receive(:warn).with('sessionStorage clear requested but is not available for this driver')
47
+ expect_any_instance_of(Kernel).to receive(:warn).with('localStorage clear requested but is not available for this driver')
48
+ @session.visit('/')
49
+ @session.reset!
50
+ end
51
+ end
52
+ end
53
+
54
+ RSpec.describe Capybara::Selenium::Driver do
55
+ before do
56
+ @driver = Capybara::Selenium::Driver.new(TestApp, browser: :firefox, desired_capabilities: Selenium::WebDriver::Remote::Capabilities.firefox(marionette: false))
57
+ end
58
+
59
+ describe '#quit' do
60
+ it "should reset browser when quit" do
61
+ expect(@driver.browser).to be
62
+ @driver.quit
63
+ #access instance variable directly so we don't create a new browser instance
64
+ expect(@driver.instance_variable_get(:@browser)).to be_nil
65
+ end
66
+ end
67
+ end
68
+
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+ require "selenium-webdriver"
4
+ require 'shared_selenium_session'
5
+ require 'rspec/shared_spec_matchers'
6
+
7
+ browser_options = ::Selenium::WebDriver::Firefox::Options.new()
8
+ browser_options.args << '--headless' if ENV['HEADLESS']
9
+ browser_options.add_preference 'dom.file.createInChild', true
10
+ # browser_options.add_option("log", {"level": "trace"})
11
+
12
+ Capybara.register_driver :selenium_marionette do |app|
13
+ # ::Selenium::WebDriver.logger.level = "debug"
14
+ Capybara::Selenium::Driver.new(
15
+ app,
16
+ browser: :firefox,
17
+ desired_capabilities: {marionette: true, 'moz:webdriverClick': true},
18
+ options: browser_options
19
+ # Get a trace level log from geckodriver
20
+ # :driver_opts => { args: ['-vv'] }
21
+ )
22
+ end
23
+
24
+ Capybara.register_driver :selenium_marionette_clear_storage do |app|
25
+ Capybara::Selenium::Driver.new(
26
+ app,
27
+ browser: :firefox,
28
+ desired_capabilities: {marionette: true},
29
+ clear_local_storage: true,
30
+ clear_session_storage: true,
31
+ options: browser_options
32
+ )
33
+ end
34
+
35
+
36
+
37
+ module TestSessions
38
+ SeleniumMarionette = Capybara::Session.new(:selenium_marionette, TestApp)
39
+ end
40
+
41
+ skipped_tests = [
42
+ :response_headers,
43
+ :status_code,
44
+ :trigger
45
+ ]
46
+ skipped_tests << :windows if ENV['TRAVIS'] && ENV['SKIP_WINDOW']
47
+
48
+ Capybara::SpecHelper.run_specs TestSessions::SeleniumMarionette, "selenium", capybara_skip: skipped_tests
49
+
50
+ RSpec.describe "Capybara::Session with firefox" do
51
+ include Capybara::SpecHelper
52
+ include_examples "Capybara::Session", TestSessions::SeleniumMarionette, :selenium_marionette
53
+ include_examples Capybara::RSpecMatchers, TestSessions::SeleniumMarionette, :selenium_marionette
54
+ end
55
+
56
+ RSpec.describe Capybara::Selenium::Driver do
57
+ before do
58
+ @driver = Capybara::Selenium::Driver.new(TestApp, browser: :firefox, options: browser_options)
59
+ end
60
+
61
+ describe '#quit' do
62
+ it "should reset browser when quit" do
63
+ expect(@driver.browser).to be
64
+ @driver.quit
65
+ #access instance variable directly so we don't create a new browser instance
66
+ expect(@driver.instance_variable_get(:@browser)).to be_nil
67
+ end
68
+
69
+ context "with errors" do
70
+ before do
71
+ @original_browser = @driver.browser
72
+ end
73
+ after do
74
+ # Ensure browser is actually quit so we don't leave hanging processe
75
+ RSpec::Mocks.space.proxy_for(@original_browser).reset
76
+ @original_browser.quit
77
+ end
78
+
79
+ it "warns UnknownError returned during quit because the browser is probably already gone" do
80
+ expect_any_instance_of(Capybara::Selenium::Driver).to receive(:warn).with(/random message/)
81
+ allow(@driver.browser).to(
82
+ receive(:quit)
83
+ .and_raise(Selenium::WebDriver::Error::UnknownError, "random message")
84
+ )
85
+
86
+ expect { @driver.quit }.not_to raise_error
87
+ expect(@driver.instance_variable_get(:@browser)).to be_nil
88
+ end
89
+
90
+ it "ignores silenced UnknownError returned during quit because the browser is almost definitely already gone" do
91
+ expect_any_instance_of(Capybara::Selenium::Driver).not_to receive(:warn)
92
+ allow(@driver.browser).to(
93
+ receive(:quit)
94
+ .and_raise(Selenium::WebDriver::Error::UnknownError, "Error communicating with the remote browser")
95
+ )
96
+
97
+ expect { @driver.quit }.not_to raise_error
98
+ expect(@driver.instance_variable_get(:@browser)).to be_nil
99
+ end
100
+ end
101
+ end
102
+
103
+ context "storage" do
104
+ describe "#reset!" do
105
+ it "does not clear either storage by default" do
106
+ @session = TestSessions::SeleniumMarionette
107
+ @session.visit('/with_js')
108
+ @session.find(:css, '#set-storage').click
109
+ @session.reset!
110
+ @session.visit('/with_js')
111
+ expect(@session.driver.browser.local_storage.keys).not_to be_empty
112
+ expect(@session.driver.browser.session_storage.keys).not_to be_empty
113
+ end
114
+
115
+ it "clears storage when set" do
116
+ @session = Capybara::Session.new(:selenium_marionette_clear_storage, TestApp)
117
+ @session.visit('/with_js')
118
+ @session.find(:css, '#set-storage').click
119
+ @session.reset!
120
+ @session.visit('/with_js')
121
+ expect(@session.driver.browser.local_storage.keys).to be_empty
122
+ expect(@session.driver.browser.session_storage.keys).to be_empty
123
+ end
124
+ end
125
+ end
126
+ end
127
+