grape 1.6.0 → 1.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/CONTRIBUTING.md +2 -1
  4. data/README.md +9 -1
  5. data/UPGRADING.md +4 -4
  6. data/lib/grape/api.rb +12 -0
  7. data/lib/grape/dsl/headers.rb +5 -2
  8. data/lib/grape/dsl/helpers.rb +1 -1
  9. data/lib/grape/middleware/auth/dsl.rb +7 -1
  10. data/lib/grape/middleware/base.rb +1 -1
  11. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  12. data/lib/grape/validations/validators/all_or_none.rb +7 -5
  13. data/lib/grape/validations/validators/allow_blank.rb +9 -7
  14. data/lib/grape/validations/validators/as.rb +7 -5
  15. data/lib/grape/validations/validators/at_least_one_of.rb +6 -4
  16. data/lib/grape/validations/validators/base.rb +73 -71
  17. data/lib/grape/validations/validators/coerce.rb +63 -75
  18. data/lib/grape/validations/validators/default.rb +36 -34
  19. data/lib/grape/validations/validators/exactly_one_of.rb +8 -6
  20. data/lib/grape/validations/validators/except_values.rb +13 -11
  21. data/lib/grape/validations/validators/multiple_params_base.rb +24 -22
  22. data/lib/grape/validations/validators/mutual_exclusion.rb +7 -5
  23. data/lib/grape/validations/validators/presence.rb +6 -4
  24. data/lib/grape/validations/validators/regexp.rb +7 -5
  25. data/lib/grape/validations/validators/same_as.rb +17 -15
  26. data/lib/grape/validations/validators/values.rb +59 -57
  27. data/lib/grape/validations.rb +6 -0
  28. data/lib/grape/version.rb +1 -1
  29. data/lib/grape.rb +2 -0
  30. data/spec/grape/api/custom_validations_spec.rb +77 -46
  31. data/spec/grape/api/deeply_included_options_spec.rb +3 -3
  32. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -1
  33. data/spec/grape/api/invalid_format_spec.rb +2 -0
  34. data/spec/grape/api/recognize_path_spec.rb +1 -1
  35. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
  36. data/spec/grape/api_remount_spec.rb +16 -15
  37. data/spec/grape/api_spec.rb +317 -193
  38. data/spec/grape/dsl/callbacks_spec.rb +1 -0
  39. data/spec/grape/dsl/headers_spec.rb +39 -9
  40. data/spec/grape/dsl/helpers_spec.rb +3 -2
  41. data/spec/grape/dsl/inside_route_spec.rb +6 -4
  42. data/spec/grape/dsl/logger_spec.rb +16 -18
  43. data/spec/grape/dsl/middleware_spec.rb +1 -0
  44. data/spec/grape/dsl/parameters_spec.rb +1 -0
  45. data/spec/grape/dsl/request_response_spec.rb +1 -0
  46. data/spec/grape/dsl/routing_spec.rb +9 -6
  47. data/spec/grape/endpoint/declared_spec.rb +12 -12
  48. data/spec/grape/endpoint_spec.rb +59 -50
  49. data/spec/grape/entity_spec.rb +13 -13
  50. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -0
  51. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -22
  52. data/spec/grape/exceptions/validation_errors_spec.rb +13 -10
  53. data/spec/grape/exceptions/validation_spec.rb +5 -3
  54. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -7
  55. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -8
  56. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -8
  57. data/spec/grape/integration/rack_sendfile_spec.rb +1 -1
  58. data/spec/grape/loading_spec.rb +8 -8
  59. data/spec/grape/middleware/auth/dsl_spec.rb +14 -5
  60. data/spec/grape/middleware/auth/strategies_spec.rb +60 -20
  61. data/spec/grape/middleware/base_spec.rb +24 -15
  62. data/spec/grape/middleware/error_spec.rb +1 -0
  63. data/spec/grape/middleware/exception_spec.rb +111 -161
  64. data/spec/grape/middleware/formatter_spec.rb +25 -4
  65. data/spec/grape/middleware/globals_spec.rb +7 -4
  66. data/spec/grape/middleware/stack_spec.rb +11 -11
  67. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -1
  68. data/spec/grape/middleware/versioner/header_spec.rb +14 -13
  69. data/spec/grape/middleware/versioner/param_spec.rb +7 -1
  70. data/spec/grape/middleware/versioner/path_spec.rb +5 -1
  71. data/spec/grape/middleware/versioner_spec.rb +1 -1
  72. data/spec/grape/parser_spec.rb +4 -0
  73. data/spec/grape/path_spec.rb +52 -52
  74. data/spec/grape/presenters/presenter_spec.rb +7 -6
  75. data/spec/grape/request_spec.rb +6 -4
  76. data/spec/grape/util/inheritable_setting_spec.rb +7 -7
  77. data/spec/grape/util/inheritable_values_spec.rb +3 -2
  78. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -1
  79. data/spec/grape/util/stackable_values_spec.rb +7 -5
  80. data/spec/grape/validations/instance_behaivour_spec.rb +9 -10
  81. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -0
  82. data/spec/grape/validations/params_scope_spec.rb +9 -7
  83. data/spec/grape/validations/single_attribute_iterator_spec.rb +1 -0
  84. data/spec/grape/validations/types/primitive_coercer_spec.rb +2 -2
  85. data/spec/grape/validations/types_spec.rb +8 -8
  86. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -56
  87. data/spec/grape/validations/validators/allow_blank_spec.rb +136 -140
  88. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -56
  89. data/spec/grape/validations/validators/coerce_spec.rb +10 -12
  90. data/spec/grape/validations/validators/default_spec.rb +72 -78
  91. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
  92. data/spec/grape/validations/validators/except_values_spec.rb +1 -1
  93. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -77
  94. data/spec/grape/validations/validators/presence_spec.rb +16 -1
  95. data/spec/grape/validations/validators/regexp_spec.rb +25 -31
  96. data/spec/grape/validations/validators/same_as_spec.rb +14 -20
  97. data/spec/grape/validations/validators/values_spec.rb +172 -171
  98. data/spec/grape/validations_spec.rb +45 -16
  99. data/spec/integration/eager_load/eager_load_spec.rb +2 -2
  100. data/spec/integration/multi_json/json_spec.rb +1 -1
  101. data/spec/integration/multi_xml/xml_spec.rb +1 -1
  102. data/spec/shared/versioning_examples.rb +10 -7
  103. data/spec/spec_helper.rb +11 -1
  104. metadata +102 -102
