capybara 3.6.0 → 3.7.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +16 -0
  3. data/README.md +5 -1
  4. data/lib/capybara.rb +2 -0
  5. data/lib/capybara/minitest/spec.rb +1 -1
  6. data/lib/capybara/node/actions.rb +34 -25
  7. data/lib/capybara/node/base.rb +15 -17
  8. data/lib/capybara/node/document_matchers.rb +1 -3
  9. data/lib/capybara/node/element.rb +11 -12
  10. data/lib/capybara/node/finders.rb +2 -1
  11. data/lib/capybara/node/simple.rb +13 -6
  12. data/lib/capybara/queries/base_query.rb +4 -4
  13. data/lib/capybara/queries/selector_query.rb +119 -94
  14. data/lib/capybara/queries/text_query.rb +2 -1
  15. data/lib/capybara/rack_test/form.rb +4 -4
  16. data/lib/capybara/rack_test/node.rb +5 -5
  17. data/lib/capybara/result.rb +23 -32
  18. data/lib/capybara/rspec/compound.rb +1 -1
  19. data/lib/capybara/rspec/matchers.rb +63 -61
  20. data/lib/capybara/selector.rb +28 -10
  21. data/lib/capybara/selector/css.rb +17 -17
  22. data/lib/capybara/selector/filter_set.rb +9 -9
  23. data/lib/capybara/selector/selector.rb +3 -4
  24. data/lib/capybara/selenium/driver.rb +73 -95
  25. data/lib/capybara/selenium/driver_specializations/chrome_driver.rb +4 -4
  26. data/lib/capybara/selenium/driver_specializations/marionette_driver.rb +9 -0
  27. data/lib/capybara/selenium/node.rb +127 -67
  28. data/lib/capybara/selenium/nodes/chrome_node.rb +3 -3
  29. data/lib/capybara/selenium/nodes/marionette_node.rb +14 -8
  30. data/lib/capybara/server.rb +2 -2
  31. data/lib/capybara/server/animation_disabler.rb +17 -3
  32. data/lib/capybara/server/middleware.rb +8 -4
  33. data/lib/capybara/session.rb +43 -37
  34. data/lib/capybara/session/config.rb +8 -6
  35. data/lib/capybara/spec/session/assert_text_spec.rb +14 -0
  36. data/lib/capybara/spec/session/attach_file_spec.rb +7 -0
  37. data/lib/capybara/spec/session/check_spec.rb +21 -0
  38. data/lib/capybara/spec/session/choose_spec.rb +15 -1
  39. data/lib/capybara/spec/session/fill_in_spec.rb +7 -0
  40. data/lib/capybara/spec/session/find_spec.rb +2 -1
  41. data/lib/capybara/spec/session/has_selector_spec.rb +18 -0
  42. data/lib/capybara/spec/session/has_text_spec.rb +14 -0
  43. data/lib/capybara/spec/session/node_spec.rb +2 -1
  44. data/lib/capybara/spec/session/reset_session_spec.rb +4 -4
  45. data/lib/capybara/spec/session/text_spec.rb +2 -1
  46. data/lib/capybara/spec/session/title_spec.rb +2 -1
  47. data/lib/capybara/spec/session/uncheck_spec.rb +8 -0
  48. data/lib/capybara/spec/session/within_spec.rb +2 -1
  49. data/lib/capybara/spec/spec_helper.rb +1 -32
  50. data/lib/capybara/spec/views/with_js.erb +3 -4
  51. data/lib/capybara/version.rb +1 -1
  52. data/spec/minitest_spec.rb +4 -0
  53. data/spec/minitest_spec_spec.rb +4 -0
  54. data/spec/rack_test_spec.rb +4 -4
  55. data/spec/rspec/shared_spec_matchers.rb +4 -2
  56. data/spec/selector_spec.rb +15 -1
  57. data/spec/selenium_spec_chrome.rb +1 -6
  58. data/spec/selenium_spec_chrome_remote.rb +1 -1
  59. data/spec/selenium_spec_firefox_remote.rb +2 -5
  60. data/spec/selenium_spec_ie.rb +41 -4
  61. data/spec/selenium_spec_marionette.rb +1 -25
  62. data/spec/shared_selenium_session.rb +74 -16
  63. data/spec/spec_helper.rb +41 -0
  64. metadata +2 -2
