capybara 3.0.3 → 3.1.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 +4 -4
- data/History.md +10 -0
- data/lib/capybara.rb +1 -1
- data/lib/capybara/helpers.rb +1 -1
- data/lib/capybara/minitest/spec.rb +2 -0
- data/lib/capybara/node/actions.rb +45 -5
- data/lib/capybara/queries/match_query.rb +2 -0
- data/lib/capybara/queries/selector_query.rb +3 -4
- data/lib/capybara/queries/text_query.rb +4 -5
- data/lib/capybara/rack_test/node.rb +6 -4
- data/lib/capybara/result.rb +1 -1
- data/lib/capybara/rspec/compound.rb +2 -0
- data/lib/capybara/selector.rb +72 -18
- data/lib/capybara/selector/css.rb +2 -0
- data/lib/capybara/selenium/driver.rb +14 -15
- data/lib/capybara/selenium/node.rb +23 -29
- data/lib/capybara/server.rb +29 -4
- data/lib/capybara/session.rb +12 -13
- data/lib/capybara/spec/session/all_spec.rb +6 -6
- data/lib/capybara/spec/session/{assert_current_path.rb → assert_current_path_spec.rb} +2 -3
- data/lib/capybara/spec/session/{assert_selector.rb → assert_selector_spec.rb} +0 -0
- data/lib/capybara/spec/session/{assert_text.rb → assert_text_spec.rb} +1 -1
- data/lib/capybara/spec/session/{assert_title.rb → assert_title_spec.rb} +0 -0
- data/lib/capybara/spec/session/check_spec.rb +6 -6
- data/lib/capybara/spec/session/click_link_or_button_spec.rb +0 -7
- data/lib/capybara/spec/session/current_url_spec.rb +6 -8
- data/lib/capybara/spec/session/element/{assert_match_selector.rb → assert_match_selector_spec.rb} +2 -0
- data/lib/capybara/spec/session/element/match_css_spec.rb +2 -0
- data/lib/capybara/spec/session/element/match_xpath_spec.rb +2 -0
- data/lib/capybara/spec/session/element/matches_selector_spec.rb +2 -0
- data/lib/capybara/spec/session/find_by_id_spec.rb +1 -1
- data/lib/capybara/spec/session/find_field_spec.rb +1 -1
- data/lib/capybara/spec/session/first_spec.rb +12 -12
- data/lib/capybara/spec/session/frame/frame_title_spec.rb +1 -1
- data/lib/capybara/spec/session/frame/frame_url_spec.rb +1 -1
- data/lib/capybara/spec/session/frame/switch_to_frame_spec.rb +2 -2
- data/lib/capybara/spec/session/frame/within_frame_spec.rb +1 -1
- data/lib/capybara/spec/session/has_button_spec.rb +5 -0
- data/lib/capybara/spec/session/has_current_path_spec.rb +2 -2
- data/lib/capybara/spec/session/has_field_spec.rb +1 -1
- data/lib/capybara/spec/session/has_none_selectors_spec.rb +2 -0
- data/lib/capybara/spec/session/has_selector_spec.rb +8 -0
- data/lib/capybara/spec/session/{headers.rb → headers_spec.rb} +0 -0
- data/lib/capybara/spec/session/node_spec.rb +4 -4
- data/lib/capybara/spec/session/reset_session_spec.rb +2 -2
- data/lib/capybara/spec/session/{response_code.rb → response_code_spec.rb} +0 -0
- data/lib/capybara/spec/session/save_and_open_screenshot_spec.rb +2 -1
- data/lib/capybara/spec/session/select_spec.rb +27 -1
- data/lib/capybara/spec/session/selectors_spec.rb +2 -0
- data/lib/capybara/spec/session/uncheck_spec.rb +3 -3
- data/lib/capybara/spec/session/visit_spec.rb +17 -10
- data/lib/capybara/spec/session/window/become_closed_spec.rb +3 -3
- data/lib/capybara/spec/session/window/current_window_spec.rb +2 -2
- data/lib/capybara/spec/session/window/open_new_window_spec.rb +3 -3
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +5 -5
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +3 -3
- data/lib/capybara/spec/session/window/window_spec.rb +24 -9
- data/lib/capybara/spec/session/window/windows_spec.rb +2 -2
- data/lib/capybara/spec/session/window/within_window_spec.rb +2 -2
- data/lib/capybara/spec/session/within_spec.rb +3 -3
- data/lib/capybara/spec/spec_helper.rb +7 -5
- data/lib/capybara/spec/views/form.erb +9 -0
- data/lib/capybara/version.rb +1 -1
- data/spec/basic_node_spec.rb +1 -1
- data/spec/capybara_spec.rb +4 -14
- data/spec/dsl_spec.rb +5 -3
- data/spec/fixtures/certificate.pem +25 -0
- data/spec/fixtures/key.pem +27 -0
- data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -2
- data/spec/fixtures/selenium_driver_rspec_success.rb +2 -2
- data/spec/rack_test_spec.rb +8 -6
- data/spec/result_spec.rb +22 -2
- data/spec/rspec/features_spec.rb +4 -2
- data/spec/rspec/scenarios_spec.rb +1 -1
- data/spec/rspec/shared_spec_matchers.rb +7 -4
- data/spec/rspec/views_spec.rb +2 -1
- data/spec/rspec_spec.rb +80 -78
- data/spec/selenium_spec_marionette.rb +6 -4
- data/spec/server_spec.rb +40 -2
- data/spec/session_spec.rb +12 -4
- data/spec/shared_selenium_session.rb +106 -84
- metadata +11 -9
data/spec/rspec_spec.rb
CHANGED
@@ -2,118 +2,120 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
RSpec.describe 'capybara/rspec'
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
it "should include RSpec matcher proxies" do
|
12
|
-
expect(self.class.ancestors).to include Capybara::RSpecMatcherProxies
|
13
|
-
end
|
14
|
-
|
15
|
-
context "resetting session" do
|
16
|
-
it "sets a cookie in one example..." do
|
17
|
-
visit('/set_cookie')
|
18
|
-
expect(page.body).to include('Cookie set to test_cookie')
|
19
|
-
end
|
20
|
-
|
21
|
-
it "...then it is not available in the next" do
|
22
|
-
visit('/get_cookie')
|
23
|
-
expect(page.body).not_to include('test_cookie')
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
context "setting the current driver" do
|
28
|
-
it "sets the current driver in one example..." do
|
29
|
-
Capybara.current_driver = :selenium
|
5
|
+
RSpec.describe 'capybara/rspec' do
|
6
|
+
context "Feature", type: :feature do
|
7
|
+
it "should include Capybara in rspec" do
|
8
|
+
visit('/foo')
|
9
|
+
expect(page.body).to include('Another World')
|
30
10
|
end
|
31
11
|
|
32
|
-
it "
|
33
|
-
expect(
|
12
|
+
it "should include RSpec matcher proxies" do
|
13
|
+
expect(self.class.ancestors).to include Capybara::RSpecMatcherProxies
|
34
14
|
end
|
35
|
-
end
|
36
|
-
|
37
|
-
it "switches to the javascript driver when giving it as metadata", js: true do
|
38
|
-
expect(Capybara.current_driver).to eq(Capybara.javascript_driver)
|
39
|
-
end
|
40
15
|
|
41
|
-
|
42
|
-
|
43
|
-
|
16
|
+
context "resetting session" do
|
17
|
+
it "sets a cookie in one example..." do
|
18
|
+
visit('/set_cookie')
|
19
|
+
expect(page.body).to include('Cookie set to test_cookie')
|
20
|
+
end
|
44
21
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
expect(found.size).to eq(5)
|
22
|
+
it "...then it is not available in the next" do
|
23
|
+
visit('/get_cookie')
|
24
|
+
expect(page.body).not_to include('test_cookie')
|
25
|
+
end
|
50
26
|
end
|
51
27
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
28
|
+
context "setting the current driver" do
|
29
|
+
it "sets the current driver in one example..." do
|
30
|
+
Capybara.current_driver = :selenium
|
31
|
+
end
|
57
32
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
expect do
|
62
|
-
within(:css, "#does_not_exist") { click_link "Go to simple" }
|
63
|
-
end.to raise_error(Capybara::ElementNotFound)
|
33
|
+
it "...then it has returned to the default in the next example" do
|
34
|
+
expect(Capybara.current_driver).to eq(:rack_test)
|
35
|
+
end
|
64
36
|
end
|
65
37
|
|
66
|
-
it "
|
67
|
-
|
68
|
-
# This reads terribly, but must call #within
|
69
|
-
expect(find(:css, 'span.number').text.to_i).to within(1).of(41)
|
38
|
+
it "switches to the javascript driver when giving it as metadata", js: true do
|
39
|
+
expect(Capybara.current_driver).to eq(Capybara.javascript_driver)
|
70
40
|
end
|
71
|
-
end
|
72
|
-
end
|
73
41
|
|
74
|
-
|
75
|
-
|
76
|
-
before do
|
77
|
-
class DSLMatchersTest
|
78
|
-
include Capybara::DSL
|
79
|
-
include RSpec::Matchers
|
80
|
-
end
|
81
|
-
|
82
|
-
@test_class_instance = DSLMatchersTest.new
|
42
|
+
it "switches to the given driver when giving it as metadata", driver: :culerity do
|
43
|
+
expect(Capybara.current_driver).to eq(:culerity)
|
83
44
|
end
|
84
45
|
|
85
46
|
context "#all" do
|
86
47
|
it "allows access to the Capybara finder" do
|
87
|
-
|
88
|
-
|
48
|
+
visit('/with_html')
|
49
|
+
found = all(:css, 'h2') { |element| element[:class] == 'head' }
|
50
|
+
expect(found.size).to eq(5)
|
89
51
|
end
|
90
52
|
|
91
53
|
it "allows access to the RSpec matcher" do
|
92
|
-
|
93
|
-
|
54
|
+
visit('/with_html')
|
55
|
+
strings = %w[test1 test2]
|
56
|
+
expect(strings).to all(be_a(String))
|
94
57
|
end
|
95
58
|
end
|
96
59
|
|
97
60
|
context "#within" do
|
98
61
|
it "allows access to the Capybara scoper" do
|
99
|
-
|
62
|
+
visit('/with_html')
|
100
63
|
expect do
|
101
|
-
|
64
|
+
within(:css, "#does_not_exist") { click_link "Go to simple" }
|
102
65
|
end.to raise_error(Capybara::ElementNotFound)
|
103
66
|
end
|
104
67
|
|
105
68
|
it "allows access to the RSpec matcher" do
|
106
|
-
|
69
|
+
visit('/with_html')
|
107
70
|
# This reads terribly, but must call #within
|
108
|
-
expect(
|
71
|
+
expect(find(:css, 'span.number').text.to_i).to within(1).of(41)
|
109
72
|
end
|
110
73
|
end
|
111
74
|
end
|
112
|
-
end
|
113
75
|
|
114
|
-
|
115
|
-
|
116
|
-
|
76
|
+
context 'Type: Other', type: :other do
|
77
|
+
context "when RSpec::Matchers is included after Capybara::DSL" do
|
78
|
+
before do
|
79
|
+
class DSLMatchersTest
|
80
|
+
include Capybara::DSL
|
81
|
+
include RSpec::Matchers
|
82
|
+
end
|
83
|
+
|
84
|
+
@test_class_instance = DSLMatchersTest.new
|
85
|
+
end
|
86
|
+
|
87
|
+
context "#all" do
|
88
|
+
it "allows access to the Capybara finder" do
|
89
|
+
@test_class_instance.visit('/with_html')
|
90
|
+
expect(@test_class_instance.all(:css, 'h2.head').size).to eq(5)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "allows access to the RSpec matcher" do
|
94
|
+
@test_class_instance.visit('/with_html')
|
95
|
+
strings = %w[test1 test2]
|
96
|
+
expect(strings).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
|
+
@test_class_instance.visit('/with_html')
|
110
|
+
# This reads terribly, but must call #within
|
111
|
+
expect(@test_class_instance.find(:css, 'span.number').text.to_i).to @test_class_instance.within(1).of(41)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should not include Capybara" do
|
117
|
+
expect { visit('/') }.to raise_error(NoMethodError)
|
118
|
+
end
|
117
119
|
end
|
118
120
|
end
|
119
121
|
|
@@ -44,7 +44,7 @@ $stdout.puts `#{Selenium::WebDriver::Firefox.driver_path} --version` if ENV['CI'
|
|
44
44
|
|
45
45
|
Capybara::SpecHelper.run_specs TestSessions::SeleniumMarionette, "selenium", capybara_skip: skipped_tests
|
46
46
|
|
47
|
-
RSpec.describe "Capybara::Session with firefox" do
|
47
|
+
RSpec.describe "Capybara::Session with firefox" do # rubocop:disable RSpec/MultipleDescribes
|
48
48
|
include Capybara::SpecHelper
|
49
49
|
include_examples "Capybara::Session", TestSessions::SeleniumMarionette, :selenium_marionette
|
50
50
|
include_examples Capybara::RSpecMatchers, TestSessions::SeleniumMarionette, :selenium_marionette
|
@@ -57,7 +57,7 @@ RSpec.describe Capybara::Selenium::Driver do
|
|
57
57
|
|
58
58
|
describe '#quit' do
|
59
59
|
it "should reset browser when quit" do
|
60
|
-
expect(@driver.browser).to
|
60
|
+
expect(@driver.browser).to be_truthy
|
61
61
|
@driver.quit
|
62
62
|
# access instance variable directly so we don't create a new browser instance
|
63
63
|
expect(@driver.instance_variable_get(:@browser)).to be_nil
|
@@ -74,7 +74,7 @@ RSpec.describe Capybara::Selenium::Driver do
|
|
74
74
|
end
|
75
75
|
|
76
76
|
it "warns UnknownError returned during quit because the browser is probably already gone" do
|
77
|
-
|
77
|
+
allow(@driver).to receive(:warn)
|
78
78
|
allow(@driver.browser).to(
|
79
79
|
receive(:quit)
|
80
80
|
.and_raise(Selenium::WebDriver::Error::UnknownError, "random message")
|
@@ -82,10 +82,11 @@ RSpec.describe Capybara::Selenium::Driver do
|
|
82
82
|
|
83
83
|
expect { @driver.quit }.not_to raise_error
|
84
84
|
expect(@driver.instance_variable_get(:@browser)).to be_nil
|
85
|
+
expect(@driver).to have_received(:warn).with(/random message/)
|
85
86
|
end
|
86
87
|
|
87
88
|
it "ignores silenced UnknownError returned during quit because the browser is almost definitely already gone" do
|
88
|
-
|
89
|
+
allow(@driver).to receive(:warn)
|
89
90
|
allow(@driver.browser).to(
|
90
91
|
receive(:quit)
|
91
92
|
.and_raise(Selenium::WebDriver::Error::UnknownError, "Error communicating with the remote browser")
|
@@ -93,6 +94,7 @@ RSpec.describe Capybara::Selenium::Driver do
|
|
93
94
|
|
94
95
|
expect { @driver.quit }.not_to raise_error
|
95
96
|
expect(@driver.instance_variable_get(:@browser)).to be_nil
|
97
|
+
expect(@driver).not_to have_received(:warn)
|
96
98
|
end
|
97
99
|
end
|
98
100
|
end
|
data/spec/server_spec.rb
CHANGED
@@ -51,7 +51,7 @@ RSpec.describe Capybara::Server do
|
|
51
51
|
|
52
52
|
it "should use given port" do
|
53
53
|
@app = proc { |_env| [200, {}, ["Hello Server!"]] }
|
54
|
-
@server = Capybara::Server.new(@app, 22790).boot
|
54
|
+
@server = Capybara::Server.new(@app, port: 22790).boot
|
55
55
|
|
56
56
|
@res = Net::HTTP.start(@server.host, 22790) { |http| http.get('/') }
|
57
57
|
expect(@res.body).to include('Hello Server')
|
@@ -73,6 +73,28 @@ RSpec.describe Capybara::Server do
|
|
73
73
|
expect(@res2.body).to include('Hello Second Server')
|
74
74
|
end
|
75
75
|
|
76
|
+
it "should support SSL" do
|
77
|
+
begin
|
78
|
+
key = File.join(Dir.pwd, "spec", "fixtures", "key.pem")
|
79
|
+
cert = File.join(Dir.pwd, "spec", "fixtures", "certificate.pem")
|
80
|
+
Capybara.server = :puma, { Host: "ssl://#{Capybara.server_host}?key=#{key}&cert=#{cert}" }
|
81
|
+
app = proc { |_env| [200, {}, ['Hello SSL Server!']] }
|
82
|
+
server = Capybara::Server.new(app).boot
|
83
|
+
|
84
|
+
expect do
|
85
|
+
Net::HTTP.start(server.host, server.port) { |http| http.get('/__idntify__') }
|
86
|
+
end.to raise_error(EOFError)
|
87
|
+
|
88
|
+
res = Net::HTTP.start(server.host, server.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do |https|
|
89
|
+
https.get('/')
|
90
|
+
end
|
91
|
+
|
92
|
+
expect(res.body).to include('Hello SSL Server!')
|
93
|
+
ensure
|
94
|
+
Capybara.server = :default
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
76
98
|
context "When Capybara.reuse_server is true" do
|
77
99
|
before do
|
78
100
|
@old_reuse_server = Capybara.reuse_server
|
@@ -189,10 +211,26 @@ RSpec.describe Capybara::Server do
|
|
189
211
|
it "is not #responsive? when Net::HTTP raises a SystemCallError" do
|
190
212
|
app = -> { [200, {}, ['Hello, world']] }
|
191
213
|
server = Capybara::Server.new(app)
|
192
|
-
|
214
|
+
allow(Net::HTTP).to receive(:start).and_raise(SystemCallError.allocate)
|
193
215
|
expect(server.responsive?).to eq false
|
194
216
|
end
|
195
217
|
|
218
|
+
[EOFError, Net::ReadTimeout].each do |err|
|
219
|
+
it "should attempt an HTTPS connection if HTTP connection returns #{err}" do
|
220
|
+
app = -> { [200, {}, ['Hello, world']] }
|
221
|
+
ordered_errors = [Errno::ECONNREFUSED, err]
|
222
|
+
# allow(Net::HTTP).to receive(:start).with(anything, anything, hash_excluding(:use_ssl)).and_yield { raise Errno::ECONNREFUSED }
|
223
|
+
allow(Net::HTTP).to receive(:start).with(anything, anything, hash_excluding(:use_ssl)) do
|
224
|
+
raise ordered_errors.shift
|
225
|
+
end
|
226
|
+
response = Net::HTTPSuccess.allocate
|
227
|
+
allow(response).to receive(:body).and_return app.object_id.to_s
|
228
|
+
allow(Net::HTTP).to receive(:start).with(anything, anything, hash_including(use_ssl: true)).and_return(response).once
|
229
|
+
Capybara::Server.new(app).boot
|
230
|
+
expect(Net::HTTP).to have_received(:start).exactly(3).times
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
196
234
|
def start_request(server, wait_time)
|
197
235
|
# Start request, but don't wait for it to finish
|
198
236
|
socket = TCPSocket.new(server.host, server.port)
|
data/spec/session_spec.rb
CHANGED
@@ -3,10 +3,18 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
RSpec.describe Capybara::Session do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
context "#new" do
|
7
|
+
it "should raise an error if passed non-existent driver" do
|
8
|
+
expect do
|
9
|
+
Capybara::Session.new(:quox, TestApp).driver
|
10
|
+
end.to raise_error(Capybara::DriverNotFoundError)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "verifies a passed app is a rack app" do
|
14
|
+
expect do
|
15
|
+
Capybara::Session.new(:unknown, random: "hash")
|
16
|
+
end.to raise_error TypeError, "The second parameter to Session::new should be a rack app if passed."
|
17
|
+
end
|
10
18
|
end
|
11
19
|
|
12
20
|
context "current_driver" do
|
@@ -7,27 +7,23 @@ RSpec.shared_examples "Capybara::Session" do |session, mode|
|
|
7
7
|
let(:session) { session }
|
8
8
|
|
9
9
|
context 'with selenium driver' do
|
10
|
-
before do
|
11
|
-
@session = session
|
12
|
-
end
|
13
|
-
|
14
10
|
describe '#driver' do
|
15
11
|
it "should be a selenium driver" do
|
16
|
-
expect(
|
12
|
+
expect(session.driver).to be_an_instance_of(Capybara::Selenium::Driver)
|
17
13
|
end
|
18
14
|
end
|
19
15
|
|
20
16
|
describe '#mode' do
|
21
17
|
it "should remember the mode" do
|
22
|
-
expect(
|
18
|
+
expect(session.mode).to eq(mode)
|
23
19
|
end
|
24
20
|
end
|
25
21
|
|
26
22
|
describe "#reset!" do
|
27
23
|
it "freshly reset session should not be touched" do
|
28
|
-
|
29
|
-
|
30
|
-
expect(
|
24
|
+
session.instance_variable_set(:@touched, true)
|
25
|
+
session.reset!
|
26
|
+
expect(session.instance_variable_get(:@touched)).to eq false
|
31
27
|
end
|
32
28
|
end
|
33
29
|
|
@@ -35,7 +31,7 @@ RSpec.shared_examples "Capybara::Session" do |session, mode|
|
|
35
31
|
before do
|
36
32
|
@current_dir = Dir.getwd
|
37
33
|
Dir.chdir(File.join(File.dirname(__FILE__), '..'))
|
38
|
-
@env = { 'SELENIUM_BROWSER' =>
|
34
|
+
@env = { 'SELENIUM_BROWSER' => session.driver.options[:browser].to_s }
|
39
35
|
end
|
40
36
|
|
41
37
|
after do
|
@@ -59,142 +55,167 @@ RSpec.shared_examples "Capybara::Session" do |session, mode|
|
|
59
55
|
|
60
56
|
describe "#accept_alert", requires: [:modals] do
|
61
57
|
it "supports a blockless mode" do
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
expect {
|
58
|
+
session.visit('/with_js')
|
59
|
+
session.click_link('Open alert')
|
60
|
+
session.accept_alert
|
61
|
+
expect { session.driver.browser.switch_to.alert }.to raise_error(session.driver.send(:modal_error))
|
66
62
|
end
|
67
63
|
|
68
64
|
it "can be called before visiting" do
|
69
|
-
|
70
|
-
|
65
|
+
session.accept_alert "Initial alert" do
|
66
|
+
session.visit('/initial_alert')
|
71
67
|
end
|
72
|
-
expect(
|
68
|
+
expect(session).to have_text('Initial alert page')
|
73
69
|
end
|
74
70
|
end
|
75
71
|
|
76
72
|
context '#fill_in_with empty string and no options' do
|
77
73
|
it 'should trigger change when clearing a field' do
|
78
|
-
|
79
|
-
|
74
|
+
session.visit('/with_js')
|
75
|
+
session.fill_in('with_change_event', with: '')
|
80
76
|
# click outside the field to trigger the change event
|
81
|
-
|
82
|
-
expect(
|
77
|
+
session.find(:css, 'body').click
|
78
|
+
expect(session).to have_selector(:css, '.change_event_triggered', match: :one)
|
83
79
|
end
|
84
80
|
end
|
85
81
|
|
86
82
|
context "#fill_in with { :clear => :backspace } fill_option", requires: [:js] do
|
87
83
|
it 'should fill in a field, replacing an existing value' do
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
expect(
|
84
|
+
session.visit('/form')
|
85
|
+
session.fill_in('form_first_name',
|
86
|
+
with: 'Harry',
|
87
|
+
fill_options: { clear: :backspace })
|
88
|
+
expect(session.find(:fillable_field, 'form_first_name').value).to eq('Harry')
|
93
89
|
end
|
94
90
|
|
95
91
|
it 'should only trigger onchange once' do
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
92
|
+
session.visit('/with_js')
|
93
|
+
session.fill_in('with_change_event',
|
94
|
+
with: 'some value',
|
95
|
+
fill_options: { clear: :backspace })
|
100
96
|
# click outside the field to trigger the change event
|
101
|
-
|
102
|
-
expect(
|
97
|
+
session.find(:css, 'body').click
|
98
|
+
expect(session.find(:css, '.change_event_triggered', match: :one)).to have_text 'some value'
|
103
99
|
end
|
104
100
|
|
105
101
|
it 'should trigger change when clearing field' do
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
102
|
+
session.visit('/with_js')
|
103
|
+
session.fill_in('with_change_event',
|
104
|
+
with: '',
|
105
|
+
fill_options: { clear: :backspace })
|
110
106
|
# click outside the field to trigger the change event
|
111
|
-
|
112
|
-
expect(
|
107
|
+
session.find(:css, 'body').click
|
108
|
+
expect(session).to have_selector(:css, '.change_event_triggered', match: :one)
|
113
109
|
end
|
114
110
|
|
115
111
|
it 'should trigger input event field_value.length times' do
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
112
|
+
session.visit('/with_js')
|
113
|
+
session.fill_in('with_change_event',
|
114
|
+
with: '',
|
115
|
+
fill_options: { clear: :backspace })
|
120
116
|
# click outside the field to trigger the change event
|
121
|
-
|
122
|
-
expect(
|
117
|
+
session.find(:css, 'body').click
|
118
|
+
expect(session).to have_xpath('//p[@class="input_event_triggered"]', count: 13)
|
123
119
|
end
|
124
120
|
end
|
125
121
|
|
126
122
|
context "#fill_in with { clear: :none } fill_options" do
|
127
123
|
it 'should append to content in a field' do
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
expect(
|
124
|
+
session.visit('/form')
|
125
|
+
session.fill_in('form_first_name',
|
126
|
+
with: 'Harry',
|
127
|
+
fill_options: { clear: :none })
|
128
|
+
expect(session.find(:fillable_field, 'form_first_name').value).to eq('JohnHarry')
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context '#fill_in with Date' do
|
133
|
+
before do
|
134
|
+
session.visit('/form')
|
135
|
+
session.execute_script <<-JS
|
136
|
+
window.capybara_formDateFiredEvents = [];
|
137
|
+
['focus', 'input', 'change'].forEach(function(eventType) {
|
138
|
+
document.getElementById('form_date')
|
139
|
+
.addEventListener(eventType, function() { window.capybara_formDateFiredEvents.push(eventType); });
|
140
|
+
});
|
141
|
+
JS
|
142
|
+
# work around weird FF issue where it would create an extra focus issue in some cases
|
143
|
+
session.find(:css, 'body').click
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should generate standard events on changing value" do
|
147
|
+
session.fill_in('form_date', with: Date.today)
|
148
|
+
expect(session.evaluate_script('window.capybara_formDateFiredEvents')).to eq %w[focus input change]
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should not generate input and change events if the value is not changed" do
|
152
|
+
session.fill_in('form_date', with: Date.today)
|
153
|
+
session.fill_in('form_date', with: Date.today)
|
154
|
+
# Chrome adds an extra focus for some reason - ok for now
|
155
|
+
expect(session.evaluate_script('window.capybara_formDateFiredEvents')).to eq(%w[focus input change])
|
133
156
|
end
|
134
157
|
end
|
135
158
|
|
136
159
|
context "#fill_in with { clear: Array } fill_options" do
|
137
160
|
it 'should pass the array through to the element' do
|
138
|
-
pending "selenium-webdriver/geckodriver doesn't support complex sets of characters" if marionette?(
|
161
|
+
pending "selenium-webdriver/geckodriver doesn't support complex sets of characters" if marionette?(session)
|
139
162
|
# this is mainly for use with [[:control, 'a'], :backspace] - however since that is platform dependant I'm testing with something less useful
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
expect(
|
163
|
+
session.visit('/form')
|
164
|
+
session.fill_in('form_first_name',
|
165
|
+
with: 'Harry',
|
166
|
+
fill_options: { clear: [[:shift, 'abc'], :backspace] })
|
167
|
+
expect(session.find(:fillable_field, 'form_first_name').value).to eq('JohnABHarry')
|
145
168
|
end
|
146
169
|
end
|
147
170
|
|
148
171
|
describe "#path" do
|
149
172
|
it "returns xpath" do
|
150
173
|
# this is here because it is testing for an XPath that is specific to the algorithm used in the selenium driver
|
151
|
-
|
152
|
-
element =
|
174
|
+
session.visit('/path')
|
175
|
+
element = session.find(:link, 'Second Link')
|
153
176
|
expect(element.path).to eq('/html/body/div[2]/a[1]')
|
154
177
|
end
|
155
178
|
end
|
156
179
|
|
157
180
|
describe "all with disappearing elements" do
|
158
181
|
it "ignores stale elements in results" do
|
159
|
-
|
160
|
-
elements =
|
182
|
+
session.visit('/path')
|
183
|
+
elements = session.all(:link) { |_node| raise Selenium::WebDriver::Error::StaleElementReferenceError }
|
161
184
|
expect(elements.size).to eq 0
|
162
185
|
end
|
163
186
|
end
|
164
187
|
|
165
188
|
describe "#evaluate_script" do
|
166
189
|
it "can return an element" do
|
167
|
-
|
168
|
-
element =
|
169
|
-
expect(element).to eq
|
190
|
+
session.visit('/form')
|
191
|
+
element = session.evaluate_script("document.getElementById('form_title')")
|
192
|
+
expect(element).to eq session.find(:id, 'form_title')
|
170
193
|
end
|
171
194
|
|
172
195
|
it "can return arrays of nested elements" do
|
173
|
-
|
174
|
-
elements =
|
175
|
-
elements.
|
176
|
-
|
177
|
-
end
|
178
|
-
expect(elements).to eq @session.find(:css, '#form_city').all(:css, 'option').to_a
|
196
|
+
session.visit('/form')
|
197
|
+
elements = session.evaluate_script('document.querySelectorAll("#form_city option")')
|
198
|
+
expect(elements).to all(be_instance_of Capybara::Node::Element)
|
199
|
+
expect(elements).to eq session.find(:css, '#form_city').all(:css, 'option').to_a
|
179
200
|
end
|
180
201
|
|
181
202
|
it "can return hashes with elements" do
|
182
|
-
|
183
|
-
result =
|
203
|
+
session.visit('/form')
|
204
|
+
result = session.evaluate_script("{ a: document.getElementById('form_title'), b: {c: document.querySelectorAll('#form_city option')}}")
|
184
205
|
expect(result).to eq(
|
185
|
-
'a' =>
|
206
|
+
'a' => session.find(:id, 'form_title'),
|
186
207
|
'b' => {
|
187
|
-
'c' =>
|
208
|
+
'c' => session.find(:css, '#form_city').all(:css, 'option').to_a
|
188
209
|
}
|
189
210
|
)
|
190
211
|
end
|
191
212
|
|
192
213
|
describe "#evaluate_async_script" do
|
193
214
|
it "will timeout if the script takes too long" do
|
194
|
-
|
215
|
+
session.visit('/with_js')
|
195
216
|
expect do
|
196
|
-
|
197
|
-
|
217
|
+
session.using_wait_time(1) do
|
218
|
+
session.evaluate_async_script("var cb = arguments[0]; setTimeout(function(){ cb(null) }, 3000)")
|
198
219
|
end
|
199
220
|
end.to raise_error Selenium::WebDriver::Error::ScriptTimeoutError
|
200
221
|
end
|
@@ -203,27 +224,28 @@ RSpec.shared_examples "Capybara::Session" do |session, mode|
|
|
203
224
|
|
204
225
|
describe "Element#inspect" do
|
205
226
|
it "outputs obsolete elements" do
|
206
|
-
|
207
|
-
el =
|
208
|
-
expect(
|
209
|
-
|
227
|
+
session.visit('/form')
|
228
|
+
el = session.find(:button, 'Click me!').click
|
229
|
+
expect(session).to have_no_button('Click me!')
|
230
|
+
allow(el).to receive(:synchronize)
|
210
231
|
expect(el.inspect).to eq "Obsolete #<Capybara::Node::Element>"
|
232
|
+
expect(el).not_to have_received(:synchronize)
|
211
233
|
end
|
212
234
|
end
|
213
235
|
|
214
236
|
describe "Element#click" do
|
215
237
|
it "should handle fixed headers/footers" do
|
216
|
-
|
217
|
-
#
|
218
|
-
|
219
|
-
expect(
|
238
|
+
session.visit('/with_fixed_header_footer')
|
239
|
+
# session.click_link('Go to root')
|
240
|
+
session.find(:link, 'Go to root').click
|
241
|
+
expect(session).to have_current_path('/')
|
220
242
|
end
|
221
243
|
end
|
222
244
|
|
223
245
|
context "Windows" do
|
224
246
|
it "can't close the primary window" do
|
225
247
|
expect do
|
226
|
-
|
248
|
+
session.current_window.close
|
227
249
|
end.to raise_error(ArgumentError, 'Not allowed to close the primary window')
|
228
250
|
end
|
229
251
|
end
|