@@ -42,7 +42,17 @@ describe Grape::Middleware::Auth::Strategies do
42
42
  end
43
43
 
44
44
  module StrategiesSpec
45
- class Test < Grape::API
45
+ class PasswordHashed < Grape::API
46
+ http_digest(realm: { realm: 'Test Api', opaque: 'secret', passwords_hashed: true }) do |username|
47
+ { 'foo' => Digest::MD5.hexdigest(['foo', 'Test Api', 'bar'].join(':')) }[username]
48
+ end
49
+
50
+ get '/test' do
51
+ [{ hey: 'you' }, { there: 'bar' }, { foo: 'baz' }]
52
+ end
53
+ end
54
+
55
+ class PasswordIsNotHashed < Grape::API
46
56
  http_digest(realm: 'Test Api', opaque: 'secret') do |username|
47
57
  { 'foo' => 'bar' }[username]
48
58
  end
@@ -53,30 +63,60 @@ describe Grape::Middleware::Auth::Strategies do
53
63
  end
54
64
  end
55
65
 
56
- def app
57
- StrategiesSpec::Test
58
- end
66
+ context 'when password is hashed' do
67
+ def app
68
+ StrategiesSpec::PasswordHashed
69
+ end
59
70
 
60
- it 'is a digest authentication challenge' do
61
- get '/test'
62
- expect(last_response).to be_challenge
63
- end
71
+ it 'is a digest authentication challenge' do
72
+ get '/test'
73
+ expect(last_response).to be_challenge
74
+ end
64
75
 
65
- it 'throws a 401 if no auth is given' do
66
- get '/test'
67
- expect(last_response.status).to eq(401)
68
- end
76
+ it 'throws a 401 if no auth is given' do
77
+ get '/test'
78
+ expect(last_response.status).to eq(401)
79
+ end
69
80
 
70
- it 'authenticates if given valid creds' do
71
- digest_authorize 'foo', 'bar'
72
- get '/test'
73
- expect(last_response.status).to eq(200)
81
+ it 'authenticates if given valid creds' do
82
+ digest_authorize 'foo', 'bar'
83
+ get '/test'
84
+ expect(last_response.status).to eq(200)
85
+ end
86
+
87
+ it 'throws a 401 if given invalid creds' do
88
+ digest_authorize 'bar', 'foo'
89
+ get '/test'
90
+ expect(last_response.status).to eq(401)
91
+ end
74
92
  end