@@ -20,7 +20,7 @@ module Capybara
20
20
  end
21
21
  end
22
22
 
23
- attr_accessor :error
23
+ attr_reader :error
24
24
 
25
25
  def initialize(app, server_errors, extra_middleware = [])
26
26
  @app = app
@@ -35,6 +35,10 @@ module Capybara
35
35
  @counter.value.positive?
36
36
  end
37
37
 
38
+ def clear_error
39
+ @error = nil
40
+ end
41
+
38
42
  def call(env)
39
43
  if env['PATH_INFO'] == '/__identify__'
40
44
  [200, {}, [@app.object_id.to_s]]
@@ -42,9 +46,9 @@ module Capybara
42
46
  @counter.increment
43
47
  begin
44
48
  @extended_app.call(env)
45
- rescue *@server_errors => e
46
- @error ||= e
47
- raise e
49
+ rescue *@server_errors => err
50
+ @error ||= err
51
+ raise err
48
52
  ensure
49
53
  @counter.decrement
50
54
  end
@@ -137,7 +137,7 @@ module Capybara
137
137
  # Raise errors encountered in the server
138
138
  #
139
139
  def raise_server_error!
140
- return if @server.nil? || !@server.error
140
+ return unless @server&.error
141
141
  # Force an explanation for the error being raised as the exception cause
142
142
  begin
143
143
  if config.raise_server_errors
@@ -244,26 +244,19 @@ module Capybara
244
244
  @touched = true
245
245
 
246
246
  visit_uri = ::Addressable::URI.parse(visit_uri.to_s)
247
+ base_uri = ::Addressable::URI.parse(config.app_host || server_url)
247
248
 
248
- base = config.app_host
249
- base ||= "http#{'s' if @server.using_ssl?}://#{@server.host}:#{@server.port}" if @server
250
-
251
- uri_base = ::Addressable::URI.parse(base)
252
-
253
- if uri_base && [nil, 'http', 'https'].include?(visit_uri.scheme)
249
+ if base_uri && [nil, 'http', 'https'].include?(visit_uri.scheme)
254
250
  if visit_uri.relative?
255
- uri_base.port ||= @server.port if @server && config.always_include_port
256
-
257
- visit_uri_parts = visit_uri.to_hash.delete_if { |_k, v| v.nil? }
251
+ visit_uri_parts = visit_uri.to_hash.delete_if { |_k, value| value.nil? }
258
252
 
259
253
  # Useful to people deploying to a subdirectory
260
254
  # and/or single page apps where only the url fragment changes
261
- visit_uri_parts[:path] = uri_base.path + visit_uri.path
255
+ visit_uri_parts[:path] = base_uri.path + visit_uri.path
262
256
 
263
- visit_uri = uri_base.merge(visit_uri_parts)
264
- elsif @server && config.always_include_port
265
- visit_uri.port ||= @server.port
257
+ visit_uri = base_uri.merge(visit_uri_parts)
266
258
  end
259
+ adjust_server_port(visit_uri)
267
260
  end
268
261
 
269
262
  driver.visit(visit_uri.to_s)
@@ -544,8 +537,7 @@ module Capybara
544
537
  old_handles = driver.window_handles
545
538
  yield
546
539
 
547
- wait_time = Capybara::Queries::BaseQuery.wait(options, config.default_max_wait_time)
548
- document.synchronize(wait_time, errors: [Capybara::WindowError]) do
540
+ synchronize_windows(options) do
549
541
  opened_handles = (driver.window_handles - old_handles)
550
542
  if opened_handles.size != 1
551
543
  raise Capybara::WindowError, 'block passed to #window_opened_by '\
@@ -675,8 +667,8 @@ module Capybara
675
667
  # @return [String] the path to which the file was saved
676
668
  #
677
669
  def save_page(path = nil)
678
- prepare_path(path, 'html').tap do |p|
679
- File.write(p, Capybara::Helpers.inject_asset_host(body, host: config.asset_host), mode: 'wb')
670
+ prepare_path(path, 'html').tap do |p_path|
671
+ File.write(p_path, Capybara::Helpers.inject_asset_host(body, host: config.asset_host), mode: 'wb')
680
672
  end
681
673
  end
682
674
 
