capybara 3.35.3 → 3.37.1

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.
Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +57 -1
  3. data/README.md +5 -1
  4. data/lib/capybara/config.rb +16 -4
  5. data/lib/capybara/driver/base.rb +4 -0
  6. data/lib/capybara/driver/node.rb +5 -1
  7. data/lib/capybara/dsl.rb +4 -10
  8. data/lib/capybara/helpers.rb +3 -12
  9. data/lib/capybara/minitest/spec.rb +2 -2
  10. data/lib/capybara/node/actions.rb +10 -5
  11. data/lib/capybara/node/document.rb +2 -2
  12. data/lib/capybara/node/element.rb +13 -2
  13. data/lib/capybara/node/finders.rb +9 -2
  14. data/lib/capybara/node/simple.rb +5 -1
  15. data/lib/capybara/queries/active_element_query.rb +18 -0
  16. data/lib/capybara/queries/ancestor_query.rb +2 -1
  17. data/lib/capybara/queries/current_path_query.rb +1 -1
  18. data/lib/capybara/queries/selector_query.rb +34 -8
  19. data/lib/capybara/queries/sibling_query.rb +2 -1
  20. data/lib/capybara/rack_test/browser.rb +56 -7
  21. data/lib/capybara/rack_test/driver.rb +4 -4
  22. data/lib/capybara/rack_test/node.rb +10 -7
  23. data/lib/capybara/registration_container.rb +0 -3
  24. data/lib/capybara/registrations/drivers.rb +3 -3
  25. data/lib/capybara/rspec/matcher_proxies.rb +3 -3
  26. data/lib/capybara/rspec/matchers/have_selector.rb +5 -5
  27. data/lib/capybara/rspec/matchers.rb +14 -14
  28. data/lib/capybara/selector/builders/css_builder.rb +1 -1
  29. data/lib/capybara/selector/builders/xpath_builder.rb +1 -1
  30. data/lib/capybara/selector/css.rb +1 -1
  31. data/lib/capybara/selector/definition/button.rb +9 -4
  32. data/lib/capybara/selector/definition/checkbox.rb +1 -1
  33. data/lib/capybara/selector/definition/file_field.rb +1 -1
  34. data/lib/capybara/selector/definition/fillable_field.rb +1 -1
  35. data/lib/capybara/selector/definition/radio_button.rb +1 -1
  36. data/lib/capybara/selector/definition.rb +3 -1
  37. data/lib/capybara/selector/filter_set.rb +4 -6
  38. data/lib/capybara/selector/selector.rb +5 -1
  39. data/lib/capybara/selector.rb +1 -0
  40. data/lib/capybara/selenium/driver.rb +25 -11
  41. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +1 -1
  42. data/lib/capybara/selenium/driver_specializations/edge_driver.rb +1 -1
  43. data/lib/capybara/selenium/driver_specializations/firefox_driver.rb +1 -1
  44. data/lib/capybara/selenium/node.rb +22 -8
  45. data/lib/capybara/selenium/nodes/chrome_node.rb +1 -1
  46. data/lib/capybara/selenium/nodes/edge_node.rb +1 -1
  47. data/lib/capybara/selenium/nodes/firefox_node.rb +1 -1
  48. data/lib/capybara/selenium/nodes/safari_node.rb +2 -2
  49. data/lib/capybara/server/animation_disabler.rb +35 -17
  50. data/lib/capybara/session/config.rb +1 -1
  51. data/lib/capybara/session.rb +20 -23
  52. data/lib/capybara/spec/session/active_element_spec.rb +31 -0
  53. data/lib/capybara/spec/session/all_spec.rb +9 -13
  54. data/lib/capybara/spec/session/assert_text_spec.rb +17 -17
  55. data/lib/capybara/spec/session/check_spec.rb +9 -0
  56. data/lib/capybara/spec/session/choose_spec.rb +6 -0
  57. data/lib/capybara/spec/session/find_spec.rb +6 -0
  58. data/lib/capybara/spec/session/has_any_selectors_spec.rb +4 -0
  59. data/lib/capybara/spec/session/has_button_spec.rb +24 -0
  60. data/lib/capybara/spec/session/has_current_path_spec.rb +2 -2
  61. data/lib/capybara/spec/session/has_field_spec.rb +25 -1
  62. data/lib/capybara/spec/session/has_link_spec.rb +30 -0
  63. data/lib/capybara/spec/session/has_select_spec.rb +4 -4
  64. data/lib/capybara/spec/session/has_selector_spec.rb +15 -0
  65. data/lib/capybara/spec/session/has_text_spec.rb +2 -6
  66. data/lib/capybara/spec/session/node_spec.rb +43 -1
  67. data/lib/capybara/spec/session/scroll_spec.rb +4 -4
  68. data/lib/capybara/spec/session/visit_spec.rb +20 -0
  69. data/lib/capybara/spec/session/window/window_spec.rb +1 -1
  70. data/lib/capybara/spec/spec_helper.rb +4 -3
  71. data/lib/capybara/spec/test_app.rb +66 -8
  72. data/lib/capybara/spec/views/animated.erb +1 -1
  73. data/lib/capybara/spec/views/form.erb +11 -3
  74. data/lib/capybara/spec/views/frame_child.erb +1 -1
  75. data/lib/capybara/spec/views/frame_one.erb +1 -1
  76. data/lib/capybara/spec/views/frame_parent.erb +1 -1
  77. data/lib/capybara/spec/views/frame_two.erb +1 -1
  78. data/lib/capybara/spec/views/initial_alert.erb +2 -1
  79. data/lib/capybara/spec/views/layout.erb +10 -0
  80. data/lib/capybara/spec/views/obscured.erb +1 -1
  81. data/lib/capybara/spec/views/offset.erb +2 -1
  82. data/lib/capybara/spec/views/path.erb +2 -2
  83. data/lib/capybara/spec/views/popup_one.erb +1 -1
  84. data/lib/capybara/spec/views/popup_two.erb +1 -1
  85. data/lib/capybara/spec/views/react.erb +2 -2
  86. data/lib/capybara/spec/views/scroll.erb +2 -1
  87. data/lib/capybara/spec/views/spatial.erb +1 -1
  88. data/lib/capybara/spec/views/with_animation.erb +2 -3
  89. data/lib/capybara/spec/views/with_base_tag.erb +2 -2
  90. data/lib/capybara/spec/views/with_dragula.erb +2 -2
  91. data/lib/capybara/spec/views/with_fixed_header_footer.erb +2 -1
  92. data/lib/capybara/spec/views/with_hover.erb +2 -2
  93. data/lib/capybara/spec/views/with_html.erb +1 -1
  94. data/lib/capybara/spec/views/with_jquery_animation.erb +1 -1
  95. data/lib/capybara/spec/views/with_js.erb +2 -3
  96. data/lib/capybara/spec/views/with_jstree.erb +1 -1
  97. data/lib/capybara/spec/views/with_namespace.erb +1 -0
  98. data/lib/capybara/spec/views/with_shadow.erb +31 -0
  99. data/lib/capybara/spec/views/with_slow_unload.erb +2 -1
  100. data/lib/capybara/spec/views/with_sortable_js.erb +2 -2
  101. data/lib/capybara/spec/views/with_unload_alert.erb +1 -0
  102. data/lib/capybara/spec/views/with_windows.erb +1 -1
  103. data/lib/capybara/spec/views/within_frames.erb +1 -1
  104. data/lib/capybara/version.rb +1 -1
  105. data/lib/capybara/window.rb +1 -1
  106. data/lib/capybara.rb +19 -22
  107. data/spec/basic_node_spec.rb +16 -3
  108. data/spec/dsl_spec.rb +3 -3
  109. data/spec/fixtures/selenium_driver_rspec_failure.rb +2 -2
  110. data/spec/fixtures/selenium_driver_rspec_success.rb +2 -2
  111. data/spec/rack_test_spec.rb +20 -10
  112. data/spec/result_spec.rb +32 -35
  113. data/spec/rspec/features_spec.rb +3 -3
  114. data/spec/rspec/scenarios_spec.rb +1 -1
  115. data/spec/rspec/shared_spec_matchers.rb +2 -2
  116. data/spec/sauce_spec_chrome.rb +3 -3
  117. data/spec/selector_spec.rb +2 -2
  118. data/spec/selenium_spec_chrome.rb +9 -10
  119. data/spec/selenium_spec_chrome_remote.rb +9 -8
  120. data/spec/selenium_spec_firefox.rb +8 -3
  121. data/spec/selenium_spec_firefox_remote.rb +2 -2
  122. data/spec/selenium_spec_ie.rb +3 -6
  123. data/spec/selenium_spec_safari.rb +31 -19
  124. data/spec/server_spec.rb +5 -5
  125. data/spec/shared_selenium_node.rb +0 -4
  126. data/spec/shared_selenium_session.rb +20 -10
  127. data/spec/spec_helper.rb +1 -1
  128. metadata +37 -14
  129. data/lib/capybara/spec/views/with_title.erb +0 -5
