capybara 2.5.0 → 2.18.0

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