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