@@ -18,6 +18,24 @@ Capybara::SpecHelper.spec '#has_link?' do
18
18
  expect(@session).not_to have_link('A link', href: '/nonexistent-href')
19
19
  expect(@session).not_to have_link('A link', href: /nonexistent/)
20
20
  end
21
+
22
+ it 'should notify if an invalid locator is specified' do
23
+ allow(Capybara::Helpers).to receive(:warn).and_return(nil)
24
+ @session.has_link?(@session)
25
+ expect(Capybara::Helpers).to have_received(:warn).with(/Called from: .+/)
26
+ end
27
+
28
+ context 'with focused:', requires: [:active_element] do
29
+ it 'should be true if the given link is on the page and has focus' do
30
+ @session.send_keys(:tab)
31
+
32
+ expect(@session).to have_link('labore', focused: true)
33
+ end
34
+
35
+ it 'should be false if the given link is on the page and does not have focus' do
36
+ expect(@session).to have_link('labore', focused: false)
37
+ end
38
+ end
21
39
  end
22
40
 
23
41
  Capybara::SpecHelper.spec '#has_no_link?' do
@@ -36,4 +54,16 @@ Capybara::SpecHelper.spec '#has_no_link?' do
36
54
  expect(@session).to have_no_link('A link', href: '/nonexistent-href')
