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