@@ -691,7 +683,7 @@ module Capybara
691
683
  # @param [String] path the path to where it should be saved
692
684
  #
693
685
  def save_and_open_page(path = nil)
694
- save_page(path).tap { |p| open_file(p) }
686
+ save_page(path).tap { |s_path| open_file(s_path) }
695
687
  end
696
688
 
697
689
  ##
@@ -706,7 +698,7 @@ module Capybara
706
698
  # @param [Hash] options a customizable set of options
707
699
  # @return [String] the path to which the file was saved
708
700
  def save_screenshot(path = nil, **options)
709
- prepare_path(path, 'png').tap { |p| driver.save_screenshot(p, options) }
701
+ prepare_path(path, 'png').tap { |p_path| driver.save_screenshot(p_path, options) }
710
702
  end
711
703
 
712
704
  ##
@@ -722,7 +714,7 @@ module Capybara
722
714
  #
723
715
  def save_and_open_screenshot(path = nil, **options)
724
716
  # rubocop:disable Lint/Debugger
725
- save_screenshot(path, options).tap { |p| open_file(p) }
717
+ save_screenshot(path, options).tap { |s_path| open_file(s_path) }
726
718
  # rubocop:enable Lint/Debugger
727
719
  end
728
720
 
@@ -822,7 +814,7 @@ module Capybara
822
814
  end
823
815
 
824
816
  def prepare_path(path, extension)
825
- File.expand_path(path || default_fn(extension), config.save_path).tap { |p| FileUtils.mkdir_p(File.dirname(p)) }
817
+ File.expand_path(path || default_fn(extension), config.save_path).tap { |p_path| FileUtils.mkdir_p(File.dirname(p_path)) }
826
818
  end
827
819
 
828
820
  def default_fn(extension)
@@ -837,9 +829,9 @@ module Capybara
837
829
  def element_script_result(arg)
838
830
  case arg
839
831
  when Array
840
- arg.map { |e| element_script_result(e) }
832
+ arg.map { |subarg| element_script_result(subarg) }
841
833
  when Hash
842
- arg.each { |k, v| arg[k] = element_script_result(v) }
834
+ arg.each { |key, value| arg[key] = element_script_result(value) }
843
835
  when Capybara::Driver::Node
844
836
  Capybara::Node::Element.new(self, arg, nil, nil)
845
837
  else
@@ -847,6 +839,14 @@ module Capybara
847
839
  end
848
840
  end
849
841
 
842
+ def server_url
843
+ "http#{'s' if @server.using_ssl?}://#{@server.host}:#{@server.port}" if @server
844
+ end
845
+
846
+ def adjust_server_port(uri)
847
+ uri.port ||= @server.port if @server && config.always_include_port
848
+ end
849
+
850
850
  def _find_frame(*args)
851
851
  return find(:frame) if args.length.zero?
852
852
 
@@ -865,31 +865,37 @@ module Capybara
865
865
  end
866
866
  end
867
867
 
868
- def _switch_to_window(window = nil, **options)
868
+ def _switch_to_window(window = nil, **options, &window_locator)
869
869
  raise Capybara::ScopeError, 'Window cannot be switched inside a `within_frame` block' if scopes.include?(:frame)
870
- raise Capybara::ScopeError, 'Window cannot be switch inside a `within` block' unless scopes.last.nil?
870
+ raise Capybara::ScopeError, 'Window cannot be switched inside a `within` block' unless scopes.last.nil?
871
871
 
872
872
  if window
873
873
  driver.switch_to_window(window.handle)
874
874
  window
875
875
  else
876
- wait_time = Capybara::Queries::BaseQuery.wait(options, config.default_max_wait_time)
877
- document.synchronize(wait_time, errors: [Capybara::WindowError]) do
876
+ synchronize_windows(options) do
878
877
  original_window_handle = driver.current_window_handle
879
878
  begin
880
- driver.window_handles.each do |handle|
881
- driver.switch_to_window handle
882
- return Window.new(self, handle) if yield
883
- end
884
- rescue StandardError => e
879
+ _switch_to_window_by_locator(&window_locator)
880
+ rescue StandardError
885
881
  driver.switch_to_window(original_window_handle)
