capybara 3.9.0 → 3.10.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 +15 -0
- data/License.txt +1 -1
- data/README.md +1 -1
- data/lib/capybara.rb +1 -2
- data/lib/capybara/helpers.rb +3 -2
- data/lib/capybara/minitest.rb +1 -1
- data/lib/capybara/minitest/spec.rb +1 -0
- data/lib/capybara/node/finders.rb +20 -15
- data/lib/capybara/node/matchers.rb +43 -10
- data/lib/capybara/queries/current_path_query.rb +2 -2
- data/lib/capybara/queries/selector_query.rb +9 -2
- data/lib/capybara/rack_test/browser.rb +14 -13
- data/lib/capybara/rack_test/form.rb +32 -27
- data/lib/capybara/result.rb +8 -11
- data/lib/capybara/rspec/compound.rb +16 -26
- data/lib/capybara/rspec/matcher_proxies.rb +28 -11
- data/lib/capybara/rspec/matchers.rb +67 -45
- data/lib/capybara/selector.rb +22 -25
- data/lib/capybara/selector/builders/css_builder.rb +3 -4
- data/lib/capybara/selector/builders/xpath_builder.rb +4 -6
- data/lib/capybara/selector/regexp_disassembler.rb +43 -44
- data/lib/capybara/selector/selector.rb +16 -11
- data/lib/capybara/selenium/driver.rb +28 -21
- data/lib/capybara/selenium/nodes/marionette_node.rb +6 -12
- data/lib/capybara/server.rb +1 -3
- data/lib/capybara/server/animation_disabler.rb +2 -2
- data/lib/capybara/session.rb +1 -1
- data/lib/capybara/spec/session/assert_all_of_selectors_spec.rb +29 -0
- data/lib/capybara/spec/session/click_button_spec.rb +6 -0
- data/lib/capybara/spec/session/click_link_spec.rb +1 -1
- data/lib/capybara/spec/session/has_all_selectors_spec.rb +1 -1
- data/lib/capybara/spec/session/has_any_selectors_spec.rb +25 -0
- data/lib/capybara/spec/session/html_spec.rb +7 -0
- data/lib/capybara/spec/session/node_spec.rb +5 -1
- data/lib/capybara/spec/session/refresh_spec.rb +4 -0
- data/lib/capybara/spec/session/window/switch_to_window_spec.rb +4 -0
- data/lib/capybara/spec/session/window/window_opened_by_spec.rb +4 -0
- data/lib/capybara/spec/session/window/window_spec.rb +4 -0
- data/lib/capybara/spec/session/window/windows_spec.rb +4 -0
- data/lib/capybara/spec/views/form.erb +2 -2
- data/lib/capybara/version.rb +1 -1
- data/spec/minitest_spec.rb +5 -1
- data/spec/minitest_spec_spec.rb +5 -1
- data/spec/regexp_dissassembler_spec.rb +5 -3
- data/spec/rspec_spec.rb +20 -0
- data/spec/selector_spec.rb +89 -3
- data/spec/selenium_spec_chrome.rb +3 -7
- data/spec/selenium_spec_marionette.rb +1 -4
- metadata +20 -6
- data/lib/capybara/xpath_patches.rb +0 -27
@@ -26,16 +26,14 @@ module Capybara
|
|
26
26
|
|
27
27
|
def class_conditions(classes)
|
28
28
|
case classes
|
29
|
-
when XPath::Expression
|
30
|
-
|
31
|
-
when Regexp
|
32
|
-
XPath.attr(:class)[regexp_to_xpath_conditions(classes)]
|
29
|
+
when XPath::Expression, Regexp
|
30
|
+
attribute_conditions(class: classes)
|
33
31
|
else
|
34
32
|
Array(classes).map do |klass|
|
35
|
-
if klass.start_with?('!')
|
33
|
+
if klass.start_with?('!') && !klass.start_with?('!!!')
|
36
34
|
!XPath.attr(:class).contains_word(klass.slice(1..-1))
|
37
35
|
else
|
38
|
-
XPath.attr(:class).contains_word(klass)
|
36
|
+
XPath.attr(:class).contains_word(klass.sub(/^!!/, ''))
|
39
37
|
end
|
40
38
|
end.reduce(:&)
|
41
39
|
end
|
@@ -1,66 +1,65 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'regexp_parser'
|
4
|
+
|
3
5
|
module Capybara
|
4
6
|
class Selector
|
5
7
|
# @api private
|
6
8
|
class RegexpDisassembler
|
7
9
|
def initialize(regexp)
|
8
10
|
@regexp = regexp
|
9
|
-
@regexp_source = regexp.source
|
10
11
|
end
|
11
12
|
|
12
13
|
def substrings
|
13
14
|
@substrings ||= begin
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
source.gsub!(/\\p\{[[:alpha:]]+\}?/, '.') # replace character properties with wildcard
|
18
|
-
source.gsub!(/\[\[:[a-z]+:\]\]/, '.') # replace posix classes with wildcard
|
19
|
-
while source.gsub!(/\[(?:[^\[\]]+)\]/, '.'); end # replace character classes with wildcard
|
20
|
-
source.gsub!(/\(\?<?[=!][^)]*\)/, '') # remove lookahead/lookbehind assertions
|
21
|
-
source.gsub!(/\(\?(?:<[^>]+>|>|:)/, '(') # replace named, atomic, and non-matching groups with unnamed matching groups
|
22
|
-
|
23
|
-
while source.gsub!(GROUP_REGEX) { |_m| simplify_group(Regexp.last_match) }; end
|
24
|
-
source.gsub!(/.[*?]\??/, '.') # replace optional character with wildcard
|
25
|
-
source.gsub!(/(.)\+\??/, '\1.') # replace one or more with character plus wildcard
|
26
|
-
source.gsub!(/(?<char>.)#{COUNTED_REP_REGEX.source}/) do |_m| # repeat counted characters
|
27
|
-
(Regexp.last_match[:char] * Regexp.last_match[:min_rep].to_i).tap { |str| str << '.' if Regexp.last_match[:max_rep] }
|
28
|
-
end
|
29
|
-
return [] if source.include?('|') # can't handle alternation here
|
30
|
-
|
31
|
-
strs = source.match(/\A\^?(.*?)\$?\Z/).captures[0].split('.').reject(&:empty?).uniq
|
32
|
-
strs = strs.map(&:upcase) if @regexp.casefold?
|
33
|
-
strs
|
15
|
+
strs = extract_strings(Regexp::Parser.parse(@regexp), [+''])
|
16
|
+
strs.map!(&:upcase) if @regexp.casefold?
|
17
|
+
strs.reject(&:empty?).uniq
|
34
18
|
end
|
35
19
|
end
|
36
20
|
|
37
21
|
private
|
38
22
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
matches[:group][1..-2]
|
50
|
-
end
|
23
|
+
def min_repeat(exp)
|
24
|
+
exp.quantifier&.min || 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def fixed_repeat?(exp)
|
28
|
+
min_repeat(exp) == (exp.quantifier&.max || 1)
|
29
|
+
end
|
30
|
+
|
31
|
+
def optional?(exp)
|
32
|
+
min_repeat(exp).zero?
|
51
33
|
end
|
52
34
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
)
|
62
|
-
|
63
|
-
|
35
|
+
def extract_strings(expression, strings)
|
36
|
+
expression.each do |exp|
|
37
|
+
if optional?(exp)
|
38
|
+
strings.push(+'')
|
39
|
+
next
|
40
|
+
end
|
41
|
+
|
42
|
+
if %i[meta set].include?(exp.type)
|
43
|
+
strings.push(+'')
|
44
|
+
next
|
45
|
+
end
|
46
|
+
|
47
|
+
if exp.terminal?
|
48
|
+
case exp.type
|
49
|
+
when :literal
|
50
|
+
strings.last << (exp.text * min_repeat(exp))
|
51
|
+
when :escape
|
52
|
+
strings.last << (exp.char * min_repeat(exp))
|
53
|
+
else
|
54
|
+
strings.push(+'')
|
55
|
+
end
|
56
|
+
else
|
57
|
+
min_repeat(exp).times { extract_strings(exp, strings) }
|
58
|
+
end
|
59
|
+
strings.push(+'') unless fixed_repeat?(exp)
|
60
|
+
end
|
61
|
+
strings
|
62
|
+
end
|
64
63
|
end
|
65
64
|
end
|
66
65
|
end
|
@@ -217,7 +217,7 @@ module Capybara
|
|
217
217
|
# Define a selector by an xpath expression
|
218
218
|
#
|
219
219
|
# @overload xpath(*expression_filters, &block)
|
220
|
-
# @param [Array<Symbol>] expression_filters ([]) Names of filters that
|
220
|
+
# @param [Array<Symbol>] expression_filters ([]) Names of filters that are implemented via this expression, if not specified the names of any keyword parameters in the block will be used
|
221
221
|
# @yield [locator, options] The block to use to generate the XPath expression
|
222
222
|
# @yieldparam [String] locator The locator string passed to the query
|
223
223
|
# @yieldparam [Hash] options The options hash passed to the query
|
@@ -227,11 +227,7 @@ module Capybara
|
|
227
227
|
# @return [#call] The block that will be called to generate the XPath expression
|
228
228
|
#
|
229
229
|
def xpath(*allowed_filters, &block)
|
230
|
-
|
231
|
-
@format, @expression = :xpath, block
|
232
|
-
allowed_filters.flatten.each { |ef| expression_filters[ef] = Filters::IdentityExpressionFilter.new(ef) }
|
233
|
-
end
|
234
|
-
format == :xpath ? @expression : nil
|
230
|
+
expression(:xpath, allowed_filters, &block)
|
235
231
|
end
|
236
232
|
|
237
233
|
##
|
@@ -249,11 +245,7 @@ module Capybara
|
|
249
245
|
# @return [#call] The block that will be called to generate the CSS selector
|
250
246
|
#
|
251
247
|
def css(*allowed_filters, &block)
|
252
|
-
|
253
|
-
@format, @expression = :css, block
|
254
|
-
allowed_filters.flatten.each { |ef| expression_filters[ef] = nil }
|
255
|
-
end
|
256
|
-
format == :css ? @expression : nil
|
248
|
+
expression(:css, allowed_filters, &block)
|
257
249
|
end
|
258
250
|
|
259
251
|
##
|
@@ -459,6 +451,19 @@ module Capybara
|
|
459
451
|
def find_by_class_attr(classes)
|
460
452
|
Array(classes).map { |klass| XPath.attr(:class).contains_word(klass) }.reduce(:&)
|
461
453
|
end
|
454
|
+
|
455
|
+
def parameter_names(block)
|
456
|
+
block.parameters.select { |(type, _name)| %i[key keyreq].include? type }.map { |(_type, name)| name }
|
457
|
+
end
|
458
|
+
|
459
|
+
def expression(type, allowed_filters, &block)
|
460
|
+
if block
|
461
|
+
@format, @expression = type, block
|
462
|
+
allowed_filters = parameter_names(block) if allowed_filters.empty?
|
463
|
+
allowed_filters.flatten.each { |ef| expression_filters[ef] = Filters::IdentityExpressionFilter.new(ef) }
|
464
|
+
end
|
465
|
+
format == type ? @expression : nil
|
466
|
+
end
|
462
467
|
end
|
463
468
|
end
|
464
469
|
|
@@ -107,33 +107,17 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
107
107
|
navigated = false
|
108
108
|
timer = Capybara::Helpers.timer(expire_in: 10)
|
109
109
|
begin
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
clear_browser_state
|
114
|
-
@browser.navigate.to('about:blank')
|
115
|
-
end
|
110
|
+
# Only trigger a navigation if we haven't done it already, otherwise it
|
111
|
+
# can trigger an endless series of unload modals
|
112
|
+
reset_browser_state unless navigated
|
116
113
|
navigated = true
|
117
|
-
|
118
114
|
# Ensure the page is empty and trigger an UnhandledAlertError for any modals that appear during unload
|
119
|
-
|
120
|
-
raise Capybara::ExpectationNotMet, 'Timed out waiting for Selenium session reset' if timer.expired?
|
121
|
-
|
122
|
-
sleep 0.05
|
123
|
-
end
|
115
|
+
wait_for_empty_page(timer)
|
124
116
|
rescue Selenium::WebDriver::Error::UnhandledAlertError, Selenium::WebDriver::Error::UnexpectedAlertOpenError
|
125
117
|
# This error is thrown if an unhandled alert is on the page
|
126
118
|
# Firefox appears to automatically dismiss this alert, chrome does not
|
127
119
|
# We'll try to accept it
|
128
|
-
|
129
|
-
@browser.switch_to.alert.accept
|
130
|
-
sleep 0.25 # allow time for the modal to be handled
|
131
|
-
rescue modal_error
|
132
|
-
# The alert is now gone.
|
133
|
-
# If navigation has not occurred attempt again and accept alert
|
134
|
-
# since FF may have dismissed the alert at first attempt.
|
135
|
-
navigate_with_accept('about:blank') if current_url != 'about:blank'
|
136
|
-
end
|
120
|
+
accept_unhandled_reset_alert
|
137
121
|
# try cleaning up the browser again
|
138
122
|
retry
|
139
123
|
end
|
@@ -382,6 +366,29 @@ private
|
|
382
366
|
exit @exit_status if @exit_status # Force exit with stored status
|
383
367
|
end
|
384
368
|
end
|
369
|
+
|
370
|
+
def reset_browser_state
|
371
|
+
clear_browser_state
|
372
|
+
@browser.navigate.to('about:blank')
|
373
|
+
end
|
374
|
+
|
375
|
+
def wait_for_empty_page(timer)
|
376
|
+
until find_xpath('/html/body/*').empty?
|
377
|
+
raise Capybara::ExpectationNotMet, 'Timed out waiting for Selenium session reset' if timer.expired?
|
378
|
+
|
379
|
+
sleep 0.05
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
def accept_unhandled_reset_alert
|
384
|
+
@browser.switch_to.alert.accept
|
385
|
+
sleep 0.25 # allow time for the modal to be handled
|
386
|
+
rescue modal_error
|
387
|
+
# The alert is now gone.
|
388
|
+
# If navigation has not occurred attempt again and accept alert
|
389
|
+
# since FF may have dismissed the alert at first attempt.
|
390
|
+
navigate_with_accept('about:blank') if current_url != 'about:blank'
|
391
|
+
end
|
385
392
|
end
|
386
393
|
|
387
394
|
require 'capybara/selenium/driver_specializations/chrome_driver'
|
@@ -36,16 +36,11 @@ class Capybara::Selenium::MarionetteNode < Capybara::Selenium::Node
|
|
36
36
|
return super if browser_version >= 62.0
|
37
37
|
|
38
38
|
# Workaround lack of support for multiple upload by uploading one at a time
|
39
|
-
path_names = value.to_s.empty? ? [] : value
|
40
|
-
|
41
|
-
|
42
|
-
if (fd = bridge.file_detector)
|
43
|
-
local_file = fd.call([path])
|
44
|
-
path = upload(local_file) if local_file
|
45
|
-
end
|
46
|
-
end
|
47
|
-
native.send_keys(path)
|
39
|
+
path_names = value.to_s.empty? ? [] : Array(value)
|
40
|
+
if (fd = bridge.file_detector) && !driver.browser.respond_to?(:upload)
|
41
|
+
path_names.map! { |path| upload(fd.call([path])) || path }
|
48
42
|
end
|
43
|
+
path_names.each { |path| native.send_keys(path) }
|
49
44
|
end
|
50
45
|
|
51
46
|
def send_keys(*args)
|
@@ -101,9 +96,8 @@ private
|
|
101
96
|
end
|
102
97
|
|
103
98
|
def upload(local_file)
|
104
|
-
unless
|
105
|
-
|
106
|
-
end
|
99
|
+
return nil unless local_file
|
100
|
+
raise ArgumentError, "You may only upload files: #{local_file.inspect}" unless File.file?(local_file)
|
107
101
|
|
108
102
|
result = bridge.http.call(:post, "session/#{bridge.session_id}/file", file: Selenium::WebDriver::Zipper.zip_file(local_file))
|
109
103
|
result['value']
|
data/lib/capybara/server.rb
CHANGED
@@ -48,9 +48,7 @@ module Capybara
|
|
48
48
|
|
49
49
|
res = @checker.request { |http| http.get('/__identify__') }
|
50
50
|
|
51
|
-
if res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPRedirection)
|
52
|
-
return res.body == app.object_id.to_s
|
53
|
-
end
|
51
|
+
return res.body == app.object_id.to_s if res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPRedirection)
|
54
52
|
rescue SystemCallError, Net::ReadTimeout, OpenSSL::SSL::SSLError
|
55
53
|
false
|
56
54
|
end
|
@@ -16,7 +16,7 @@ module Capybara
|
|
16
16
|
|
17
17
|
def initialize(app)
|
18
18
|
@app = app
|
19
|
-
@disable_markup = DISABLE_MARKUP_TEMPLATE
|
19
|
+
@disable_markup = format(DISABLE_MARKUP_TEMPLATE, selector: AnimationDisabler.selector_for(Capybara.disable_animation))
|
20
20
|
end
|
21
21
|
|
22
22
|
def call(env)
|
@@ -46,7 +46,7 @@ module Capybara
|
|
46
46
|
DISABLE_MARKUP_TEMPLATE = <<~HTML
|
47
47
|
<script defer>(typeof jQuery !== 'undefined') && (jQuery.fx.off = true);</script>
|
48
48
|
<style>
|
49
|
-
|
49
|
+
%<selector>s {
|
50
50
|
transition: none !important;
|
51
51
|
animation-duration: 0s !important;
|
52
52
|
animation-delay: 0s !important;
|
data/lib/capybara/session.rb
CHANGED
@@ -49,7 +49,7 @@ module Capybara
|
|
49
49
|
has_no_table? has_table? unselect has_select? has_no_select?
|
50
50
|
has_selector? has_no_selector? click_on has_no_checked_field?
|
51
51
|
has_no_unchecked_field? query assert_selector assert_no_selector
|
52
|
-
assert_all_of_selectors assert_none_of_selectors
|
52
|
+
assert_all_of_selectors assert_none_of_selectors assert_any_of_selectors
|
53
53
|
refute_selector assert_text assert_no_text
|
54
54
|
].freeze
|
55
55
|
# @api private
|
@@ -19,6 +19,10 @@ Capybara::SpecHelper.spec '#assert_all_of_selectors' do
|
|
19
19
|
@session.assert_all_of_selectors('p a#foo', 'h2#h2two', 'h2#h2one')
|
20
20
|
end
|
21
21
|
|
22
|
+
it 'should support filter block' do
|
23
|
+
expect { @session.assert_all_of_selectors(:css, 'h2#h2one', 'h2#h2two') { |n| n[:id] == 'h2one' } }.to raise_error(Capybara::ElementNotFound, /custom filter block/)
|
24
|
+
end
|
25
|
+
|
22
26
|
context 'should respect scopes' do
|
23
27
|
it 'when used with `within`' do
|
24
28
|
@session.within "//p[@id='first']" do
|
@@ -109,3 +113,28 @@ Capybara::SpecHelper.spec '#assert_none_of_selectors' do
|
|
109
113
|
end
|
110
114
|
end
|
111
115
|
end
|
116
|
+
|
117
|
+
Capybara::SpecHelper.spec '#assert_any_of_selectors' do
|
118
|
+
before do
|
119
|
+
@session.visit('/with_html')
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should be true if any of the given selectors are on the page' do
|
123
|
+
@session.assert_any_of_selectors(:css, 'a#foo', 'h2#h2three')
|
124
|
+
@session.assert_any_of_selectors(:css, 'h2#h2three', 'a#foo')
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should be false if none of the given selectors are on the page' do
|
128
|
+
expect { @session.assert_any_of_selectors(:css, 'h2#h2three', 'h4#h4four') }.to raise_error(Capybara::ElementNotFound)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should use default selector' do
|
132
|
+
Capybara.default_selector = :css
|
133
|
+
expect { @session.assert_any_of_selectors('h2#h2three', 'h5#h5five') }.to raise_error(Capybara::ElementNotFound)
|
134
|
+
@session.assert_any_of_selectors('p a#foo', 'h2#h2two', 'h2#h2one')
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'should support filter block' do
|
138
|
+
expect { @session.assert_any_of_selectors(:css, 'h2#h2one', 'h2#h2two') { |_n| false } }.to raise_error(Capybara::ElementNotFound, /custom filter block/)
|
139
|
+
end
|
140
|
+
end
|
@@ -376,6 +376,12 @@ Capybara::SpecHelper.spec '#click_button' do
|
|
376
376
|
expect(@results['no_value']).not_to be_nil
|
377
377
|
end
|
378
378
|
|
379
|
+
it 'should send button in document order' do
|
380
|
+
@session.click_button('outside_button')
|
381
|
+
@results = extract_results(@session)
|
382
|
+
expect(@results.keys).to eq %w[for_form2 outside_button which_form post_count]
|
383
|
+
end
|
384
|
+
|
379
385
|
it 'should not send image buttons that were not clicked' do
|
380
386
|
@session.click_button('Click me!')
|
381
387
|
@results = extract_results(@session)
|
@@ -211,7 +211,7 @@ Capybara::SpecHelper.spec '#click_link' do
|
|
211
211
|
download_file = File.join(Capybara.save_path, 'download.csv')
|
212
212
|
expect(File).not_to exist(download_file)
|
213
213
|
@session.click_link('Download Me')
|
214
|
-
sleep 2
|
214
|
+
sleep 2 # allow time for file to download
|
215
215
|
expect(File).to exist(download_file)
|
216
216
|
FileUtils.rm_rf download_file
|
217
217
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Capybara::SpecHelper.spec '#have_any_of_selectors' do
|
4
|
+
before do
|
5
|
+
@session.visit('/with_html')
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should be true if any of the given selectors are on the page' do
|
9
|
+
expect(@session).to have_any_of_selectors(:css, 'p a#foo', 'h2#blah', 'h2#h2two')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should be false if none of the given selectors are not on the page' do
|
13
|
+
expect do
|
14
|
+
expect(@session).to have_any_of_selectors(:css, 'span a#foo', 'h2#h2nope', 'h2#h2one_no')
|
15
|
+
end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should use default selector' do
|
19
|
+
Capybara.default_selector = :css
|
20
|
+
expect(@session).to have_any_of_selectors('p a#foo', 'h2#h2two', 'a#not_on_page')
|
21
|
+
expect do
|
22
|
+
expect(@session).to have_any_of_selectors('p a#blah', 'h2#h2three')
|
23
|
+
end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
|
24
|
+
end
|
25
|
+
end
|
@@ -1,5 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Note: This file uses `sleep` to sync up parts of the tests. This is only implemented like this
|
4
|
+
# because of the methods being tested. In tests using Capybara this type of behavior should be implemented
|
5
|
+
# using Capybara provided assertions with builtin waiting behavior.
|
6
|
+
|
3
7
|
Capybara::SpecHelper.spec '#html' do
|
4
8
|
it 'should return the unmodified page body' do
|
5
9
|
@session.visit('/')
|
@@ -8,6 +12,7 @@ Capybara::SpecHelper.spec '#html' do
|
|
8
12
|
|
9
13
|
it 'should return the current state of the page', requires: [:js] do
|
10
14
|
@session.visit('/with_js')
|
15
|
+
sleep 1
|
11
16
|
expect(@session.html).to include('I changed it')
|
12
17
|
expect(@session.html).not_to include('This is text')
|
13
18
|
end
|
@@ -21,6 +26,7 @@ Capybara::SpecHelper.spec '#source' do
|
|
21
26
|
|
22
27
|
it 'should return the current state of the page', requires: [:js] do
|
23
28
|
@session.visit('/with_js')
|
29
|
+
sleep 1
|
24
30
|
expect(@session.source).to include('I changed it')
|
25
31
|
expect(@session.source).not_to include('This is text')
|
26
32
|
end
|
@@ -34,6 +40,7 @@ Capybara::SpecHelper.spec '#body' do
|
|
34
40
|
|
35
41
|
it 'should return the current state of the page', requires: [:js] do
|
36
42
|
@session.visit('/with_js')
|
43
|
+
sleep 1
|
37
44
|
expect(@session.body).to include('I changed it')
|
38
45
|
expect(@session.body).not_to include('This is text')
|
39
46
|
end
|