37
55
  expect(@session).to have_no_link('A link', href: %r{/nonexistent-href})
38
56
  end
57
+
58
+ context 'with focused:', requires: [:active_element] do
59
+ it 'should be true if the given link is on the page and has focus' do
60
+ expect(@session).to have_no_link('labore', focused: true)
61
+ end
62
+
63
+ it 'should be false if the given link is on the page and does not have focus' do
64
+ @session.send_keys(:tab)
65
+
66
+ expect(@session).to have_no_link('labore', focused: false)
67
+ end
68
+ end
39
69
  end
@@ -180,9 +180,9 @@ Capybara::SpecHelper.spec '#has_select?' do
180
180
  end
181
181
 
182
182
  it 'should support locator-less usage' do
183
- expect(@session.has_select?(with_options: %w[Norway Sweden])).to eq true
183
+ expect(@session.has_select?(with_options: %w[Norway Sweden])).to be true
184
184
  expect(@session).to have_select(with_options: ['London'])
185
- expect(@session.has_select?(with_selected: %w[Commando Boxerbriefs])).to eq true
185
+ expect(@session.has_select?(with_selected: %w[Commando Boxerbriefs])).to be true
186
186
  expect(@session).to have_select(with_selected: ['Briefs'])
187
187
  end
188
188
  end
@@ -302,9 +302,9 @@ Capybara::SpecHelper.spec '#has_no_select?' do
302
302
  end
303
303
 
304
304
  it 'should support locator-less usage' do
305
- expect(@session.has_no_select?(with_options: %w[Norway Sweden Finland Latvia])).to eq true
305
+ expect(@session.has_no_select?(with_options: %w[Norway Sweden Finland Latvia])).to be true
306
306
  expect(@session).to have_no_select(with_options: ['New London'])
307
- expect(@session.has_no_select?(id: 'form_underwear', with_selected: ['Boxers'])).to eq true
307
+ expect(@session.has_no_select?(id: 'form_underwear', with_selected: ['Boxers'])).to be true
308
308
  expect(@session).to have_no_select(id: 'form_underwear', with_selected: %w[Commando Boxers])