886
- raise e
887
- else
888
- driver.switch_to_window(original_window_handle)
889
- raise Capybara::WindowError, 'Could not find a window matching block/lambda'
882
+ raise
890
883
  end
891
884
  end
892
885
  end
893
886
  end
887
+
888
+ def _switch_to_window_by_locator
889
+ driver.window_handles.each do |handle|
890
+ driver.switch_to_window handle
891
+ return Window.new(self, handle) if yield
892
+ end
893
+ raise Capybara::WindowError, 'Could not find a window matching block/lambda'
894
+ end
895
+
896
+ def synchronize_windows(options, &block)
897
+ wait_time = Capybara::Queries::BaseQuery.wait(options, config.default_max_wait_time)
898
+ document.synchronize(wait_time, errors: [Capybara::WindowError], &block)
899
+ end
894
900
  end
895
901
  end
@@ -8,7 +8,7 @@ module Capybara
8
8
  automatic_reload match exact exact_text raise_server_errors visible_text_only
9
9
  automatic_label_click enable_aria_label save_path asset_host default_host app_host
10
10
  server_host server_port server_errors default_set_options disable_animation test_id
11
- predicates_wait].freeze
11
+ predicates_wait default_normalize_ws].freeze
12
12
 
13
13
  attr_accessor(*OPTIONS)
14
14
 
@@ -57,6 +57,8 @@ module Capybara
57
57
  # See {Capybara.configure}
58
58
  # @!method test_id
59
59
  # See {Capybara.configure}
60
+ # @!method default_normalize_ws
61
+ # See {Capybara.configure}
60
62
 
61
63
  remove_method :server_host
62
64
 
@@ -86,9 +88,9 @@ module Capybara
86
88
  end
87
89
 
88
90
  remove_method :disable_animation=
89
- def disable_animation=(bool)
90
- warn 'Capybara.disable_animation is a beta feature - it may change/disappear in a future point version' if bool
91
- @disable_animation = bool
91
+ def disable_animation=(bool_or_allowlist)
92
+ warn 'Capybara.disable_animation is a beta feature - it may change/disappear in a future point version' if bool_or_allowlist
93
+ @disable_animation = bool_or_allowlist
92
94
  end
93
95
 
94
96
  remove_method :test_id=
@@ -111,8 +113,8 @@ module Capybara
111
113
  end
112
114
 
113
115
  class ReadOnlySessionConfig < SimpleDelegator
114
- SessionConfig::OPTIONS.each do |m|
115
- define_method "#{m}=" do |_|
116
+ SessionConfig::OPTIONS.each do |option|
117
+ define_method "#{option}=" do |_|
116
118
  raise 'Per session settings are only supported when Capybara.threadsafe == true'
117
119
  end
118
120
  end
@@ -15,6 +15,20 @@ Capybara::SpecHelper.spec '#assert_text' do
15
15
  expect(@session.assert_text('text with whitespace', normalize_ws: true)).to eq(true)
16
16
  end
17
17
 
18
+ context 'with enabled default collapsing whitespace' do
19
+ before { Capybara.default_normalize_ws = true }
20
+
21
+ it 'should be true if the given unnormalized text is on the page' do
22
+ @session.visit('/with_html')
23
+ expect(@session.assert_text('text with whitespace', normalize_ws: false)).to eq(true)
24
+ end
25
+
26
+ it 'should support collapsing whitespace' do
27
+ @session.visit('/with_html')
28
+ expect(@session.assert_text('text with whitespace')).to eq(true)
29
+ end
30
+ end
31
+
18
32
  it 'should take scopes into account' do
19
33
  @session.visit('/with_html')
20
34
  @session.within("//a[@title='awesome title']") do
@@ -22,6 +22,13 @@ Capybara::SpecHelper.spec '#attach_file' do
22
22
  expect(extract_results(@session)['image']).to eq(File.basename(__FILE__))
23
23
  end
24
24
 
25
+ it 'should be able to set on element if no locator passed' do
26
+ ff = @session.find(:file_field, 'Image')
27
+ ff.attach_file(with_os_path_separators(__FILE__))
28
+ @session.click_button('awesome')
29
+ expect(extract_results(@session)['image']).to eq(File.basename(__FILE__))
30
+ end
31
+
25
32
  it 'casts to string' do
26
33
  @session.attach_file :form_image, with_os_path_separators(__FILE__)
