capybara 2.13.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.
- checksums.yaml +5 -5
- data/History.md +218 -18
- data/README.md +54 -23
- data/lib/capybara/config.rb +132 -0
- data/lib/capybara/cucumber.rb +1 -0
- data/lib/capybara/driver/base.rb +14 -0
- data/lib/capybara/dsl.rb +1 -3
- data/lib/capybara/helpers.rb +3 -3
- data/lib/capybara/minitest/spec.rb +14 -37
- data/lib/capybara/minitest.rb +95 -114
- data/lib/capybara/node/actions.rb +10 -10
- data/lib/capybara/node/base.rb +7 -2
- data/lib/capybara/node/element.rb +9 -3
- data/lib/capybara/node/finders.rb +92 -18
- data/lib/capybara/node/matchers.rb +21 -9
- data/lib/capybara/node/simple.rb +5 -0
- data/lib/capybara/queries/ancestor_query.rb +25 -0
- data/lib/capybara/queries/base_query.rb +12 -3
- data/lib/capybara/queries/current_path_query.rb +13 -9
- data/lib/capybara/queries/selector_query.rb +62 -23
- data/lib/capybara/queries/sibling_query.rb +25 -0
- data/lib/capybara/queries/text_query.rb +10 -5
- data/lib/capybara/queries/title_query.rb +1 -0
- data/lib/capybara/rack_test/browser.rb +13 -5
- data/lib/capybara/rack_test/driver.rb +6 -1
- data/lib/capybara/rack_test/form.rb +4 -3
- data/lib/capybara/rack_test/node.rb +1 -1
- data/lib/capybara/rspec/compound.rb +95 -0
- data/lib/capybara/rspec/matcher_proxies.rb +45 -0
- data/lib/capybara/rspec/matchers.rb +108 -7
- data/lib/capybara/rspec.rb +3 -1
- data/lib/capybara/selector/filter.rb +13 -41
- data/lib/capybara/selector/filter_set.rb +30 -4
- data/lib/capybara/selector/filters/base.rb +33 -0
- data/lib/capybara/selector/filters/expression_filter.rb +40 -0
- data/lib/capybara/selector/filters/node_filter.rb +27 -0
- data/lib/capybara/selector/selector.rb +36 -15
- data/lib/capybara/selector.rb +63 -42
- data/lib/capybara/selenium/driver.rb +177 -33
- data/lib/capybara/selenium/node.rb +106 -55
- data/lib/capybara/server.rb +6 -5
- data/lib/capybara/session/config.rb +114 -0
- data/lib/capybara/session/matchers.rb +15 -4
- data/lib/capybara/session.rb +178 -65
- data/lib/capybara/spec/fixtures/no_extension +1 -0
- data/lib/capybara/spec/public/test.js +18 -3
- data/lib/capybara/spec/session/accept_alert_spec.rb +9 -1
- data/lib/capybara/spec/session/accept_prompt_spec.rb +29 -1
- data/lib/capybara/spec/session/all_spec.rb +13 -1
- data/lib/capybara/spec/session/ancestor_spec.rb +85 -0
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +24 -8
- data/lib/capybara/spec/session/assert_selector.rb +1 -1
- data/lib/capybara/spec/session/assert_text.rb +8 -0
- data/lib/capybara/spec/session/assert_title.rb +22 -9
- data/lib/capybara/spec/session/attach_file_spec.rb +8 -1
- data/lib/capybara/spec/session/check_spec.rb +4 -4
- data/lib/capybara/spec/session/choose_spec.rb +2 -2
- data/lib/capybara/spec/session/click_button_spec.rb +1 -1
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +3 -3
- data/lib/capybara/spec/session/click_link_spec.rb +1 -1
- data/lib/capybara/spec/session/current_url_spec.rb +3 -3
- data/lib/capybara/spec/session/dismiss_confirm_spec.rb +3 -3
- data/lib/capybara/spec/session/dismiss_prompt_spec.rb +1 -1
- data/lib/capybara/spec/session/evaluate_async_script_spec.rb +22 -0
- data/lib/capybara/spec/session/evaluate_script_spec.rb +1 -1
- data/lib/capybara/spec/session/fill_in_spec.rb +8 -2
- data/lib/capybara/spec/session/find_field_spec.rb +1 -0
- data/lib/capybara/spec/session/find_spec.rb +8 -6
- data/lib/capybara/spec/session/first_spec.rb +10 -5
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +69 -0
- data/lib/capybara/spec/session/has_css_spec.rb +11 -0
- data/lib/capybara/spec/session/has_current_path_spec.rb +52 -7
- data/lib/capybara/spec/session/has_link_spec.rb +4 -4
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +76 -0
- data/lib/capybara/spec/session/has_select_spec.rb +64 -6
- data/lib/capybara/spec/session/has_selector_spec.rb +1 -3
- data/lib/capybara/spec/session/has_text_spec.rb +5 -3
- data/lib/capybara/spec/session/has_title_spec.rb +4 -2
- data/lib/capybara/spec/session/has_xpath_spec.rb +5 -3
- data/lib/capybara/spec/session/node_spec.rb +50 -26
- data/lib/capybara/spec/session/refresh_spec.rb +28 -0
- data/lib/capybara/spec/session/reset_session_spec.rb +3 -3
- data/lib/capybara/spec/session/select_spec.rb +3 -2
- data/lib/capybara/spec/session/sibling_spec.rb +52 -0
- data/lib/capybara/spec/session/uncheck_spec.rb +2 -2
- data/lib/capybara/spec/session/unselect_spec.rb +2 -2
- data/lib/capybara/spec/session/visit_spec.rb +56 -1
- data/lib/capybara/spec/session/window/become_closed_spec.rb +11 -11
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +11 -9
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +4 -4
- data/lib/capybara/spec/session/window/within_window_spec.rb +27 -2
- data/lib/capybara/spec/spec_helper.rb +28 -4
- data/lib/capybara/spec/test_app.rb +3 -1
- data/lib/capybara/spec/views/form.erb +27 -1
- data/lib/capybara/spec/views/initial_alert.erb +10 -0
- data/lib/capybara/spec/views/with_fixed_header_footer.erb +17 -0
- data/lib/capybara/spec/views/with_hover.erb +5 -0
- data/lib/capybara/spec/views/with_html.erb +33 -2
- data/lib/capybara/spec/views/with_js.erb +12 -0
- data/lib/capybara/spec/views/with_windows.erb +4 -0
- data/lib/capybara/version.rb +1 -1
- data/lib/capybara/window.rb +1 -1
- data/lib/capybara.rb +102 -124
- data/spec/capybara_spec.rb +43 -21
- data/spec/dsl_spec.rb +1 -0
- data/spec/filter_set_spec.rb +28 -0
- data/spec/minitest_spec.rb +9 -1
- data/spec/minitest_spec_spec.rb +19 -5
- data/spec/per_session_config_spec.rb +67 -0
- data/spec/result_spec.rb +20 -0
- data/spec/rspec/shared_spec_matchers.rb +148 -44
- data/spec/rspec/views_spec.rb +4 -0
- data/spec/rspec_matchers_spec.rb +46 -0
- data/spec/rspec_spec.rb +77 -0
- data/spec/selector_spec.rb +2 -1
- data/spec/selenium_spec_chrome.rb +25 -17
- data/spec/selenium_spec_firefox.rb +2 -1
- data/spec/selenium_spec_marionette.rb +18 -5
- data/spec/session_spec.rb +44 -0
- data/spec/shared_selenium_session.rb +72 -8
- data/spec/spec_helper.rb +4 -0
- metadata +55 -8
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
Capybara::SpecHelper.spec '#refresh' do
|
3
|
+
it "reload the page" do
|
4
|
+
@session.visit('/form')
|
5
|
+
expect(@session).to have_select('form_locale', selected: 'English')
|
6
|
+
@session.select('Swedish', from: 'form_locale')
|
7
|
+
expect(@session).to have_select('form_locale', selected: 'Swedish')
|
8
|
+
@session.refresh
|
9
|
+
expect(@session).to have_select('form_locale', selected: 'English')
|
10
|
+
end
|
11
|
+
|
12
|
+
it "raises any errors caught inside the server", requires: [:server] do
|
13
|
+
quietly { @session.visit("/error") }
|
14
|
+
expect do
|
15
|
+
@session.refresh
|
16
|
+
end.to raise_error(TestApp::TestAppError)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "it reposts" do
|
20
|
+
@session.visit('/form')
|
21
|
+
@session.select('Sweden', from: 'form_region')
|
22
|
+
@session.click_button('awesome')
|
23
|
+
expect {
|
24
|
+
@session.refresh
|
25
|
+
sleep 2
|
26
|
+
}.to change{ extract_results(@session)['post_count'] }.by(1)
|
27
|
+
end
|
28
|
+
end
|
@@ -39,14 +39,14 @@ Capybara::SpecHelper.spec '#reset_session!' do
|
|
39
39
|
expect(@session).to have_no_selector :xpath, "/html/body/*", wait: false
|
40
40
|
end
|
41
41
|
|
42
|
-
it "handles modals during unload" do
|
42
|
+
it "handles modals during unload", requires: [:modals] do
|
43
43
|
@session.visit('/with_unload_alert')
|
44
44
|
expect(@session).to have_selector(:css, 'div')
|
45
45
|
expect { @session.reset_session! }.not_to raise_error
|
46
46
|
expect(@session).to have_no_selector :xpath, "/html/body/*", wait: false
|
47
47
|
end
|
48
48
|
|
49
|
-
it "handles already open modals" do
|
49
|
+
it "handles already open modals", requires: [:modals] do
|
50
50
|
@session.visit('/with_unload_alert')
|
51
51
|
@session.click_link('Go away')
|
52
52
|
expect { @session.reset_session! }.not_to raise_error
|
@@ -88,7 +88,7 @@ Capybara::SpecHelper.spec '#reset_session!' do
|
|
88
88
|
end
|
89
89
|
|
90
90
|
it "raises configured errors caught inside the server", requires: [:server] do
|
91
|
-
prev_errors = Capybara.server_errors
|
91
|
+
prev_errors = Capybara.server_errors.dup
|
92
92
|
|
93
93
|
Capybara.server_errors = [LoadError]
|
94
94
|
quietly { @session.visit("/error") }
|
@@ -24,6 +24,7 @@ Capybara::SpecHelper.spec "#select" do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
it "should not allow selecting options where they are the only inexact match if `Capybara.exact_options = true`" do
|
27
|
+
expect_any_instance_of(Kernel).to receive(:warn).with(/^DEPRECATED:/)
|
27
28
|
Capybara.exact_options = true
|
28
29
|
expect do
|
29
30
|
@session.select("Mis", from: 'Title')
|
@@ -85,7 +86,7 @@ Capybara::SpecHelper.spec "#select" do
|
|
85
86
|
|
86
87
|
context "with a locator that doesn't exist" do
|
87
88
|
it "should raise an error" do
|
88
|
-
msg = "Unable to find select box \"does not exist\""
|
89
|
+
msg = "Unable to find visible select box \"does not exist\" that is not disabled"
|
89
90
|
expect do
|
90
91
|
@session.select('foo', from: 'does not exist')
|
91
92
|
end.to raise_error(Capybara::ElementNotFound, msg)
|
@@ -94,7 +95,7 @@ Capybara::SpecHelper.spec "#select" do
|
|
94
95
|
|
95
96
|
context "with an option that doesn't exist" do
|
96
97
|
it "should raise an error" do
|
97
|
-
msg =
|
98
|
+
msg = /^Unable to find visible option "Does not Exist" within/
|
98
99
|
expect do
|
99
100
|
@session.select('Does not Exist', from: 'form_locale')
|
100
101
|
end.to raise_error(Capybara::ElementNotFound, msg)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
Capybara::SpecHelper.spec '#sibling' do
|
3
|
+
before do
|
4
|
+
@session.visit('/with_html')
|
5
|
+
end
|
6
|
+
|
7
|
+
after do
|
8
|
+
Capybara::Selector.remove(:monkey)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should find a prior sibling element using the given locator" do
|
12
|
+
el = @session.find(:css, '#mid_sibling')
|
13
|
+
expect(el.sibling('//div[@data-pre]')[:id]).to eq('pre_sibling')
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should find a following sibling element using the given locator" do
|
17
|
+
el = @session.find(:css, '#mid_sibling')
|
18
|
+
expect(el.sibling('//div[@data-post]')[:id]).to eq('post_sibling')
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should raise an error if there are multiple matches" do
|
22
|
+
el = @session.find(:css, '#mid_sibling')
|
23
|
+
expect { el.sibling('//div') }.to raise_error(Capybara::Ambiguous)
|
24
|
+
end
|
25
|
+
|
26
|
+
context "with css selectors" do
|
27
|
+
it "should find the first element using the given locator" do
|
28
|
+
el = @session.find(:css, '#mid_sibling')
|
29
|
+
expect(el.sibling(:css, '#pre_sibling')).to have_text('Pre Sibling')
|
30
|
+
expect(el.sibling(:css, '#post_sibling')).to have_text('Post Sibling')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with custom selector" do
|
35
|
+
it "should use the custom selector" do
|
36
|
+
Capybara.add_selector(:data_attribute) do
|
37
|
+
xpath { |attr| ".//*[@data-#{attr}]" }
|
38
|
+
end
|
39
|
+
el = @session.find(:css, '#mid_sibling')
|
40
|
+
expect(el.sibling(:data_attribute, 'pre').text).to eq('Pre Sibling')
|
41
|
+
expect(el.sibling(:data_attribute, 'post').text).to eq('Post Sibling')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
it "should raise ElementNotFound with a useful default message if nothing was found" do
|
47
|
+
el = @session.find(:css, '#child')
|
48
|
+
expect do
|
49
|
+
el.sibling(:xpath, '//div[@id="nosuchthing"]')
|
50
|
+
end.to raise_error(Capybara::ElementNotFound, "Unable to find xpath \"//div[@id=\\\"nosuchthing\\\"]\" that is a sibling of visible css \"#child\"")
|
51
|
+
end
|
52
|
+
end
|
@@ -69,11 +69,11 @@ Capybara::SpecHelper.spec "#uncheck" do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
it "should raise original error when no label available" do
|
72
|
-
expect { @session.uncheck('form_cars_ariel') }.to raise_error(Capybara::ElementNotFound, 'Unable to find checkbox "form_cars_ariel"')
|
72
|
+
expect { @session.uncheck('form_cars_ariel') }.to raise_error(Capybara::ElementNotFound, 'Unable to find visible checkbox "form_cars_ariel" that is not disabled')
|
73
73
|
end
|
74
74
|
|
75
75
|
it "should raise error if not allowed to click label" do
|
76
|
-
expect{@session.uncheck('form_cars_jaguar', allow_label_click: false)}.to raise_error(Capybara::ElementNotFound, 'Unable to find checkbox "form_cars_jaguar"')
|
76
|
+
expect{@session.uncheck('form_cars_jaguar', allow_label_click: false)}.to raise_error(Capybara::ElementNotFound, 'Unable to find visible checkbox "form_cars_jaguar" that is not disabled')
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
@@ -55,7 +55,7 @@ Capybara::SpecHelper.spec "#unselect" do
|
|
55
55
|
|
56
56
|
context "with a locator that doesn't exist" do
|
57
57
|
it "should raise an error" do
|
58
|
-
msg = "Unable to find select box \"does not exist\""
|
58
|
+
msg = "Unable to find visible select box \"does not exist\" that is not disabled"
|
59
59
|
expect do
|
60
60
|
@session.unselect('foo', from: 'does not exist')
|
61
61
|
end.to raise_error(Capybara::ElementNotFound, msg)
|
@@ -64,7 +64,7 @@ Capybara::SpecHelper.spec "#unselect" do
|
|
64
64
|
|
65
65
|
context "with an option that doesn't exist" do
|
66
66
|
it "should raise an error" do
|
67
|
-
msg =
|
67
|
+
msg = /^Unable to find visible option "Does not Exist" within/
|
68
68
|
expect do
|
69
69
|
@session.unselect('Does not Exist', from: 'form_underwear')
|
70
70
|
end.to raise_error(Capybara::ElementNotFound, msg)
|
@@ -63,8 +63,58 @@ Capybara::SpecHelper.spec '#visit' do
|
|
63
63
|
expect(URI.parse(@session.current_url).port).to eq(root_uri.port)
|
64
64
|
expect(@session).to have_content('Another World')
|
65
65
|
end
|
66
|
+
|
67
|
+
it "should add the server port to a visited url if no port specified", requires: [:server] do
|
68
|
+
expect(@session.driver).to receive(:visit).with("http://www.example.com:#{@session.server.port}")
|
69
|
+
@session.visit("http://www.example.com")
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should not override the visit specified port even if default for scheme", requires: [:server] do
|
73
|
+
expect(@session.driver).to receive(:visit).with("http://www.example.com:80")
|
74
|
+
@session.visit('http://www.example.com:80')
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should give preference to app_host port if specified", requires: [:server] do
|
78
|
+
Capybara.app_host = "http://www.example.com:6666"
|
79
|
+
expect(@session.driver).to receive(:visit).with("http://www.example.com:6666/random")
|
80
|
+
@session.visit('/random')
|
81
|
+
end
|
82
|
+
|
83
|
+
it "shouldn't override port if no server", requires: [:server] do
|
84
|
+
session = Capybara::Session.new(@session.mode, nil)
|
85
|
+
expect(session.driver).to receive(:visit).with("http://www.google.com")
|
86
|
+
session.visit("http://www.google.com")
|
87
|
+
end
|
88
|
+
|
89
|
+
it "shouldn't override port if no server but app_host is set", requires: [:server] do
|
90
|
+
session = Capybara::Session.new(@session.mode, nil)
|
91
|
+
Capybara.app_host = "http://www.example.com:6666"
|
92
|
+
expect(session.driver).to receive(:visit).with("http://www.google.com")
|
93
|
+
session.visit("http://www.google.com")
|
94
|
+
end
|
66
95
|
end
|
67
96
|
|
97
|
+
context "when Capybara.always_include_port is false" do
|
98
|
+
before(:each) do
|
99
|
+
Capybara.always_include_port = false
|
100
|
+
end
|
101
|
+
|
102
|
+
it "shouldn't overwrite port if app_host is set", requires: [:server] do
|
103
|
+
session = Capybara::Session.new(@session.mode, nil)
|
104
|
+
Capybara.app_host = "http://www.example.com:6666"
|
105
|
+
expect(session.driver).to receive(:visit).with("http://www.google.com")
|
106
|
+
session.visit("http://www.google.com")
|
107
|
+
end
|
108
|
+
|
109
|
+
it "shouldn't overwrite port if port specfified", requires: [:server] do
|
110
|
+
session = Capybara::Session.new(@session.mode, nil)
|
111
|
+
Capybara.app_host = "http://www.example.com:6666"
|
112
|
+
expect(session.driver).to receive(:visit).with("http://www.google.com:99")
|
113
|
+
session.visit("http://www.google.com:99")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
68
118
|
context "without a server", requires: [:server] do
|
69
119
|
it "should respect `app_host`" do
|
70
120
|
serverless_session = Capybara::Session.new(@session.mode, nil)
|
@@ -96,8 +146,13 @@ Capybara::SpecHelper.spec '#visit' do
|
|
96
146
|
@session.visit('/times')
|
97
147
|
expect(@session).to have_content('redirection complete')
|
98
148
|
end
|
99
|
-
end
|
100
149
|
|
150
|
+
it "should work if `app_host` has a trailing /", requires: [:server] do
|
151
|
+
Capybara.app_host = "http://#{@session.server.host}:#{@session.server.port}/"
|
152
|
+
@session.visit('/')
|
153
|
+
expect(@session).to have_content('Hello world!')
|
154
|
+
end
|
155
|
+
end
|
101
156
|
|
102
157
|
it "should send no referer when visiting a page" do
|
103
158
|
@session.visit '/get_referer'
|
@@ -21,18 +21,18 @@ Capybara::SpecHelper.spec '#become_closed', requires: [:windows, :js] do
|
|
21
21
|
@session.execute_script('setTimeout(function(){ window.close(); }, 500);')
|
22
22
|
end
|
23
23
|
Capybara.using_wait_time 0.1 do
|
24
|
-
expect(@other_window).to become_closed(wait:
|
24
|
+
expect(@other_window).to become_closed(wait: 5)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'should raise error if value of :wait is less than timeout' do
|
29
29
|
@session.within_window @other_window do
|
30
|
-
@session.execute_script('setTimeout(function(){ window.close(); },
|
30
|
+
@session.execute_script('setTimeout(function(){ window.close(); }, 1000);')
|
31
31
|
end
|
32
32
|
Capybara.using_wait_time 2 do
|
33
33
|
expect do
|
34
|
-
expect(@other_window).to become_closed(wait: 0.
|
35
|
-
end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /\Aexpected #<Window @handle=".+"> to become closed after 0.
|
34
|
+
expect(@other_window).to become_closed(wait: 0.2)
|
35
|
+
end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /\Aexpected #<Window @handle=".+"> to become closed after 0.2 seconds\Z/)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -42,7 +42,7 @@ Capybara::SpecHelper.spec '#become_closed', requires: [:windows, :js] do
|
|
42
42
|
@session.within_window @other_window do
|
43
43
|
@session.execute_script('setTimeout(function(){ window.close(); }, 500);')
|
44
44
|
end
|
45
|
-
Capybara.using_wait_time
|
45
|
+
Capybara.using_wait_time 5 do
|
46
46
|
expect(@other_window).to become_closed
|
47
47
|
end
|
48
48
|
end
|
@@ -60,25 +60,25 @@ Capybara::SpecHelper.spec '#become_closed', requires: [:windows, :js] do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
context 'with not_to' do
|
63
|
-
it
|
63
|
+
it "should not raise error if window doesn't close before default_max_wait_time" do
|
64
64
|
@session.within_window @other_window do
|
65
|
-
@session.execute_script('setTimeout(function(){ window.close(); },
|
65
|
+
@session.execute_script('setTimeout(function(){ window.close(); }, 1000);')
|
66
66
|
end
|
67
|
-
Capybara.using_wait_time 0.
|
67
|
+
Capybara.using_wait_time 0.3 do
|
68
68
|
expect do
|
69
69
|
expect(@other_window).not_to become_closed
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
it 'should raise error if
|
74
|
+
it 'should raise error if window closes before default_max_wait_time' do
|
75
75
|
@session.within_window @other_window do
|
76
76
|
@session.execute_script('setTimeout(function(){ window.close(); }, 700);')
|
77
77
|
end
|
78
|
-
Capybara.using_wait_time
|
78
|
+
Capybara.using_wait_time 3.1 do
|
79
79
|
expect do
|
80
80
|
expect(@other_window).not_to become_closed
|
81
|
-
end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /\Aexpected #<Window @handle=".+"> not to become closed after
|
81
|
+
end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /\Aexpected #<Window @handle=".+"> not to become closed after 3.1 seconds\Z/)
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
@@ -79,7 +79,7 @@ Capybara::SpecHelper.spec '#switch_to_window', requires: [:windows] do
|
|
79
79
|
@session.within(:css, '#doesNotOpenWindows') do
|
80
80
|
@session.switch_to_window { @session.title == 'With Windows' }
|
81
81
|
end
|
82
|
-
end.to raise_error(Capybara::ScopeError,
|
82
|
+
end.to raise_error(Capybara::ScopeError, /`switch_to_window` is not supposed to be invoked/)
|
83
83
|
end
|
84
84
|
|
85
85
|
it "should raise error when invoked inside `within_frame` as it's nonsense" do
|
@@ -87,16 +87,18 @@ Capybara::SpecHelper.spec '#switch_to_window', requires: [:windows] do
|
|
87
87
|
@session.within_frame('frameOne') do
|
88
88
|
@session.switch_to_window { @session.title == 'With Windows' }
|
89
89
|
end
|
90
|
-
end.to raise_error(Capybara::ScopeError,
|
90
|
+
end.to raise_error(Capybara::ScopeError, /`switch_to_window` is not supposed to be invoked from/)
|
91
91
|
end
|
92
92
|
|
93
|
-
it "should
|
94
|
-
|
95
|
-
expect
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
93
|
+
it "should allow to be called inside within_window and within_window will still return to original" do
|
94
|
+
other_windows = (@session.windows - [@window])
|
95
|
+
expect(@session.current_window).to eq(@window)
|
96
|
+
@session.within_window other_windows[0] do
|
97
|
+
expect(@session.current_window).to eq(other_windows[0])
|
98
|
+
@session.switch_to_window other_windows[1]
|
99
|
+
expect(@session.current_window).to eq(other_windows[1])
|
100
|
+
end
|
101
|
+
expect(@session.current_window).to eq(@window)
|
100
102
|
end
|
101
103
|
|
102
104
|
it "should raise error if window matching block wasn't found" do
|
@@ -22,12 +22,12 @@ Capybara::SpecHelper.spec '#window_opened_by', requires: [:windows] do
|
|
22
22
|
Capybara.using_wait_time 2 do
|
23
23
|
button=@session.find(:css, '#openWindowWithLongerTimeout')
|
24
24
|
expect do
|
25
|
-
@session.window_opened_by(wait: 0.
|
25
|
+
@session.window_opened_by(wait: 0.3) do
|
26
26
|
button.click
|
27
27
|
end
|
28
28
|
end.to raise_error(Capybara::WindowError, zero_windows_message)
|
29
29
|
end
|
30
|
-
@session.document.synchronize(
|
30
|
+
@session.document.synchronize(5, errors: [Capybara::CapybaraError]) do
|
31
31
|
raise Capybara::CapybaraError if @session.windows.size != 2
|
32
32
|
end
|
33
33
|
end
|
@@ -46,7 +46,7 @@ Capybara::SpecHelper.spec '#window_opened_by', requires: [:windows] do
|
|
46
46
|
context 'without :wait option' do
|
47
47
|
it 'should raise error if default_max_wait_time is less than timeout' do
|
48
48
|
button = @session.find(:css, '#openWindowWithTimeout')
|
49
|
-
Capybara.using_wait_time 0.
|
49
|
+
Capybara.using_wait_time 0.1 do
|
50
50
|
expect do
|
51
51
|
@session.window_opened_by do
|
52
52
|
button.click
|
@@ -60,7 +60,7 @@ Capybara::SpecHelper.spec '#window_opened_by', requires: [:windows] do
|
|
60
60
|
|
61
61
|
it 'should find window if default_max_wait_time is more than timeout' do
|
62
62
|
button = @session.find(:css, '#openWindowWithTimeout')
|
63
|
-
Capybara.using_wait_time
|
63
|
+
Capybara.using_wait_time 5 do
|
64
64
|
window = @session.window_opened_by do
|
65
65
|
button.click
|
66
66
|
end
|
@@ -57,10 +57,10 @@ Capybara::SpecHelper.spec '#within_window', requires: [:windows] do
|
|
57
57
|
expect(@session.send(:scopes)).to eq([nil])
|
58
58
|
end
|
59
59
|
|
60
|
-
it "should leave correct scopes after execution in case of error" do
|
60
|
+
it "should leave correct scopes after execution in case of error", requires: [:windows, :frames] do
|
61
61
|
window = (@session.windows - [@window]).first
|
62
62
|
expect do
|
63
|
-
@session.
|
63
|
+
@session.within_frame 'frameOne' do
|
64
64
|
@session.within_window(window) {}
|
65
65
|
end
|
66
66
|
end.to raise_error(Capybara::ScopeError)
|
@@ -102,6 +102,31 @@ Capybara::SpecHelper.spec '#within_window', requires: [:windows] do
|
|
102
102
|
expect(@session.title).to eq('With Windows')
|
103
103
|
end
|
104
104
|
|
105
|
+
it "should be able to nest within_window" do
|
106
|
+
@session.within_window(->{ @session.title == 'Title of popup two'}) do
|
107
|
+
expect(@session).to have_css('#divInPopupTwo')
|
108
|
+
@session.within_window(->{ @session.title == 'Title of the first popup'}) do
|
109
|
+
expect(@session).to have_css('#divInPopupOne')
|
110
|
+
end
|
111
|
+
expect(@session).to have_css('#divInPopupTwo')
|
112
|
+
expect(@session).not_to have_css('divInPopupOne')
|
113
|
+
end
|
114
|
+
expect(@session).not_to have_css('#divInPopupTwo')
|
115
|
+
expect(@session).not_to have_css('divInPopupOne')
|
116
|
+
expect(@session.title).to eq('With Windows')
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should work inside a normal scope" do
|
120
|
+
expect(@session).to have_css('#openWindow')
|
121
|
+
@session.within(:css, '#scope') do
|
122
|
+
@session.within_window(->{ @session.title == 'Title of the first popup'}) do
|
123
|
+
expect(@session).to have_css('#divInPopupOne')
|
124
|
+
end
|
125
|
+
expect(@session).to have_content('My scoped content')
|
126
|
+
expect(@session).not_to have_css('#openWindow')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
105
130
|
it "should raise error if window wasn't found" do
|
106
131
|
expect do
|
107
132
|
@session.within_window(->{ @session.title == 'Invalid title'}) do
|
@@ -33,12 +33,15 @@ module Capybara
|
|
33
33
|
Capybara.default_max_wait_time = 1
|
34
34
|
Capybara.ignore_hidden_elements = true
|
35
35
|
Capybara.exact = false
|
36
|
-
|
36
|
+
# `exact_options` is deprecated - set instancce var directly so we
|
37
|
+
# don't generate message every reset
|
38
|
+
Capybara.send(:config).session_options.instance_variable_set('@exact_options', false)
|
37
39
|
Capybara.raise_server_errors = true
|
38
40
|
Capybara.visible_text_only = false
|
39
41
|
Capybara.match = :smart
|
40
42
|
Capybara.wait_on_first_by_default = false
|
41
43
|
Capybara.enable_aria_label = false
|
44
|
+
reset_threadsafe
|
42
45
|
end
|
43
46
|
|
44
47
|
def filter(requires, metadata)
|
@@ -51,7 +54,7 @@ module Capybara
|
|
51
54
|
end
|
52
55
|
end
|
53
56
|
|
54
|
-
def spec(name, options
|
57
|
+
def spec(name, *options, &block)
|
55
58
|
@specs ||= []
|
56
59
|
@specs << [name, options, block]
|
57
60
|
end
|
@@ -64,16 +67,33 @@ module Capybara
|
|
64
67
|
before do
|
65
68
|
@session = session
|
66
69
|
end
|
70
|
+
|
67
71
|
after do
|
68
72
|
@session.reset_session!
|
69
73
|
end
|
74
|
+
|
75
|
+
before :each, psc: true do
|
76
|
+
SpecHelper.reset_threadsafe(true, @session)
|
77
|
+
end
|
78
|
+
|
79
|
+
after psc: true do
|
80
|
+
SpecHelper.reset_threadsafe(false, @session)
|
81
|
+
end
|
82
|
+
|
70
83
|
specs.each do |spec_name, spec_options, block|
|
71
|
-
describe spec_name, spec_options do
|
84
|
+
describe spec_name, *spec_options do
|
72
85
|
class_eval(&block)
|
73
86
|
end
|
74
87
|
end
|
75
88
|
end
|
76
89
|
end
|
90
|
+
|
91
|
+
def reset_threadsafe(bool = false, session = nil)
|
92
|
+
Capybara::Session.class_variable_set(:@@instance_created, false) # Work around limit on when threadsafe can be changed
|
93
|
+
Capybara.threadsafe = bool
|
94
|
+
session = session.current_session if session.respond_to?(:current_session)
|
95
|
+
session.instance_variable_set(:@config, nil) if session
|
96
|
+
end
|
77
97
|
end # class << self
|
78
98
|
|
79
99
|
def silence_stream(stream)
|
@@ -99,7 +119,11 @@ module Capybara
|
|
99
119
|
end
|
100
120
|
|
101
121
|
def marionette?(session)
|
102
|
-
session.driver.respond_to?(:marionette
|
122
|
+
session.driver.respond_to?(:marionette?, true) && session.driver.send(:marionette?)
|
123
|
+
end
|
124
|
+
|
125
|
+
def rspec2?
|
126
|
+
!defined?(::RSpec::Expectations::Version) || (Gem::Version.new(RSpec::Expectations::Version::STRING) < Gem::Version.new('3.0'))
|
103
127
|
end
|
104
128
|
end
|
105
129
|
end
|
@@ -17,6 +17,7 @@ class TestApp < Sinatra::Base
|
|
17
17
|
set :raise_errors, true
|
18
18
|
set :show_exceptions, false
|
19
19
|
|
20
|
+
@@form_post_count = 0
|
20
21
|
# Also check lib/capybara/spec/views/*.erb for pages not listed here
|
21
22
|
|
22
23
|
get '/' do
|
@@ -147,7 +148,8 @@ class TestApp < Sinatra::Base
|
|
147
148
|
end
|
148
149
|
|
149
150
|
post '/form' do
|
150
|
-
|
151
|
+
@@form_post_count += 1
|
152
|
+
'<pre id="results">' + params[:form].merge({"post_count" => @@form_post_count}).to_yaml + '</pre>'
|
151
153
|
end
|
152
154
|
|
153
155
|
post '/upload_empty' do
|
@@ -235,6 +235,17 @@ New line after and before textarea tag
|
|
235
235
|
</select>
|
236
236
|
</p>
|
237
237
|
|
238
|
+
<!-- invisible multiselect and options -->
|
239
|
+
<p style="display: none">
|
240
|
+
<label for="form_dessert">Dessert</label>
|
241
|
+
<select name="form[dessert]" id="form_dessert" multiple="multiple">
|
242
|
+
<option selected="selected">Pudding</option>
|
243
|
+
<option>Lava cake</option>
|
244
|
+
<option selected="selected">Tiramisu</option>
|
245
|
+
<option>Panna cotta</option>
|
246
|
+
</select>
|
247
|
+
</p>
|
248
|
+
|
238
249
|
<!-- visible select with invisible selected option (which some browsers may treat as visible) -->
|
239
250
|
<p>
|
240
251
|
<label for="form_sorbet">Sorbet</label>
|
@@ -245,6 +256,17 @@ New line after and before textarea tag
|
|
245
256
|
</select>
|
246
257
|
</p>
|
247
258
|
|
259
|
+
<!-- visible multiselect with invisible selected options (which some browsers may treat as visible) -->
|
260
|
+
<p>
|
261
|
+
<label for="form_cake">Cake</label>
|
262
|
+
<select name="form[cake]" id="form_cake" multiple="multiple">
|
263
|
+
<option>Butter Cake</option>
|
264
|
+
<option selected="selected" style="display: none">Chocolate Cake</option>
|
265
|
+
<option>Strawberry Cake</option>
|
266
|
+
<option selected="selected" style="display: none">Sponge Cake</option>
|
267
|
+
</select>
|
268
|
+
</p>
|
269
|
+
|
248
270
|
<p>
|
249
271
|
<span>First address<span>
|
250
272
|
<label for='address1_street'>Street</label>
|
@@ -586,6 +608,10 @@ New line after and before textarea tag
|
|
586
608
|
</label>
|
587
609
|
|
588
610
|
<label>Confusion
|
589
|
-
<textarea id="confusion_textarea" class="confusion confusion-textarea"
|
611
|
+
<textarea id="confusion_textarea" class="confusion confusion-textarea"></textarea>
|
590
612
|
</label>
|
591
613
|
|
614
|
+
<p>
|
615
|
+
<label for="asterisk_input">With Asterisk<abbr title="required">*</abbr></label>
|
616
|
+
<input id="asterisk_input" type="number"value="2016"/>
|
617
|
+
</p>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<style>
|
4
|
+
header { height: 45px; position: fixed; top: 0; background-color: red; width: 100%;}
|
5
|
+
footer { height: 45px; position: fixed; bottom: 0; background-color: red; width: 100%;}
|
6
|
+
#main { margin: 45px;}
|
7
|
+
#tall { display: block; height: 2000px;}
|
8
|
+
</style>
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
<header>My headers</header>
|
12
|
+
<div id="main">
|
13
|
+
<div id="tall">A tall block</div>
|
14
|
+
<a href="/">Go to root</a>
|
15
|
+
</div>
|
16
|
+
<footer>My footer</footer>
|
17
|
+
</body>
|
@@ -14,5 +14,10 @@
|
|
14
14
|
Some text here so the wrapper has size
|
15
15
|
<div class="hidden_until_hover">Here I am</div>
|
16
16
|
</div>
|
17
|
+
<div style="display: block; height: 1000px; width: 100%"></div>
|
18
|
+
<div class="wrapper scroll_needed" >
|
19
|
+
Some text here so the wrapper has size
|
20
|
+
<div class="hidden_until_hover">Here I am</div>
|
21
|
+
</div>
|
17
22
|
</body>
|
18
23
|
</html>
|
@@ -13,13 +13,13 @@
|
|
13
13
|
<span class="number">42</span>
|
14
14
|
<span>Other span</span>
|
15
15
|
|
16
|
-
<p class="para" id="first">
|
16
|
+
<p class="para" id="first" data-random="abc\def">
|
17
17
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
18
18
|
tempor incididunt ut <a href="/with_simple_html" title="awesome title" class="simple">labore</a>
|
19
19
|
et dolore magna aliqua. Ut enim ad minim veniam,
|
20
20
|
quis nostrud exercitation <a href="/foo" id="foo">ullamco</a> laboris nisi
|
21
21
|
ut aliquip ex ea commodo consequat.
|
22
|
-
<a href="/with_simple_html" aria-label="Go to simple"><img width="20" height="20" alt="awesome image" /></a>
|
22
|
+
<a href="/with_simple_html" aria-label="Go to simple"><img id="first_image" width="20" height="20" alt="awesome image" /></a>
|
23
23
|
</p>
|
24
24
|
|
25
25
|
<p class="para" id="second">
|
@@ -119,4 +119,35 @@ banana</textarea>
|
|
119
119
|
|
120
120
|
<div>
|
121
121
|
<a id="link_placeholder">No href</a>
|
122
|
+
<a id="link_blank_href" href="">Blank href</a>
|
122
123
|
</div>
|
124
|
+
|
125
|
+
<div id="uppercase" style="text-transform: uppercase;">
|
126
|
+
text here
|
127
|
+
</div>
|
128
|
+
|
129
|
+
<div id="ancestor3">
|
130
|
+
Ancestor
|
131
|
+
<div id="ancestor2">
|
132
|
+
Ancestor
|
133
|
+
<div id="ancestor1">
|
134
|
+
Ancestor
|
135
|
+
<div id="child">Child</div>
|
136
|
+
</div>
|
137
|
+
</div>
|
138
|
+
<button id="ancestor_button" type="submit" disabled>
|
139
|
+
<img id="button_img" width="20" height="20" alt="button img"/>
|
140
|
+
</button>
|
141
|
+
</div>
|
142
|
+
|
143
|
+
<div id="sibling_test">
|
144
|
+
<div id="sibling_wrapper" data-pre=true>
|
145
|
+
<div id="pre_sibling" data-pre=true>Pre Sibling</div>
|
146
|
+
<div id="mid_sibling">Mid Sibling</div>
|
147
|
+
<div id="post_sibling" data-post=true>Post Sibling</div>
|
148
|
+
</div>
|
149
|
+
<div id="other_sibling_wrapper" data-post=true>
|
150
|
+
<div data-pre=true>Pre Sibling</div>
|
151
|
+
<div data-post=true>Post Sibling</div>
|
152
|
+
</div>
|
153
|
+
</div>
|