capybara 3.10.1 → 3.11.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 +13 -0
- data/README.md +2 -3
- data/lib/capybara.rb +16 -6
- data/lib/capybara/minitest.rb +8 -9
- data/lib/capybara/node/actions.rb +31 -28
- data/lib/capybara/node/base.rb +2 -1
- data/lib/capybara/node/document_matchers.rb +6 -2
- data/lib/capybara/node/element.rb +10 -10
- data/lib/capybara/node/finders.rb +13 -14
- data/lib/capybara/node/matchers.rb +1 -3
- data/lib/capybara/node/simple.rb +10 -2
- data/lib/capybara/queries/base_query.rb +7 -3
- data/lib/capybara/queries/selector_query.rb +60 -34
- data/lib/capybara/queries/style_query.rb +5 -1
- data/lib/capybara/queries/text_query.rb +2 -2
- data/lib/capybara/queries/title_query.rb +1 -1
- data/lib/capybara/rack_test/node.rb +16 -2
- data/lib/capybara/result.rb +9 -4
- data/lib/capybara/rspec/features.rb +4 -4
- data/lib/capybara/rspec/matcher_proxies.rb +3 -1
- data/lib/capybara/rspec/matchers.rb +25 -287
- data/lib/capybara/rspec/matchers/base.rb +98 -0
- data/lib/capybara/rspec/matchers/become_closed.rb +33 -0
- data/lib/capybara/rspec/matchers/compound.rb +88 -0
- data/lib/capybara/rspec/matchers/have_current_path.rb +29 -0
- data/lib/capybara/rspec/matchers/have_selector.rb +69 -0
- data/lib/capybara/rspec/matchers/have_style.rb +23 -0
- data/lib/capybara/rspec/matchers/have_text.rb +33 -0
- data/lib/capybara/rspec/matchers/have_title.rb +29 -0
- data/lib/capybara/rspec/matchers/match_selector.rb +27 -0
- data/lib/capybara/selector.rb +48 -20
- data/lib/capybara/selector/builders/xpath_builder.rb +3 -3
- data/lib/capybara/selector/css.rb +5 -5
- data/lib/capybara/selector/filters/base.rb +11 -3
- data/lib/capybara/selector/filters/expression_filter.rb +3 -3
- data/lib/capybara/selector/filters/node_filter.rb +16 -2
- data/lib/capybara/selector/regexp_disassembler.rb +116 -17
- data/lib/capybara/selector/selector.rb +52 -26
- data/lib/capybara/selenium/driver.rb +6 -2
- data/lib/capybara/selenium/node.rb +15 -14
- data/lib/capybara/selenium/nodes/marionette_node.rb +19 -5
- data/lib/capybara/selenium/patches/pause_duration_fix.rb +1 -3
- data/lib/capybara/server.rb +6 -1
- data/lib/capybara/server/animation_disabler.rb +1 -1
- data/lib/capybara/session.rb +4 -2
- data/lib/capybara/session/matchers.rb +7 -3
- data/lib/capybara/spec/public/test.js +5 -5
- data/lib/capybara/spec/session/all_spec.rb +5 -0
- data/lib/capybara/spec/session/has_css_spec.rb +4 -4
- data/lib/capybara/spec/session/has_field_spec.rb +17 -0
- data/lib/capybara/spec/session/node_spec.rb +45 -4
- data/lib/capybara/spec/spec_helper.rb +6 -1
- data/lib/capybara/spec/views/frame_child.erb +1 -1
- data/lib/capybara/spec/views/obscured.erb +44 -0
- data/lib/capybara/spec/views/with_html.erb +1 -1
- data/lib/capybara/version.rb +1 -1
- data/spec/rack_test_spec.rb +15 -0
- data/spec/regexp_dissassembler_spec.rb +88 -8
- data/spec/selector_spec.rb +3 -0
- data/spec/selenium_spec_chrome.rb +9 -15
- data/spec/selenium_spec_chrome_remote.rb +3 -2
- data/spec/selenium_spec_firefox_remote.rb +6 -2
- metadata +54 -3
- data/lib/capybara/rspec/compound.rb +0 -86
@@ -225,7 +225,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base
|
|
225
225
|
::Selenium::WebDriver::Error::StaleElementReferenceError,
|
226
226
|
::Selenium::WebDriver::Error::UnhandledError,
|
227
227
|
::Selenium::WebDriver::Error::ElementNotVisibleError,
|
228
|
-
::Selenium::WebDriver::Error::InvalidSelectorError, # Work around a
|
228
|
+
::Selenium::WebDriver::Error::InvalidSelectorError, # Work around a chromedriver go_back/go_forward race condition
|
229
229
|
::Selenium::WebDriver::Error::ElementNotInteractableError,
|
230
230
|
::Selenium::WebDriver::Error::ElementClickInterceptedError,
|
231
231
|
::Selenium::WebDriver::Error::InvalidElementStateError,
|
@@ -352,11 +352,15 @@ private
|
|
352
352
|
when :chrome
|
353
353
|
extend ChromeDriver
|
354
354
|
when :firefox
|
355
|
-
require 'capybara/selenium/patches/pause_duration_fix' if
|
355
|
+
require 'capybara/selenium/patches/pause_duration_fix' if pause_broken?(sel_driver)
|
356
356
|
extend MarionetteDriver if sel_driver.capabilities.is_a?(::Selenium::WebDriver::Remote::W3C::Capabilities)
|
357
357
|
end
|
358
358
|
end
|
359
359
|
|
360
|
+
def pause_broken?(driver)
|
361
|
+
driver.capabilities['moz:geckodriverVersion']&.start_with?('0.22.')
|
362
|
+
end
|
363
|
+
|
360
364
|
def setup_exit_handler
|
361
365
|
main = Process.pid
|
362
366
|
at_exit do
|
@@ -170,22 +170,9 @@ class Capybara::Selenium::Node < Capybara::Driver::Node
|
|
170
170
|
selector = node[:tagName]
|
171
171
|
if node[:namespaceURI] != default_ns
|
172
172
|
selector = XPath.child.where((XPath.local_name == selector) & (XPath.namespace_uri == node[:namespaceURI])).to_s
|
173
|
-
selector
|
174
173
|
end
|
175
174
|
|
176
|
-
if parent
|
177
|
-
siblings = parent.find_xpath(selector)
|
178
|
-
selector += case siblings.size
|
179
|
-
when 0
|
180
|
-
'[ERROR]' # IE doesn't support full XPath (namespace-uri, etc)
|
181
|
-
when 1
|
182
|
-
'' # index not necessary when only one matching element
|
183
|
-
else
|
184
|
-
idx = siblings.index(node)
|
185
|
-
# Element may not be found in the siblings if it has gone away
|
186
|
-
idx.nil? ? '[ERROR]' : "[#{idx + 1}]"
|
187
|
-
end
|
188
|
-
end
|
175
|
+
selector += sibling_index(parent, node, selector) if parent
|
189
176
|
result.push selector
|
190
177
|
end
|
191
178
|
|
@@ -203,6 +190,20 @@ protected
|
|
203
190
|
|
204
191
|
private
|
205
192
|
|
193
|
+
def sibling_index(parent, node, selector)
|
194
|
+
siblings = parent.find_xpath(selector)
|
195
|
+
case siblings.size
|
196
|
+
when 0
|
197
|
+
'[ERROR]' # IE doesn't support full XPath (namespace-uri, etc)
|
198
|
+
when 1
|
199
|
+
'' # index not necessary when only one matching element
|
200
|
+
else
|
201
|
+
idx = siblings.index(node)
|
202
|
+
# Element may not be found in the siblings if it has gone away
|
203
|
+
idx.nil? ? '[ERROR]' : "[#{idx + 1}]"
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
206
207
|
def boolean_attr(val)
|
207
208
|
val && (val != 'false')
|
208
209
|
end
|
@@ -9,8 +9,9 @@ class Capybara::Selenium::MarionetteNode < Capybara::Selenium::Node
|
|
9
9
|
super
|
10
10
|
rescue ::Selenium::WebDriver::Error::ElementNotInteractableError
|
11
11
|
if tag_name == 'tr'
|
12
|
-
warn 'You are attempting to click a table row which has issues in geckodriver/marionette -
|
13
|
-
'Your test should probably be
|
12
|
+
warn 'You are attempting to click a table row which has issues in geckodriver/marionette - '\
|
13
|
+
'see https://github.com/mozilla/geckodriver/issues/1228. Your test should probably be '\
|
14
|
+
'clicking on a table cell like a user would. Clicking the first cell in the row instead.'
|
14
15
|
return find_css('th:first-child,td:first-child')[0].click(keys, options)
|
15
16
|
end
|
16
17
|
raise
|
@@ -26,7 +27,7 @@ class Capybara::Selenium::MarionetteNode < Capybara::Selenium::Node
|
|
26
27
|
if %w[option optgroup].include? tag_name
|
27
28
|
find_xpath('parent::*[self::optgroup or self::select]')[0].disabled?
|
28
29
|
else
|
29
|
-
!find_xpath(
|
30
|
+
!find_xpath(DISABLED_BY_FIELDSET_XPATH).empty?
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
@@ -99,14 +100,27 @@ private
|
|
99
100
|
return nil unless local_file
|
100
101
|
raise ArgumentError, "You may only upload files: #{local_file.inspect}" unless File.file?(local_file)
|
101
102
|
|
102
|
-
|
103
|
-
|
103
|
+
file = ::Selenium::WebDriver::Zipper.zip_file(local_file)
|
104
|
+
bridge.http.call(:post, "session/#{bridge.session_id}/file", file: file)['value']
|
104
105
|
end
|
105
106
|
|
106
107
|
def browser_version
|
107
108
|
driver.browser.capabilities[:browser_version].to_f
|
108
109
|
end
|
109
110
|
|
111
|
+
DISABLED_BY_FIELDSET_XPATH = XPath.generate do |x|
|
112
|
+
x.parent(:fieldset)[
|
113
|
+
x.attr(:disabled)
|
114
|
+
] + x.ancestor[
|
115
|
+
~x.self(:legned) |
|
116
|
+
x.preceding_sibling(:legend)
|
117
|
+
][
|
118
|
+
x.parent(:fieldset)[
|
119
|
+
x.attr(:disabled)
|
120
|
+
]
|
121
|
+
]
|
122
|
+
end.to_s.freeze
|
123
|
+
|
110
124
|
class ModifierKeysStack
|
111
125
|
def initialize
|
112
126
|
@stack = []
|
data/lib/capybara/server.rb
CHANGED
@@ -18,7 +18,12 @@ module Capybara
|
|
18
18
|
|
19
19
|
attr_reader :app, :port, :host
|
20
20
|
|
21
|
-
def initialize(app,
|
21
|
+
def initialize(app,
|
22
|
+
*deprecated_options,
|
23
|
+
port: Capybara.server_port,
|
24
|
+
host: Capybara.server_host,
|
25
|
+
reportable_errors: Capybara.server_errors,
|
26
|
+
extra_middleware: [])
|
22
27
|
warn 'Positional arguments, other than the application, to Server#new are deprecated, please use keyword arguments' unless deprecated_options.empty?
|
23
28
|
@app = app
|
24
29
|
@extra_middleware = extra_middleware
|
@@ -16,7 +16,7 @@ module Capybara
|
|
16
16
|
|
17
17
|
def initialize(app)
|
18
18
|
@app = app
|
19
|
-
@disable_markup = format(DISABLE_MARKUP_TEMPLATE, selector:
|
19
|
+
@disable_markup = format(DISABLE_MARKUP_TEMPLATE, selector: self.class.selector_for(Capybara.disable_animation))
|
20
20
|
end
|
21
21
|
|
22
22
|
def call(env)
|
data/lib/capybara/session.rb
CHANGED
@@ -43,7 +43,7 @@ module Capybara
|
|
43
43
|
click_link_or_button click_button click_link
|
44
44
|
fill_in find find_all find_button find_by_id find_field find_link
|
45
45
|
has_content? has_text? has_css? has_no_content? has_no_text?
|
46
|
-
has_no_css? has_no_xpath?
|
46
|
+
has_no_css? has_no_xpath? has_xpath? select uncheck
|
47
47
|
has_link? has_no_link? has_button? has_no_button? has_field?
|
48
48
|
has_no_field? has_checked_field? has_unchecked_field?
|
49
49
|
has_no_table? has_table? unselect has_select? has_no_select?
|
@@ -819,7 +819,9 @@ module Capybara
|
|
819
819
|
end
|
820
820
|
|
821
821
|
def prepare_path(path, extension)
|
822
|
-
File.expand_path(path || default_fn(extension), config.save_path).tap
|
822
|
+
File.expand_path(path || default_fn(extension), config.save_path).tap do |p_path|
|
823
|
+
FileUtils.mkdir_p(File.dirname(p_path))
|
824
|
+
end
|
823
825
|
end
|
824
826
|
|
825
827
|
def default_fn(extension)
|
@@ -6,7 +6,7 @@ module Capybara
|
|
6
6
|
# Asserts that the page has the given path.
|
7
7
|
# By default, if passed a full url this will compare against the full url,
|
8
8
|
# if passed a path only the path+query portion will be compared, if passed a regexp
|
9
|
-
# the comparison will depend on the :url option
|
9
|
+
# the comparison will depend on the :url option (path+query by default)
|
10
10
|
#
|
11
11
|
# @!macro current_path_query_params
|
12
12
|
# @overload $0(string, **options)
|
@@ -20,7 +20,9 @@ module Capybara
|
|
20
20
|
# @return [true]
|
21
21
|
#
|
22
22
|
def assert_current_path(path, **options)
|
23
|
-
_verify_current_path(path, options)
|
23
|
+
_verify_current_path(path, options) do |query|
|
24
|
+
raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
|
25
|
+
end
|
24
26
|
end
|
25
27
|
|
26
28
|
##
|
@@ -34,7 +36,9 @@ module Capybara
|
|
34
36
|
# @return [true]
|
35
37
|
#
|
36
38
|
def assert_no_current_path(path, **options)
|
37
|
-
_verify_current_path(path, options)
|
39
|
+
_verify_current_path(path, options) do |query|
|
40
|
+
raise Capybara::ExpectationNotMet, query.negative_failure_message if query.resolves_for?(self)
|
41
|
+
end
|
38
42
|
end
|
39
43
|
|
40
44
|
##
|
@@ -159,25 +159,25 @@ $(function() {
|
|
159
159
|
$(this).attr('confirmed', 'false');
|
160
160
|
}
|
161
161
|
}
|
162
|
-
})
|
162
|
+
});
|
163
163
|
$('#delayed-page-change').click(function() {
|
164
164
|
setTimeout(function() {
|
165
165
|
window.location.pathname = '/with_html'
|
166
166
|
}, 500)
|
167
|
-
})
|
167
|
+
});
|
168
168
|
$('#with-key-events').keydown(function(e){
|
169
169
|
$('#key-events-output').append('keydown:'+e.which+' ')
|
170
170
|
});
|
171
171
|
$('#disable-on-click').click(function(e){
|
172
|
-
var input = this
|
172
|
+
var input = this;
|
173
173
|
setTimeout(function() {
|
174
174
|
input.disabled = true;
|
175
175
|
}, 500)
|
176
|
-
})
|
176
|
+
});
|
177
177
|
$('#set-storage').click(function(e){
|
178
178
|
sessionStorage.setItem('session', 'session_value');
|
179
179
|
localStorage.setItem('local', 'local value');
|
180
|
-
})
|
180
|
+
});
|
181
181
|
$('#multiple-file').change(function(e){
|
182
182
|
$('body').append($('<p class="file_change"input_event_triggered">File input changed</p>'));
|
183
183
|
})
|
@@ -56,6 +56,11 @@ Capybara::SpecHelper.spec '#all' do
|
|
56
56
|
expect(@session.all(:xpath, '//h1').first.text).to eq('This is a test')
|
57
57
|
expect(@session.all(:xpath, "//input[@id='test_field']").first.value).to eq('monkey')
|
58
58
|
end
|
59
|
+
|
60
|
+
it 'should use alternated regex for :id' do
|
61
|
+
expect(@session.all(:xpath, './/h2', id: /h2/).unfiltered_size).to eq 3
|
62
|
+
expect(@session.all(:xpath, './/h2', id: /h2(one|two)/).unfiltered_size).to eq 2
|
63
|
+
end
|
59
64
|
end
|
60
65
|
|
61
66
|
context 'with css as default selector' do
|
@@ -50,17 +50,17 @@ Capybara::SpecHelper.spec '#has_css?' do
|
|
50
50
|
it 'should be able to generate an error message if the scope is a sibling' do
|
51
51
|
el = @session.find(:css, '#first')
|
52
52
|
@session.within el.sibling(:css, '#second') do
|
53
|
-
expect
|
53
|
+
expect do
|
54
54
|
expect(@session).to have_css('a#not_on_page')
|
55
|
-
|
55
|
+
end.to raise_error(/there were no matches/)
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'should be able to generate an error message if the scope is a sibling from XPath' do
|
60
60
|
el = @session.find(:css, '#first').find(:xpath, './following-sibling::*[1]') do
|
61
|
-
expect
|
61
|
+
expect do
|
62
62
|
expect(el).to have_css('a#not_on_page')
|
63
|
-
|
63
|
+
end.to raise_error(/there were no matches/)
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
@@ -41,6 +41,23 @@ Capybara::SpecHelper.spec '#has_field' do
|
|
41
41
|
expect(@session).not_to have_field('First Name', with: 'John')
|
42
42
|
expect(@session).not_to have_field('First Name', with: /John|Paul|George|Ringo/)
|
43
43
|
end
|
44
|
+
|
45
|
+
it 'should output filter errors if only one element matched the selector but failed the filters' do
|
46
|
+
@session.fill_in('First Name', with: 'Thomas')
|
47
|
+
expect do
|
48
|
+
expect(@session).to have_field('First Name', with: 'Jonas')
|
49
|
+
end.to raise_exception(RSpec::Expectations::ExpectationNotMetError, /Expected value to be "Jonas" but was "Thomas"/)
|
50
|
+
|
51
|
+
# native boolean node filter
|
52
|
+
expect do
|
53
|
+
expect(@session).to have_field('First Name', readonly: true)
|
54
|
+
end.to raise_exception(RSpec::Expectations::ExpectationNotMetError, /Expected readonly true but it wasn't/)
|
55
|
+
|
56
|
+
# inherited boolean node filter
|
57
|
+
expect do
|
58
|
+
expect(@session).to have_field('form_pets_cat', checked: true)
|
59
|
+
end.to raise_exception(RSpec::Expectations::ExpectationNotMetError, /Expected checked true but it wasn't/)
|
60
|
+
end
|
44
61
|
end
|
45
62
|
|
46
63
|
context 'with type' do
|
@@ -411,6 +411,33 @@ Capybara::SpecHelper.spec 'node' do
|
|
411
411
|
tr = @session.find(:css, '#agent_table tr:first-child').click
|
412
412
|
expect(tr).to have_css('label', text: 'Clicked')
|
413
413
|
end
|
414
|
+
|
415
|
+
it 'should retry clicking', requires: [:js] do
|
416
|
+
@session.visit('/obscured')
|
417
|
+
obscured = @session.find(:css, '#obscured')
|
418
|
+
@session.execute_script <<~JS
|
419
|
+
setTimeout(function(){ $('#cover').hide(); }, 1000)
|
420
|
+
JS
|
421
|
+
expect { obscured.click }.not_to raise_error
|
422
|
+
end
|
423
|
+
|
424
|
+
it 'should allow to retry longer', requires: [:js] do
|
425
|
+
@session.visit('/obscured')
|
426
|
+
obscured = @session.find(:css, '#obscured')
|
427
|
+
@session.execute_script <<~JS
|
428
|
+
setTimeout(function(){ $('#cover').hide(); }, 3000)
|
429
|
+
JS
|
430
|
+
expect { obscured.click(wait: 4) }.not_to raise_error
|
431
|
+
end
|
432
|
+
|
433
|
+
it 'should not retry clicking when wait is disabled', requires: [:js] do
|
434
|
+
@session.visit('/obscured')
|
435
|
+
obscured = @session.find(:css, '#obscured')
|
436
|
+
@session.execute_script <<~JS
|
437
|
+
setTimeout(function(){ $('#cover').hide(); }, 2000)
|
438
|
+
JS
|
439
|
+
expect { obscured.click(wait: 0) }.to(raise_error { |e| expect(e).to be_an_invalid_element_error(@session) })
|
440
|
+
end
|
414
441
|
end
|
415
442
|
|
416
443
|
describe '#double_click', requires: [:js] do
|
@@ -436,6 +463,15 @@ Capybara::SpecHelper.spec 'node' do
|
|
436
463
|
expect(locations[:x].to_f).to be_within(1).of(10)
|
437
464
|
expect(locations[:y].to_f).to be_within(1).of(5)
|
438
465
|
end
|
466
|
+
|
467
|
+
it 'should retry clicking', requires: [:js] do
|
468
|
+
@session.visit('/obscured')
|
469
|
+
obscured = @session.find(:css, '#obscured')
|
470
|
+
@session.execute_script <<~JS
|
471
|
+
setTimeout(function(){ $('#cover').hide(); }, 1000)
|
472
|
+
JS
|
473
|
+
expect { obscured.double_click }.not_to raise_error
|
474
|
+
end
|
439
475
|
end
|
440
476
|
|
441
477
|
describe '#right_click', requires: [:js] do
|
@@ -461,6 +497,15 @@ Capybara::SpecHelper.spec 'node' do
|
|
461
497
|
expect(locations[:x].to_f).to be_within(1).of(10)
|
462
498
|
expect(locations[:y].to_f).to be_within(1).of(10)
|
463
499
|
end
|
500
|
+
|
501
|
+
it 'should retry clicking', requires: [:js] do
|
502
|
+
@session.visit('/obscured')
|
503
|
+
obscured = @session.find(:css, '#obscured')
|
504
|
+
@session.execute_script <<~JS
|
505
|
+
setTimeout(function(){ $('#cover').hide(); }, 1000)
|
506
|
+
JS
|
507
|
+
expect { obscured.right_click }.not_to raise_error
|
508
|
+
end
|
464
509
|
end
|
465
510
|
|
466
511
|
describe '#send_keys', requires: [:send_keys] do
|
@@ -670,8 +715,4 @@ Capybara::SpecHelper.spec 'node' do
|
|
670
715
|
end)
|
671
716
|
end
|
672
717
|
end
|
673
|
-
|
674
|
-
def be_an_invalid_element_error(session)
|
675
|
-
satisfy { |error| session.driver.invalid_element_errors.any? { |e| error.is_a? e } }
|
676
|
-
end
|
677
718
|
end
|
@@ -117,7 +117,12 @@ module Capybara
|
|
117
117
|
|
118
118
|
def extract_results(session)
|
119
119
|
expect(session).to have_xpath("//pre[@id='results']")
|
120
|
-
YAML.load Nokogiri::HTML(session.body).xpath("//pre[@id='results']").first.inner_html.lstrip
|
120
|
+
# YAML.load Nokogiri::HTML(session.body).xpath("//pre[@id='results']").first.inner_html.lstrip
|
121
|
+
YAML.load Capybara::HTML(session.body).xpath("//pre[@id='results']").first.inner_html.lstrip
|
122
|
+
end
|
123
|
+
|
124
|
+
def be_an_invalid_element_error(session)
|
125
|
+
satisfy { |error| session.driver.invalid_element_errors.any? { |e| error.is_a? e } }
|
121
126
|
end
|
122
127
|
end
|
123
128
|
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
<title>This is the child frame title</title>
|
5
5
|
<script>
|
6
6
|
function closeWin() {
|
7
|
-
var iframe = window.parent.document.getElementById('childFrame')
|
7
|
+
var iframe = window.parent.document.getElementById('childFrame');
|
8
8
|
iframe.parentNode.removeChild(iframe)
|
9
9
|
}
|
10
10
|
</script>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
|
4
|
+
<title>with_animation</title>
|
5
|
+
<script src="/jquery.js" type="text/javascript" charset="utf-8"></script>
|
6
|
+
<style>
|
7
|
+
div {
|
8
|
+
width: 400px;
|
9
|
+
height: 400px;
|
10
|
+
position: absolute;
|
11
|
+
}
|
12
|
+
#obscured {
|
13
|
+
z-index: 1;
|
14
|
+
background-color: red;
|
15
|
+
}
|
16
|
+
#cover {
|
17
|
+
z-index: 2;
|
18
|
+
background-color: blue;
|
19
|
+
}
|
20
|
+
#offscreen {
|
21
|
+
top: 2000px;
|
22
|
+
left: 2000px;
|
23
|
+
background-color: green;
|
24
|
+
}
|
25
|
+
#offscreen_wrapper {
|
26
|
+
top: 2000px;
|
27
|
+
left: 2000px;
|
28
|
+
overflow-x: scroll;
|
29
|
+
background-color: yellow;
|
30
|
+
}
|
31
|
+
</style>
|
32
|
+
</head>
|
33
|
+
|
34
|
+
<body id="with_animation">
|
35
|
+
<div id="obscured">
|
36
|
+
<input id="obscured_input"/>
|
37
|
+
</div>
|
38
|
+
<div id="cover"></div>
|
39
|
+
<div id="offscreen_wrapper">
|
40
|
+
<div id="offscreen"></div>
|
41
|
+
</div>
|
42
|
+
</body>
|
43
|
+
</html>
|
44
|
+
|
@@ -10,7 +10,7 @@
|
|
10
10
|
<h2 class="no text"></h2>
|
11
11
|
<h2 class="head" id="h2one">Header Class Test One</h2>
|
12
12
|
<h2 class="head" id="h2two">Header Class Test Two</h2>
|
13
|
-
<h2 class="head">Header Class Test Three</h2>
|
13
|
+
<h2 class="head" id="h2_">Header Class Test Three</h2>
|
14
14
|
<h2 class="head">Header Class Test Four</h2>
|
15
15
|
<h2 class="head">Header Class Test Five</h2>
|
16
16
|
|