75
93
 
76
- it 'throws a 401 if given invalid creds' do
77
- digest_authorize 'bar', 'foo'
78
- get '/test'
79
- expect(last_response.status).to eq(401)
94
+ context 'when password is not hashed' do
95
+ def app
96
+ StrategiesSpec::PasswordIsNotHashed
97
+ end
98
+
99
+ it 'is a digest authentication challenge' do
100
+ get '/test'
101
+ expect(last_response).to be_challenge
102
+ end
103
+
104
+ it 'throws a 401 if no auth is given' do
105
+ get '/test'
106
+ expect(last_response.status).to eq(401)
107
+ end
108
+
109
+ it 'authenticates if given valid creds' do
110
+ digest_authorize 'foo', 'bar'
111
+ get '/test'
112
+ expect(last_response.status).to eq(200)
113
+ end
114
+
115
+ it 'throws a 401 if given invalid creds' do
116
+ digest_authorize 'bar', 'foo'
117
+ get '/test'
118
+ expect(last_response.status).to eq(401)
119
+ end
80
120
  end
81
121
  end
82
122
  end
@@ -3,7 +3,8 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Grape::Middleware::Base do
6
- subject { Grape::Middleware::Base.new(blank_app) }
6
+ subject { described_class.new(blank_app) }
7
+
7
8
  let(:blank_app) { ->(_) { [200, {}, 'Hi there.'] } }
8
9
 
9
10
  before do
@@ -20,6 +21,8 @@ describe Grape::Middleware::Base do
20
21
  end
21
22
 
22
23
  context 'callbacks' do
24
+ after { subject.call!({}) }
25
+
23
26
  it 'calls #before' do
24
27
  expect(subject).to receive(:before)
25
28
  end
@@ -27,8 +30,6 @@ describe Grape::Middleware::Base do
27
30
  it 'calls #after' do
28
31
  expect(subject).to receive(:after)
29
32
  end
30
-
31
- after { subject.call!({}) }
32
33
  end
33
34
 
34
35
  context 'callbacks on error' do
@@ -58,7 +59,7 @@ describe Grape::Middleware::Base do
58
59
  context 'with patched warnings' do
59
60
  before do
60
61
  @warnings = warnings = []
61
- allow_any_instance_of(Grape::Middleware::Base).to receive(:warn) { |m| warnings << m }
62
+ allow_any_instance_of(described_class).to receive(:warn) { |m| warnings << m }
62
63
  allow(subject).to receive(:after).and_raise(StandardError)
63
64
  end
64
65
 
@@ -75,49 +76,57 @@ describe Grape::Middleware::Base do
75
76
  end
76
77
 
77
78
  describe '#response' do
78
- subject { Grape::Middleware::Base.new(response) }
79
+ subject do
80
+ puts described_class
81
+ described_class.new(response)
82
+ end
79
83
 
80
- context Array do
84
+ before { subject.call({}) }
85
+
86
+ context 'when Array' do
81
87
  let(:response) { ->(_) { [204, { abc: 1 }, 'test'] } }
82
88
 
83
89
  it 'status' do
84
- subject.call({})
85
90
  expect(subject.response.status).to eq(204)
86
91
  end
87
92
 
88
93
  it 'body' do
89
- subject.call({})
90
94
  expect(subject.response.body).to eq(['test'])
91
95
  end
92
96
 
93
97
  it 'header' do
94
- subject.call({})
95
98
  expect(subject.response.header).to have_key(:abc)
96
99
  end
100
+
101
+ it 'returns the memoized Rack::Response instance' do
102
+ expect(subject.response).to be(subject.response)
103
+ end
97
104
  end
98
105
 
99
- context Rack::Response do
106
+ context 'when Rack::Response' do
100
107
  let(:response) { ->(_) { Rack::Response.new('test', 204, abc: 1) } }
101
108
 
102
109
  it 'status' do
103
- subject.call({})
104
110
  expect(subject.response.status).to eq(204)
105
111
  end
106
112
 
107
113
  it 'body' do
108
- subject.call({})
109
114
  expect(subject.response.body).to eq(['test'])
110
115
  end
111
116
 
112
117
  it 'header' do
113
- subject.call({})
114
118
  expect(subject.response.header).to have_key(:abc)
115
119
  end