309
309
  end
310
310
  end
@@ -117,6 +117,21 @@ Capybara::SpecHelper.spec '#has_selector?' do
117
117
  expect(@session).to have_selector(:id, 'h2one', text: 'Header Class Test One', exact_text: false)
118
118
  expect(@session).to have_selector(:id, 'h2one', text: 'Header Class Test', exact_text: false)
119
119
  end
120
+
121
+ it 'should warn if text option is a regexp that it is ignoring exact_text' do
122
+ allow(Capybara::Helpers).to receive(:warn)
123
+ expect(@session).to have_selector(:id, 'h2one', text: /Class Test/, exact_text: true)
124
+ expect(Capybara::Helpers).to have_received(:warn).with(/'exact_text' option is not supported/)
125
+ end
126
+ end
127
+
128
+ context 'regexp' do
129
+ it 'should only match when it fully matches' do
130
+ expect(@session).to have_selector(:id, 'h2one', exact_text: /Header Class Test One/)
131
+ expect(@session).to have_no_selector(:id, 'h2one', exact_text: /Header Class Test/)
132
+ expect(@session).to have_no_selector(:id, 'h2one', exact_text: /Class Test One/)
133
+ expect(@session).to have_no_selector(:id, 'h2one', exact_text: /Class Test/)
134
+ end
120
135
  end
121
136
  end
122
137
 
@@ -127,11 +127,7 @@ Capybara::SpecHelper.spec '#has_text?' do
127
127
  def to_hash; { value: 'Other hash' } end
128
128
  end.new
129
129
  @session.visit('/with_html')
130
- if RUBY_VERSION >= '2.7'
131
- expect(@session).to have_text(:visible, with_to_hash, **{})
132
- else
133
- expect(@session).to have_text(:visible, with_to_hash, {})
134
- end
130
+ expect(@session).to have_text(:visible, with_to_hash, **{})
135
131
  end
136
132
  end
137
133
 
@@ -356,7 +352,7 @@ Capybara::SpecHelper.spec '#has_no_text?' do
356
352
  expect(@session).to have_no_text(/xxxxyzzz/)
357
353
  end
358
354
 
359
- it 'should be false if the text in the page matches given regexp' do
355
+ it 'should be false if the text in the page matches given regexp' do
360
356
  @session.visit('/with_html')
361
357
  expect(@session).not_to have_no_text(/Lorem/)
362
358
  end
@@ -1115,7 +1115,7 @@ Capybara::SpecHelper.spec 'node' do
1115
1115
  end
1116
1116
 
1117
1117
  describe '#evaluate_script', requires: %i[js es_args] do
1118
- it 'should evaluate the given script in the context of the element and return whatever it produces' do
1118
+ it 'should evaluate the given script in the context of the element and return whatever it produces' do
1119
1119
  @session.visit('/with_js')
1120
1120
  el = @session.find(:css, '#with_change_event')
1121
1121
  expect(el.evaluate_script('this.value')).to eq('default value')
@@ -1176,6 +1176,48 @@ Capybara::SpecHelper.spec 'node' do
1176
1176
  end
1177
1177
  end
1178
1178
 