27
34
  @session.click_button('awesome')
@@ -68,6 +68,13 @@ Capybara::SpecHelper.spec '#check' do
68
68
  expect(extract_results(@session)['pets']).to include('dog', 'cat', 'hamster')
69
69
  end
70
70
 
71
+ it 'should be able to check itself if no locator specified' do
72
+ cb = @session.find(:id, 'form_pets_cat')
73
+ cb.check
74
+ @session.click_button('awesome')
75
+ expect(extract_results(@session)['pets']).to include('dog', 'cat', 'hamster')
76
+ end
77
+
71
78
  it 'casts to string' do
72
79
  @session.check(:form_pets_cat)
73
80
  @session.click_button('awesome')
@@ -142,6 +149,20 @@ Capybara::SpecHelper.spec '#check' do
142
149
  expect(extract_results(@session)['cars']).to include('mclaren')
143
150
  end
144
151
 
152
+ it 'should check via clicking the label with :for attribute if locator nil' do
153
+ cb = @session.find(:checkbox, 'form_cars_tesla', unchecked: true, visible: :hidden)
154
+ cb.check
155
+ @session.click_button('awesome')
156
+ expect(extract_results(@session)['cars']).to include('tesla')
157
+ end
158
+
159
+ it 'should check self via clicking the wrapping label if locator nil' do
160
+ cb = @session.find(:checkbox, 'form_cars_mclaren', unchecked: true, visible: :hidden)
161
+ cb.check
162
+ @session.click_button('awesome')
163
+ expect(extract_results(@session)['cars']).to include('mclaren')
164
+ end
165
+
145
166
  it 'should not click the label if unneeded' do
146
167
  expect(@session.find(:checkbox, 'form_cars_jaguar', checked: true, visible: :hidden)).to be_truthy
147
168
  @session.check('form_cars_jaguar')
@@ -23,6 +23,13 @@ Capybara::SpecHelper.spec '#choose' do
23
23
  expect(extract_results(@session)['gender']).to eq('male')
24
24
  end
25
25
 
26
+ it 'should be able to choose self when no locator string specified' do
27
+ rb = @session.find(:id, 'gender_male')
28
+ rb.choose
29
+ @session.click_button('awesome')
30
+ expect(extract_results(@session)['gender']).to eq('male')
31
+ end
32
+
26
33
  it 'casts to string' do
27
34
  @session.choose('Both')
28
35
  @session.click_button(:awesome)
@@ -82,12 +89,19 @@ Capybara::SpecHelper.spec '#choose' do
82
89
  Capybara.automatic_label_click = old_click_label
83
90
  end
84
91
 
85
- it 'should select by clicking the link if available' do
92
+ it 'should select by clicking the label if available' do
86
93
  @session.choose('party_democrat')
87
94
  @session.click_button('awesome')
88
95
  expect(extract_results(@session)['party']).to eq('democrat')
89
96
  end
90
97
 
98
+ it 'should select self by clicking the label if no locator specified' do
99
+ cb = @session.find(:id, 'party_democrat', visible: :hidden)
100
+ cb.choose
101
+ @session.click_button('awesome')
102
+ expect(extract_results(@session)['party']).to eq('democrat')
103
+ end
104
+
91
105
  it 'should raise error if not allowed to click label' do
92
106
  expect { @session.choose('party_democrat', allow_label_click: false) }.to raise_error(Capybara::ElementNotFound, 'Unable to find visible radio button "party_democrat"')
93
107
  end
@@ -137,6 +137,13 @@ Capybara::SpecHelper.spec '#fill_in' do
137
137
  expect(extract_results(@session)['schmooo']).to eq('Schmooo for all')
138
138
  end
139
139
 
140
+ it 'should be able to fill in element called on when no locator passed' do
141
+ field = @session.find(:fillable_field, 'form[password]')
142
+ field.fill_in(with: 'supasikrit')
143
+ @session.click_button('awesome')
144
+ expect(extract_results(@session)['password']).to eq('supasikrit')
145
+ end
146
+
140
147
  it "should throw an exception if a hash containing 'with' is not provided" do
141
148
  expect { @session.fill_in 'Name' }.to raise_error(ArgumentError, /with/)
142
149
  end