120
+
121
+ it 'returns the memoized Rack::Response instance' do
122
+ expect(subject.response).to be(subject.response)
123
+ end
116
124
  end
117
125
  end
118
126
 
119
127
  describe '#context' do
120
- subject { Grape::Middleware::Base.new(blank_app) }
128
+ subject { described_class.new(blank_app) }
129
+
121
130
  it 'allows access to response context' do
122
131
  subject.call(Grape::Env::API_ENDPOINT => { header: 'some header' })
123
132
  expect(subject.context).to eq(header: 'some header')
@@ -126,7 +135,7 @@ describe Grape::Middleware::Base do
126
135
 
127
136
  context 'options' do
128
137
  it 'persists options passed at initialization' do
129
- expect(Grape::Middleware::Base.new(blank_app, abc: true).options[:abc]).to be true
138
+ expect(described_class.new(blank_app, abc: true).options[:abc]).to be true
130
139
  end
131
140
 
132
141
  context 'defaults' do
@@ -62,6 +62,7 @@ describe Grape::Middleware::Error do
62
62
 
63
63
  context 'with http code' do
64
64
  let(:options) { { default_message: 'Aww, hamburgers.' } }
65
+
65
66
  it 'adds the status code if wanted' do
66
67
  ErrorSpec::ErrApp.error = { message: { code: 200 } }
67
68
  get '/'
@@ -3,76 +3,82 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Grape::Middleware::Error do
6
- # raises a text exception
7
- module ExceptionSpec
8
- class ExceptionApp
6
+ let(:exception_app) do
7
+ Class.new do
9
8
  class << self
10
9
  def call(_env)
11
10
  raise 'rain!'
12
11
  end
13
12
  end
14
13
  end
14
+ end
15
15
 
16
- # raises a non-StandardError (ScriptError) exception
17
- class OtherExceptionApp
16
+ let(:other_exception_app) do
17
+ Class.new do
18
18
  class << self
19
19
  def call(_env)
20
20
  raise NotImplementedError, 'snow!'
21
21
  end
22
22
  end
23
23
  end
24
+ end
24
25
 
25
- # raises a hash error
26
- class ErrorHashApp
26
+ let(:custom_error_app) do
27
+ Class.new do
27
28
  class << self
28
- def error!(message, status)
29
- throw :error, message: { error: message, detail: 'missing widget' }, status: status
30
- end
29
+ class CustomError < Grape::Exceptions::Base; end
31
30
 
32
31
  def call(_env)
33
- error!('rain!', 401)
32
+ raise CustomError.new(status: 400, message: 'failed validation')
34
33
  end
35
34
  end
36
35
  end
36
+ end
37
37
 
38
- # raises an error!
39
- class AccessDeniedApp
38
+ let(:error_hash_app) do
39
+ Class.new do
40
40
  class << self
41
41
  def error!(message, status)
42
- throw :error, message: message, status: status
42
+ throw :error, message: { error: message, detail: 'missing widget' }, status: status
43
43
  end
44
44
 
45
45
  def call(_env)
46
- error!('Access Denied', 401)
46
+ error!('rain!', 401)
47
47
  end
48
48
  end
49
49
  end
50
+ end
50
51
 
51
- # raises a custom error
52
- class CustomError < Grape::Exceptions::Base
53
- end
54
-
55
- class CustomErrorApp
52
+ let(:access_denied_app) do
53
+ Class.new do
56
54
  class << self
55
+ def error!(message, status)
56
+ throw :error, message: message, status: status
57
+ end
58
+
57
59
  def call(_env)
58
- raise CustomError.new(status: 400, message: 'failed validation')
60
+ error!('Access Denied', 401)
59
61
  end
60
62
  end
61
63
  end
62
64
  end
63
65
 
64
- def app
65
- subject
66
+ let(:app) do
67
+ builder = Rack::Builder.new
68
+ builder.use Spec::Support::EndpointFaker
69
+ if options.any?
70
+ builder.use described_class, options
71
+ else
72
+ builder.use described_class
73
+ end
74
+ builder.run running_app
75
+ builder.to_app
66
76
  end
67
77
 
68
78
  context 'with defaults' do
69
- subject do
70
- Rack::Builder.app do
71
- use Spec::Support::EndpointFaker
72
- use Grape::Middleware::Error
73
- run ExceptionSpec::ExceptionApp
74
- end
75
- end
79
+ let(:running_app) { exception_app }
80
+ let(:options) { {} }
81
+
76
82
  it 'does not trap errors by default' do