1179
+ describe '#shadow_root', requires: %i[js] do
1180
+ it 'should get the shadow root' do
1181
+ @session.visit('/with_shadow')
1182
+ expect do
1183
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1184
+ expect(shadow_root).not_to be_nil
1185
+ end.not_to raise_error
1186
+ end
1187
+
1188
+ it 'should find elements inside the shadow dom using CSS' do
1189
+ @session.visit('/with_shadow')
1190
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1191
+ expect(shadow_root).to have_css('#shadow_content', text: 'some text')
1192
+ end
1193
+
1194
+ it 'should find nested shadow roots' do
1195
+ @session.visit('/with_shadow')
1196
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1197
+ nested_shadow_root = shadow_root.find(:css, '#nested_shadow_host').shadow_root
1198
+ expect(nested_shadow_root).to have_css('#nested_shadow_content', text: 'nested text')
1199
+ end
1200
+
1201
+ it 'should click on elements' do
1202
+ @session.visit('/with_shadow')
1203
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1204
+ checkbox = shadow_root.find(:css, 'input[type="checkbox"]')
1205
+ expect(checkbox).not_to be_checked
1206
+ checkbox.click
1207
+ expect(checkbox).to be_checked
1208
+ end
1209
+
1210
+ it 'should use convenience methods once moved to a descendant of the shadow root' do
1211
+ @session.visit('/with_shadow')
1212
+ shadow_root = @session.find(:css, '#shadow_host').shadow_root
1213
+ descendant = shadow_root.find(:css, '#controls_wrapper')
1214
+ expect do
1215
+ descendant.check('shadow_checkbox')
1216
+ end.not_to raise_error
1217
+ expect(descendant).to have_checked_field('shadow_checkbox')
1218
+ end
1219
+ end
1220
+
1179
1221
  describe '#reload', requires: [:js] do
1180
1222
  it 'should reload elements found via ancestor with CSS' do
1181
1223
  @session.visit('/with_js')
@@ -15,7 +15,7 @@ Capybara::SpecHelper.spec '#scroll_to', requires: [:scroll] do
15
15
  el = @session.find(:css, '#scroll')
16
16
  @session.scroll_to(el, align: :bottom)
17
17
  el_bottom = el.evaluate_script('this.getBoundingClientRect().bottom')
18
- viewport_bottom = el.evaluate_script('document.body.clientHeight')
18
+ viewport_bottom = el.evaluate_script('document.documentElement.clientHeight')
19
19
  expect(el_bottom).to be_within(1).of(viewport_bottom)
20
20
  end
21
21
 
@@ -23,7 +23,7 @@ Capybara::SpecHelper.spec '#scroll_to', requires: [:scroll] do
23
23
  el = @session.find(:css, '#scroll')
24
24
  @session.scroll_to(el, align: :center)
25
25
  el_center = el.evaluate_script('(function(rect){return (rect.top + rect.bottom)/2})(this.getBoundingClientRect())')
26
- viewport_bottom = el.evaluate_script('document.body.clientHeight')
26
+ viewport_bottom = el.evaluate_script('document.documentElement.clientHeight')
27
27
  expect(el_center).to be_within(2).of(viewport_bottom / 2)
28
28
  end
29
29
 
@@ -35,13 +35,13 @@ Capybara::SpecHelper.spec '#scroll_to', requires: [:scroll] do
35
35
 
36
36
  it 'can scroll the window to the vertical bottom' do
37
37
  @session.scroll_to :bottom
38
- max_scroll = @session.evaluate_script('document.body.scrollHeight - document.body.clientHeight')
38
+ max_scroll = @session.evaluate_script('document.documentElement.scrollHeight - document.documentElement.clientHeight')
39
39
  expect(@session.evaluate_script('[window.scrollX || window.pageXOffset, window.scrollY || window.pageYOffset]')).to eq [0, max_scroll]
40
40
  end
41
41
 
42
42
  it 'can scroll the window to the vertical center' do
43
43
  @session.scroll_to :center
44
- max_scroll = @session.evaluate_script('document.documentElement.scrollHeight - document.body.clientHeight')
44
+ max_scroll = @session.evaluate_script('document.documentElement.scrollHeight - document.documentElement.clientHeight')
45
45
  expect(@session.evaluate_script('[window.scrollX || window.pageXOffset, window.scrollY || window.pageYOffset]')).to eq [0, max_scroll / 2]
46
46
  end
47
47
 
@@ -201,4 +201,24 @@ Capybara::SpecHelper.spec '#visit' do
201
201
  @session.visit('/get_cookie')
202
202
  expect(@session).to have_content('root cookie')
203
203
  end
204
+
205
+ context 'with base element' do
206
+ it 'should use base href with relative links' do
207
+ @session.visit('/base/with_base')
208
+ @session.click_link('Title page')
209
+ expect(@session).to have_current_path('/with_title')
210
+ end
211
+
212
+ it 'should use base href with bare queries' do
213
+ @session.visit('/base/with_base')
214
+ @session.click_link('Bare query')
215
+ expect(@session).to have_current_path('/?a=3')
216
+ end
217
+
218
+ it 'should not use the base href with a new visit call' do
219
+ @session.visit('/base/with_other_base')
220
+ @session.visit('with_html')
221
+ expect(@session).to have_current_path('/with_html')
222
+ end
223
+ end
204
224
  end