@@ -208,11 +208,12 @@ Capybara::SpecHelper.spec '#find' do
208
208
  context 'with css as default selector' do
209
209
  before { Capybara.default_selector = :css }
210
210
 
211
+ after { Capybara.default_selector = :xpath }
212
+
211
213
  it 'should find the first element using the given locator' do
212
214
  expect(@session.find('h1').text).to eq('This is a test')
213
215
  expect(@session.find("input[id='test_field']").value).to eq('monkey')
214
216
  end
215
- after { Capybara.default_selector = :xpath }
216
217
  end
217
218
 
218
219
  it 'should raise ElementNotFound with a useful default message if nothing was found' do
@@ -78,6 +78,24 @@ Capybara::SpecHelper.spec '#has_selector?' do
78
78
  expect(@session).to have_selector(:css, 'p a#foo', 'extra')
79
79
  end.to raise_error ArgumentError, /extra/
80
80
  end
81
+
82
+ context 'with whitespace normalization' do
83
+ context 'Capybara.default_normalize_ws = false' do
84
+ it 'should support normalize_ws option' do
85
+ Capybara.default_normalize_ws = false
86
+ expect(@session).not_to have_selector(:id, 'second', text: 'text with whitespace')
87
+ expect(@session).to have_selector(:id, 'second', text: 'text with whitespace', normalize_ws: true)
88
+ end
89
+ end
90
+
91
+ context 'Capybara.default_normalize_ws = true' do
92
+ it 'should support normalize_ws option' do
93
+ Capybara.default_normalize_ws = true
94
+ expect(@session).to have_selector(:id, 'second', text: 'text with whitespace')
95
+ expect(@session).not_to have_selector(:id, 'second', text: 'text with whitespace', normalize_ws: false)
96
+ end
97
+ end
98
+ end
81
99
  end
82
100
 
83
101
  context 'with exact_text' do
@@ -39,6 +39,20 @@ Capybara::SpecHelper.spec '#has_text?' do
39
39
  expect(@session).to have_text('text with whitespace', normalize_ws: true)
40
40
  end
41
41
 
42
+ context 'with enabled default collapsing whitespace' do
43
+ before { Capybara.default_normalize_ws = true }
44
+
45
+ it 'should search unnormalized text' do
46
+ @session.visit('/with_html')
47
+ expect(@session).to have_text('text with whitespace', normalize_ws: false)
48
+ end
49
+
50
+ it 'should search whitespace collapsed text' do
51
+ @session.visit('/with_html')
52
+ expect(@session).to have_text('text with whitespace')
53
+ end
54
+ end
55
+
42
56
  it 'should be false if the given text is not on the page' do
43
57
  @session.visit('/with_html')
44
58
  expect(@session).not_to have_text('xxxxyzzz')
@@ -545,6 +545,8 @@ Capybara::SpecHelper.spec 'node' do
545
545
  context 'without automatic reload' do
546
546
  before { Capybara.automatic_reload = false }
547
547
 
548
+ after { Capybara.automatic_reload = true }
549
+
548
550
  it 'should reload the current context of the node' do
549
551
  @session.visit('/with_js')
550
552
  node = @session.find(:css, '#reload-me')
@@ -574,7 +576,6 @@ Capybara::SpecHelper.spec 'node' do
574
576
  expect(error).to be_an_invalid_element_error(@session)
575
577
  end)
576
578
  end
577
- after { Capybara.automatic_reload = true }
578
579
  end
579
580
 
580
581
  context 'with automatic reload' do
@@ -87,6 +87,10 @@ Capybara::SpecHelper.spec '#reset_session!' do
87
87
  Capybara.reuse_server = false
88
88
  end
89
89
 
90
+ after do
91
+ Capybara.reuse_server = @reuse_server
92
+ end
93
+
90
94
  it 'raises any standard errors caught inside the server during a second session', requires: [:server] do
91
95
  Capybara.using_driver(@session.mode) do
92
96
  Capybara.using_session(:another_session) do
@@ -100,10 +104,6 @@ Capybara::SpecHelper.spec '#reset_session!' do
100
104
  end
101
105
  end
102
106
  end
103
-
104
- after do
105
- Capybara.reuse_server = @reuse_server
106
- end
107
107
  end
108
108
 
109
109
  it 'raises configured errors caught inside the server', requires: [:server] do