77
83
  expect { get '/' }.to raise_error(RuntimeError, 'rain!')
78
84
  end
@@ -80,17 +86,14 @@ describe Grape::Middleware::Error do
80
86
 
81
87
  context 'with rescue_all' do
82
88
  context 'StandardError exception' do
83
- subject do
84
- Rack::Builder.app do
85
- use Spec::Support::EndpointFaker
86
- use Grape::Middleware::Error, rescue_all: true
87
- run ExceptionSpec::ExceptionApp
88
- end
89
- end
89
+ let(:running_app) { exception_app }
90
+ let(:options) { { rescue_all: true } }
91
+
90
92
  it 'sets the message appropriately' do
91
93
  get '/'
92
94
  expect(last_response.body).to eq('rain!')
93
95
  end
96
+
94
97
  it 'defaults to a 500 status' do
95
98
  get '/'
96
99
  expect(last_response.status).to eq(500)
@@ -98,13 +101,9 @@ describe Grape::Middleware::Error do
98
101
  end
99
102
 
100
103
  context 'Non-StandardError exception' do
101
- subject do
102
- Rack::Builder.app do
103
- use Spec::Support::EndpointFaker
104
- use Grape::Middleware::Error, rescue_all: true
105
- run ExceptionSpec::OtherExceptionApp
106
- end
107
- end
104
+ let(:running_app) { other_exception_app }
105
+ let(:options) { { rescue_all: true } }
106
+
108
107
  it 'does not trap errors other than StandardError' do
109
108
  expect { get '/' }.to raise_error(NotImplementedError, 'snow!')
110
109
  end
@@ -113,13 +112,9 @@ describe Grape::Middleware::Error do
113
112
 
114
113
  context 'Non-StandardError exception with a provided rescue handler' do
115
114
  context 'default error response' do
116
- subject do
117
- Rack::Builder.app do
118
- use Spec::Support::EndpointFaker
119
- use Grape::Middleware::Error, rescue_handlers: { NotImplementedError => nil }
120
- run ExceptionSpec::OtherExceptionApp
121
- end
122
- end
115
+ let(:running_app) { other_exception_app }
116
+ let(:options) { { rescue_handlers: { NotImplementedError => nil } } }
117
+
123
118
  it 'rescues the exception using the default handler' do
124
119
  get '/'
125
120
  expect(last_response.body).to eq('snow!')
@@ -127,13 +122,9 @@ describe Grape::Middleware::Error do
127
122
  end
128
123
 
129
124
  context 'custom error response' do
130
- subject do
131
- Rack::Builder.app do
132
- use Spec::Support::EndpointFaker
133
- use Grape::Middleware::Error, rescue_handlers: { NotImplementedError => -> { Rack::Response.new('rescued', 200, {}) } }
134
- run ExceptionSpec::OtherExceptionApp
135
- end
136
- end
125
+ let(:running_app) { other_exception_app }
126
+ let(:options) { { rescue_handlers: { NotImplementedError => -> { Rack::Response.new('rescued', 200, {}) } } } }
127
+
137
128
  it 'rescues the exception using the provided handler' do
138
129
  get '/'
139
130
  expect(last_response.body).to eq('rescued')
@@ -142,13 +133,9 @@ describe Grape::Middleware::Error do
142
133
  end
143
134
 
144
135
  context do
145
- subject do
146
- Rack::Builder.app do
147
- use Spec::Support::EndpointFaker
148
- use Grape::Middleware::Error, rescue_all: true, default_status: 500
149
- run ExceptionSpec::ExceptionApp
150
- end
151
- end
136
+ let(:running_app) { exception_app }
137
+ let(:options) { { rescue_all: true, default_status: 500 } }
138
+
152
139
  it 'is possible to specify a different default status code' do
153
140
  get '/'
154
141
  expect(last_response.status).to eq(500)
@@ -156,13 +143,9 @@ describe Grape::Middleware::Error do
156
143
  end
157
144
 
158
145
  context do
159
- subject do
160
- Rack::Builder.app do
161
- use Spec::Support::EndpointFaker
162
- use Grape::Middleware::Error, rescue_all: true, format: :json
163
- run ExceptionSpec::ExceptionApp
164
- end
165
- end
146
+ let(:running_app) { exception_app }
147
+ let(:options) { { rescue_all: true, format: :json } }
148
+
166
149
  it 'is possible to return errors in json format' do