@@ -59,7 +59,7 @@ Capybara::SpecHelper.spec Capybara::Window, requires: [:windows] do
59
59
  it 'should return false if window is closed' do
60
60
  @session.switch_to_window(other_window)
61
61
  other_window.close
62
- expect(other_window.current?).to eq(false)
62
+ expect(other_window.current?).to be(false)
63
63
  end
64
64
  end
65
65
 
@@ -36,7 +36,7 @@ module Capybara
36
36
  Capybara.test_id = nil
37
37
  Capybara.predicates_wait = true
38
38
  Capybara.default_normalize_ws = false
39
- Capybara.allow_gumbo = true
39
+ Capybara.use_html5_parsing = !ENV['HTML5_PARSING'].nil?
40
40
  Capybara.w3c_click_offset = false
41
41
  reset_threadsafe
42
42
  end
@@ -117,8 +117,9 @@ 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
121
- YAML.load Capybara::HTML(session.body).xpath("//pre[@id='results']").first.inner_html.lstrip
120
+ perms = [(::Sinatra::IndifferentHash if defined? ::Sinatra::IndifferentHash)].compact
121
+ results = Capybara::HTML(session.body).xpath("//pre[@id='results']").first.inner_html.lstrip
122
+ YAML.safe_load results, permitted_classes: perms
122
123
  end
123
124
 
124
125
  def be_an_invalid_element_error(session)
@@ -53,8 +53,8 @@ class TestApp < Sinatra::Base
53
53
 
54
54
  get '/referer_base' do
55
55
  '<a href="/get_referer">direct link</a>' \
56
- '<a href="/redirect_to_get_referer">link via redirect</a>' \
57
- '<form action="/get_referer" method="get"><input type="submit"></form>'
56
+ '<a href="/redirect_to_get_referer">link via redirect</a>' \
57
+ '<form action="/get_referer" method="get"><input type="submit"></form>'
58
58
  end
59
59
 
60
60
  get '/redirect_to_get_referer' do
@@ -163,21 +163,79 @@ class TestApp < Sinatra::Base
163
163
 
164
164
  get '/with_title' do
165
165
  <<-HTML
166
- <title>#{params[:title] || 'Test Title'}</title>
167
- <body>
168
- <svg><title>abcdefg</title></svg>
169
- </body>
166
+ <!DOCTYPE html>
167
+ <html lang="en">
168
+ <head>
169
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
170
+ <title>#{params[:title] || 'Test Title'}</title>
171
+ </head>
172
+
173
+ <body>
174
+ <svg><title>abcdefg</title></svg>
175
+ </body>
176
+ </html>
177
+ HTML
178
+ end
179
+
180
+ get '/base/with_base' do
181
+ <<-HTML
182
+ <!DOCTYPE html>
183
+ <html>
184
+ <head>
185
+ <base href="/">
186
+ <title>Origin</title>
187
+ </head>
188
+ <body>
189
+ <a href="with_title">Title page</a>
190
+ <a href="?a=3">Bare query</a>
191
+ </body>
192
+ </html>
193
+ HTML
194
+ end
195
+
196
+ get '/base/with_other_base' do
197
+ <<-HTML
198
+ <!DOCTYPE html>
199
+ <html>
200
+ <head>
201
+ <base href="/base/">
202
+ <title>Origin</title>
203
+ </head>
204
+ <body>
205
+ <a href="with_title">Title page</a>
206
+ <a href="?a=3">Bare query</a>
207
+ </body>
208
+ </html>
209
+ HTML
210
+ end
211
+
212
+ get '/csp' do
213
+ response.headers['Content-Security-Policy'] = "default-src 'none'; connect-src 'self'; base-uri 'none'; font-src 'self'; img-src 'self' data:; object-src 'none'; script-src 'self' 'nonce-jAviMuMisoTisVXjgLoWdA=='; style-src 'self' 'nonce-jAviMuMisoTisVXjgLoWdA=='; form-action 'self';"
214
+ <<-HTML
215
+ <!DOCTYPE html>
216
+ <html lang="en">
217
+ <head>
218
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
219
+ <title>CSP</title>
220
+ </head>
221
+
222
+ <body>
223
+ <div>CSP</div>
224
+ </body>
225
+ </html>
170
226
  HTML
171
227
  end
172
228
 
173
229
  get '/download.csv' do
174
230
  content_type 'text/csv'
175
231
  'This, is, comma, separated' \
176
- 'Thomas, Walpole, was , here'
232
+ 'Thomas, Walpole, was , here'
177
233
  end
178
234
 
179
235
  get '/:view' do |view|
180
- erb view.to_sym, locals: { referrer: request.referrer }
236
+ view_template = "#{__dir__}/views/#{view}.erb"
237
+ has_layout = File.exist?(view_template) && File.open(view_template) { |f| f.first.downcase.include?('doctype') }
238
+ erb view.to_sym, locals: { referrer: request.referrer }, layout: !has_layout
181
239
  end
182
240
 
183
241
  post '/form' do
@@ -1,3 +1,4 @@
1
+ <!DOCTYPE html>
1
2
  <html>
2
3
  <head>
3
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
@@ -46,4 +47,3 @@
46
47
 
47
48
  <iframe id="frameOne" src="/frame_one"></iframe>
48
49
  </html>
49
-
@@ -1,11 +1,17 @@
1
-
2
1
  <h1>Form</h1>
3
2
 
3
+ <button type="button" tabindex="1">A Button</button>
4
+
5
+ <label>
6
+ An Input
7
+ <input type="text" tabindex="2">
8
+ </label>
9
+
4
10
  <form action="/form" method="post" novalidate>
5
11
 
6
12
  <p>
7
13
  <label for="form_title">Title</label>
8
- <select name="form[title]" id="form_title" class="title">
14
+ <select name="form[title]" id="form_title" class="title" tabindex="3">
9
15
  <option class="title">Mrs</option>
10
16
  <option class="title">Mr</option>
11
17
  <option>Miss</option>
@@ -170,7 +176,7 @@ New line after and before textarea tag
170
176
  <label for="gender_male">Male</label>
171
177
  <input type="radio" name="form[gender]" value="female" id="gender_female" checked="checked"/>
172
178
  <label for="gender_female">Female</label>
173
- <input type="radio" name="form[gender]" value="both" id="gender_both"/>
179
+ <input type="radio" name="form[gender]" value="both" id="gender_both" readonly="readonly"/>
174
180
  <label for="gender_both">Both</label>
175
181
  </p>
176
182
 
@@ -223,6 +229,8 @@ New line after and before textarea tag
223
229
  </label>
224
230
  <input type="checkbox" value="maserati" name="form[cars][]" id="form_cars_maserati" disabled="disabled"/>
225
231
  <label for="form_cars_maserati">Maserati</label>
232
+ <input type="checkbox" value="lotus" name="form[cars][]" id="form_cars_lotus" style="display: none"/>
233
+ <label for="form_cars_lotus"><a href="#" onclick="return false;">Link here</a>Lotus</label>
226
234
  </p>
227
235
 
228
236
  <p>
@@ -1,4 +1,4 @@
1
-
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <title>This is the child frame title</title>
@@ -1,4 +1,4 @@
1
-
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <title>This is the title of frame one</title>
@@ -1,4 +1,4 @@
1
-
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <title>This is the parent frame title</title>
@@ -1,4 +1,4 @@
1
-
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <title>This is the title of frame two</title>
@@ -1,4 +1,5 @@
1
- <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
1
+ <!DOCTYPE html>
2
+ <html lang="en">
2
3
  <body>
3
4
  <div>
4
5
  Initial alert page
@@ -0,0 +1,10 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
5
+ </head>
6
+
7
+ <body>
8
+ <%= yield %>
9
+ </body>
10
+ </html>
@@ -1,3 +1,4 @@
1
+ <!DOCTYPE html>
1
2
  <html>