167
150
  get '/'
168
151
  expect(last_response.body).to eq('{"error":"rain!"}')
@@ -170,13 +153,9 @@ describe Grape::Middleware::Error do
170
153
  end
171
154
 
172
155
  context do
173
- subject do
174
- Rack::Builder.app do
175
- use Spec::Support::EndpointFaker
176
- use Grape::Middleware::Error, rescue_all: true, format: :json
177
- run ExceptionSpec::ErrorHashApp
178
- end
179
- end
156
+ let(:running_app) { error_hash_app }
157
+ let(:options) { { rescue_all: true, format: :json } }
158
+
180
159
  it 'is possible to return hash errors in json format' do
181
160
  get '/'
182
161
  expect(['{"error":"rain!","detail":"missing widget"}',
@@ -185,13 +164,9 @@ describe Grape::Middleware::Error do
185
164
  end
186
165
 
187
166
  context do
188
- subject do
189
- Rack::Builder.app do
190
- use Spec::Support::EndpointFaker
191
- use Grape::Middleware::Error, rescue_all: true, format: :jsonapi
192
- run ExceptionSpec::ExceptionApp
193
- end
194
- end
167
+ let(:running_app) { exception_app }
168
+ let(:options) { { rescue_all: true, format: :jsonapi } }
169
+
195
170
  it 'is possible to return errors in jsonapi format' do
196
171
  get '/'
197
172
  expect(last_response.body).to eq('{&quot;error&quot;:&quot;rain!&quot;}')
@@ -199,13 +174,8 @@ describe Grape::Middleware::Error do
199
174
  end
200
175
 
201
176
  context do
202
- subject do
203
- Rack::Builder.app do
204
- use Spec::Support::EndpointFaker
205
- use Grape::Middleware::Error, rescue_all: true, format: :jsonapi
206
- run ExceptionSpec::ErrorHashApp
207
- end
208
- end
177
+ let(:running_app) { error_hash_app }
178
+ let(:options) { { rescue_all: true, format: :jsonapi } }
209
179
 
210
180
  it 'is possible to return hash errors in jsonapi format' do
211
181
  get '/'
@@ -215,13 +185,9 @@ describe Grape::Middleware::Error do
215
185
  end
216
186
 
217
187
  context do
218
- subject do
219
- Rack::Builder.app do
220
- use Spec::Support::EndpointFaker
221
- use Grape::Middleware::Error, rescue_all: true, format: :xml
222
- run ExceptionSpec::ExceptionApp
223
- end
224
- end
188
+ let(:running_app) { exception_app }
189
+ let(:options) { { rescue_all: true, format: :xml } }
190
+
225
191
  it 'is possible to return errors in xml format' do
226
192
  get '/'
227
193
  expect(last_response.body).to eq("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<error>\n <message>rain!</message>\n</error>\n")
@@ -229,13 +195,9 @@ describe Grape::Middleware::Error do
229
195
  end
230
196
 
231
197
  context do
232
- subject do
233
- Rack::Builder.app do
234
- use Spec::Support::EndpointFaker
235
- use Grape::Middleware::Error, rescue_all: true, format: :xml
236
- run ExceptionSpec::ErrorHashApp
237
- end
238
- end
198
+ let(:running_app) { error_hash_app }
199
+ let(:options) { { rescue_all: true, format: :xml } }
200
+
239
201
  it 'is possible to return hash errors in xml format' do
240
202
  get '/'
241
203
  expect(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<error>\n <detail>missing widget</detail>\n <error>rain!</error>\n</error>\n",
@@ -244,20 +206,19 @@ describe Grape::Middleware::Error do
244
206
  end
245
207
 
246
208
  context do
247
- subject do
248
- Rack::Builder.app do
249
- use Spec::Support::EndpointFaker
250
- use Grape::Middleware::Error,
251
- rescue_all: true,
252
- format: :custom,
253
- error_formatters: {
254
- custom: lambda do |message, _backtrace, _options, _env, _original_exception|
255
- { custom_formatter: message }.inspect
256
- end
257
- }
258
- run ExceptionSpec::ExceptionApp
259
- end
209
+ let(:running_app) { exception_app }
210
+ let(:options) do
211
+ {
212
+ rescue_all: true,
213
+ format: :custom,
214
+ error_formatters: {
215
+ custom: lambda do |message, _backtrace, _options, _env, _original_exception|
216
+ { custom_formatter: message }.inspect
217
+ end
218
+ }
219
+ }
260
220
  end
221
+
261
222
  it 'is possible to specify a custom formatter' do
262
223
  get '/'
263
224
  expect(last_response.body).to eq('{:custom_formatter=&gt;&quot;rain!&quot;}')
@@ -265,13 +226,9 @@ describe Grape::Middleware::Error do
265
226
  end
266
227
 
267
228
  context do
268
- subject do
269
- Rack::Builder.app do
270
- use Spec::Support::EndpointFaker
271
- use Grape::Middleware::Error
272
- run ExceptionSpec::AccessDeniedApp
273
- end
274
- end
229
+ let(:running_app) { access_denied_app }
230
+ let(:options) { {} }
231
+
275
232
  it 'does not trap regular error! codes' do
276
233
  get '/'
277
234
  expect(last_response.status).to eq(401)
@@ -279,13 +236,9 @@ describe Grape::Middleware::Error do
279
236
  end
280
237
 
281
238
  context do
282
- subject do
283
- Rack::Builder.app do
284
- use Spec::Support::EndpointFaker
285
- use Grape::Middleware::Error, rescue_all: false
286
- run ExceptionSpec::CustomErrorApp
287
- end
288
- end
239
+ let(:running_app) { custom_error_app }
240
+ let(:options) { { rescue_all: false } }
241
+
289
242
  it 'responds to custom Grape exceptions appropriately' do
290
243
  get '/'
291
244
  expect(last_response.status).to eq(400)
@@ -294,16 +247,15 @@ describe Grape::Middleware::Error do
294
247
  end
295
248
 
296
249
  context 'with rescue_options :backtrace and :exception set to true' do
297
- subject do
298
- Rack::Builder.app do
299
- use Spec::Support::EndpointFaker
300
- use Grape::Middleware::Error,
301
- rescue_all: true,
302
- format: :json,
303
- rescue_options: { backtrace: true, original_exception: true }
304
- run ExceptionSpec::ExceptionApp
305
- end
250
+ let(:running_app) { exception_app }
251
+ let(:options) do
252
+ {
253
+ rescue_all: true,
254
+ format: :json,
255
+ rescue_options: { backtrace: true, original_exception: true }
256
+ }
306
257
  end
258
+
307
259
  it 'is possible to return the backtrace and the original exception in json format' do
308
260
  get '/'
309
261
  expect(last_response.body).to include('error', 'rain!', 'backtrace', 'original_exception', 'RuntimeError')
@@ -311,16 +263,15 @@ describe Grape::Middleware::Error do
311
263
  end
312
264
 
313
265
  context do
314
- subject do
315
- Rack::Builder.app do
316
- use Spec::Support::EndpointFaker
317
- use Grape::Middleware::Error,
318
- rescue_all: true,
319
- format: :xml,
320
- rescue_options: { backtrace: true, original_exception: true }
321
- run ExceptionSpec::ExceptionApp
322
- end
266
+ let(:running_app) { exception_app }
267
+ let(:options) do
268
+ {
269
+ rescue_all: true,
270
+ format: :xml,
271
+ rescue_options: { backtrace: true, original_exception: true }
272
+ }
323
273
  end
274
+
324
275
  it 'is possible to return the backtrace and the original exception in xml format' do
325
276
  get '/'
326
277
  expect(last_response.body).to include('error', 'rain!', 'backtrace', 'original-exception', 'RuntimeError')
@@ -328,16 +279,15 @@ describe Grape::Middleware::Error do
328
279
  end
329
280
 
330
281
  context do
331
- subject do
332
- Rack::Builder.app do
333
- use Spec::Support::EndpointFaker
334
- use Grape::Middleware::Error,
335
- rescue_all: true,
336
- format: :txt,
337
- rescue_options: { backtrace: true, original_exception: true }
338
- run ExceptionSpec::ExceptionApp
339
- end
282
+ let(:running_app) { exception_app }
283
+ let(:options) do
284
+ {
285
+ rescue_all: true,
286
+ format: :txt,
287
+ rescue_options: { backtrace: true, original_exception: true }
288
+ }
340
289
  end
290
+
341
291
  it 'is possible to return the backtrace and the original exception in txt format' do
342
292
  get '/'
343
293
  expect(last_response.body).to include('error', 'rain!', 'backtrace', 'original exception', 'RuntimeError')