2
3
  <head>
3
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
@@ -44,4 +45,3 @@
44
45
  </div>
45
46
  </body>
46
47
  </html>
47
-
@@ -1,3 +1,4 @@
1
+ <!DOCTYPE html>
1
2
  <html>
2
3
  <head>
3
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
@@ -29,4 +30,4 @@
29
30
  <div id="clicker"></div>
30
31
  </div>
31
32
  </body>
32
- </html>
33
+ </html>
@@ -1,5 +1,5 @@
1
-
2
- <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
3
  <body>
4
4
  <div>
5
5
  <a href="#">First Link</a>
@@ -1,4 +1,4 @@
1
-
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <title>Title of the first popup</title>
@@ -1,4 +1,4 @@
1
-
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <title>Title of popup two</title>
@@ -1,4 +1,4 @@
1
- <!doctype html>
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <script src="https://unpkg.com/react/umd/react.development.js"></script>
@@ -42,4 +42,4 @@
42
42
  document.getElementById('root'));
43
43
  </script>
44
44
  </body>
45
- </html>
45
+ </html>
@@ -1,3 +1,4 @@
1
+ <!DOCTYPE html>
1
2
  <html style="height: 250%; width: 150%">
2
3
  <head>
3
4
  <style>
@@ -17,4 +18,4 @@
17
18
  </div>
18
19
  </div>
19
20
  </body>
20
- </html>
21
+ </html>
@@ -1,3 +1,4 @@
1
+ <!DOCTYPE html>
1
2
  <html>
2
3
  <head>
3
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
@@ -28,4 +29,3 @@
28
29
  <div class="footer distance">10</div>
29
30
  </body>
30
31
  </html>
31
-
@@ -1,5 +1,5 @@
1
-
2
- <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
3
  <head>
4
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
5
5
  <title>with_animation</title>
@@ -79,4 +79,3 @@
79
79
  </a>
80
80
  </body>
81
81
  </html>
82
-
@@ -1,5 +1,5 @@
1
-
2
- <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
3
  <head>
4
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
5
5
  <base href="http://example2.com" />
@@ -1,4 +1,5 @@
1
- <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
1
+ <!DOCTYPE html>
2
+ <html lang="en">
2
3
  <head>
3
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
4
5
  <title>with_dragula</title>
@@ -21,4 +22,3 @@
21
22
  </script>
22
23
  </body>
23
24
  </html>
24
-
@@ -1,3 +1,4 @@
1
+ <!DOCTYPE html>
1
2
  <html>
2
3
  <head>
3
4
  <style>
@@ -14,4 +15,4 @@
14
15
  <a href="/">Go to root</a>
15
16
  </div>
16
17
  <footer>My footer</footer>
17
- </body>
18
+ </body>
@@ -1,5 +1,5 @@
1
-
2
- <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
3
  <head>
4
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
5
5
  <title>with_hover</title>
@@ -19,7 +19,7 @@
19
19
 
20
20
  <p class="para" id="first" data-random="abc\def" style="line-height: 25px;">
21
21
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
22
- tempor incididunt ut <a href="/with_simple_html" title="awesome title" class="simple">labore</a>
22
+ tempor incididunt ut <a href="/with_simple_html" title="awesome title" class="simple" tabindex="1">labore</a>
23
23
  et dolore magna aliqua. Ut enim ad minim veniam,
24
24
  quis nostrud exercitation <a href="/foo" id="foo" data-test-id="test-foo">ullamco</a> laboris nisi
25
25
  ut aliquip ex ea commodo consequat.
@@ -1,4 +1,4 @@
1
-
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
@@ -1,5 +1,5 @@
1
-
2
- <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
3
  <head>
4
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
5
5
  <title>with_js</title>
@@ -160,4 +160,3 @@
160
160
  </script>
161
161
  </body>
162
162
  </html>
163
-
@@ -1,4 +1,4 @@
1
- <!doctype html>
1
+ <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
4
  <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
@@ -1,3 +1,4 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
1
2
  <html xmlns="http://www.w3.org/1999/xhtml">
2
3
  <head>
3
4
  <title>Namespace</title>