grape 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grape might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -2
- data/.rubocop_todo.yml +80 -0
- data/.travis.yml +2 -2
- data/CHANGELOG.md +21 -2
- data/Gemfile +1 -6
- data/Guardfile +1 -5
- data/README.md +110 -27
- data/Rakefile +1 -1
- data/UPGRADING.md +35 -0
- data/grape.gemspec +5 -2
- data/lib/grape.rb +20 -4
- data/lib/grape/api.rb +25 -467
- data/lib/grape/api/helpers.rb +7 -0
- data/lib/grape/dsl/callbacks.rb +27 -0
- data/lib/grape/dsl/configuration.rb +27 -0
- data/lib/grape/dsl/helpers.rb +86 -0
- data/lib/grape/dsl/inside_route.rb +227 -0
- data/lib/grape/dsl/middleware.rb +33 -0
- data/lib/grape/dsl/parameters.rb +79 -0
- data/lib/grape/dsl/request_response.rb +152 -0
- data/lib/grape/dsl/routing.rb +172 -0
- data/lib/grape/dsl/validations.rb +29 -0
- data/lib/grape/endpoint.rb +6 -226
- data/lib/grape/error_formatter/base.rb +28 -0
- data/lib/grape/error_formatter/json.rb +2 -0
- data/lib/grape/error_formatter/txt.rb +2 -0
- data/lib/grape/error_formatter/xml.rb +2 -0
- data/lib/grape/exceptions/base.rb +6 -0
- data/lib/grape/exceptions/validation.rb +3 -3
- data/lib/grape/exceptions/validation_errors.rb +19 -6
- data/lib/grape/locale/en.yml +5 -3
- data/lib/grape/middleware/auth/base.rb +28 -12
- data/lib/grape/middleware/auth/dsl.rb +35 -0
- data/lib/grape/middleware/auth/strategies.rb +24 -0
- data/lib/grape/middleware/auth/strategy_info.rb +15 -0
- data/lib/grape/validations.rb +3 -92
- data/lib/grape/validations/at_least_one_of.rb +25 -0
- data/lib/grape/validations/coerce.rb +2 -2
- data/lib/grape/validations/exactly_one_of.rb +2 -2
- data/lib/grape/validations/mutual_exclusion.rb +2 -2
- data/lib/grape/validations/presence.rb +1 -1
- data/lib/grape/validations/regexp.rb +1 -1
- data/lib/grape/validations/values.rb +1 -1
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api/helpers_spec.rb +36 -0
- data/spec/grape/api_spec.rb +72 -19
- data/spec/grape/dsl/callbacks_spec.rb +44 -0
- data/spec/grape/dsl/configuration_spec.rb +37 -0
- data/spec/grape/dsl/helpers_spec.rb +54 -0
- data/spec/grape/dsl/inside_route_spec.rb +222 -0
- data/spec/grape/dsl/middleware_spec.rb +40 -0
- data/spec/grape/dsl/parameters_spec.rb +108 -0
- data/spec/grape/dsl/request_response_spec.rb +123 -0
- data/spec/grape/dsl/routing_spec.rb +132 -0
- data/spec/grape/dsl/validations_spec.rb +55 -0
- data/spec/grape/endpoint_spec.rb +60 -11
- data/spec/grape/entity_spec.rb +9 -4
- data/spec/grape/exceptions/validation_errors_spec.rb +31 -1
- data/spec/grape/middleware/auth/base_spec.rb +34 -0
- data/spec/grape/middleware/auth/dsl_spec.rb +53 -0
- data/spec/grape/middleware/auth/strategies_spec.rb +81 -0
- data/spec/grape/middleware/error_spec.rb +33 -1
- data/spec/grape/middleware/exception_spec.rb +13 -0
- data/spec/grape/validations/at_least_one_of_spec.rb +63 -0
- data/spec/grape/validations/exactly_one_of_spec.rb +1 -1
- data/spec/grape/validations/presence_spec.rb +159 -122
- data/spec/grape/validations/zh-CN.yml +1 -1
- data/spec/grape/validations_spec.rb +77 -15
- data/spec/spec_helper.rb +1 -0
- data/spec/support/endpoint_faker.rb +23 -0
- metadata +93 -15
- data/lib/grape/middleware/auth/basic.rb +0 -13
- data/lib/grape/middleware/auth/digest.rb +0 -13
- data/lib/grape/middleware/auth/oauth2.rb +0 -83
- data/spec/grape/middleware/auth/basic_spec.rb +0 -31
- data/spec/grape/middleware/auth/digest_spec.rb +0 -47
- data/spec/grape/middleware/auth/oauth2_spec.rb +0 -135
data/spec/grape/endpoint_spec.rb
CHANGED
@@ -27,7 +27,7 @@ describe Grape::Endpoint do
|
|
27
27
|
expect { get '/' }.to raise_error(NameError)
|
28
28
|
|
29
29
|
Grape::Endpoint.before_each do |endpoint|
|
30
|
-
endpoint.
|
30
|
+
allow(endpoint).to receive(:current_user).and_return("Bob")
|
31
31
|
end
|
32
32
|
|
33
33
|
get '/'
|
@@ -45,7 +45,7 @@ describe Grape::Endpoint do
|
|
45
45
|
Grape::Endpoint.new(Grape::Util::HashStack.new, {
|
46
46
|
path: '/',
|
47
47
|
method: :get
|
48
|
-
|
48
|
+
}, &p)
|
49
49
|
}.not_to raise_error
|
50
50
|
end
|
51
51
|
end
|
@@ -67,6 +67,33 @@ describe Grape::Endpoint do
|
|
67
67
|
expect(last_response.status).to eq(206)
|
68
68
|
expect(last_response.body).to eq("Hello")
|
69
69
|
end
|
70
|
+
|
71
|
+
it 'is set as default to 200 for get' do
|
72
|
+
memoized_status = nil
|
73
|
+
subject.get('/home') do
|
74
|
+
memoized_status = status
|
75
|
+
"Hello"
|
76
|
+
end
|
77
|
+
|
78
|
+
get '/home'
|
79
|
+
expect(last_response.status).to eq(200)
|
80
|
+
expect(memoized_status).to eq(200)
|
81
|
+
expect(last_response.body).to eq("Hello")
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'is set as default to 201 for post' do
|
85
|
+
memoized_status = nil
|
86
|
+
subject.post('/home') do
|
87
|
+
memoized_status = status
|
88
|
+
"Hello"
|
89
|
+
end
|
90
|
+
|
91
|
+
post '/home'
|
92
|
+
expect(last_response.status).to eq(201)
|
93
|
+
expect(memoized_status).to eq(201)
|
94
|
+
expect(last_response.body).to eq("Hello")
|
95
|
+
end
|
96
|
+
|
70
97
|
end
|
71
98
|
|
72
99
|
describe '#header' do
|
@@ -214,33 +241,37 @@ describe Grape::Endpoint do
|
|
214
241
|
end
|
215
242
|
|
216
243
|
it 'has as many keys as there are declared params' do
|
244
|
+
inner_params = nil
|
217
245
|
subject.get '/declared' do
|
218
|
-
declared(params).keys
|
246
|
+
inner_params = declared(params).keys
|
219
247
|
""
|
220
248
|
end
|
221
|
-
|
222
249
|
get '/declared?first=present'
|
223
250
|
expect(last_response.status).to eq(200)
|
251
|
+
expect(inner_params.size).to eq(4)
|
224
252
|
end
|
225
253
|
|
226
254
|
it 'has a optional param with default value all the time' do
|
255
|
+
inner_params = nil
|
227
256
|
subject.get '/declared' do
|
228
|
-
|
257
|
+
inner_params = declared(params)
|
229
258
|
""
|
230
259
|
end
|
231
|
-
|
232
260
|
get '/declared?first=one'
|
233
261
|
expect(last_response.status).to eq(200)
|
262
|
+
expect(inner_params[:third]).to eql('third-default')
|
234
263
|
end
|
235
264
|
|
236
265
|
it 'builds nested params' do
|
266
|
+
inner_params = nil
|
237
267
|
subject.get '/declared' do
|
238
|
-
declared(params)
|
268
|
+
inner_params = declared(params)
|
239
269
|
""
|
240
270
|
end
|
241
271
|
|
242
272
|
get '/declared?first=present&nested[fourth]=1'
|
243
273
|
expect(last_response.status).to eq(200)
|
274
|
+
expect(inner_params[:nested].keys.size).to eq 1
|
244
275
|
end
|
245
276
|
|
246
277
|
it 'builds nested params when given array' do
|
@@ -254,33 +285,38 @@ describe Grape::Endpoint do
|
|
254
285
|
optional :fourth
|
255
286
|
end
|
256
287
|
end
|
288
|
+
inner_params = nil
|
257
289
|
subject.get '/declared' do
|
258
|
-
declared(params)
|
290
|
+
inner_params = declared(params)
|
259
291
|
""
|
260
292
|
end
|
261
293
|
|
262
294
|
get '/declared?first=present&nested[][fourth]=1&nested[][fourth]=2'
|
263
295
|
expect(last_response.status).to eq(200)
|
296
|
+
expect(inner_params[:nested].size).to eq 2
|
264
297
|
end
|
265
298
|
|
266
299
|
it 'filters out any additional params that are given' do
|
300
|
+
inner_params = nil
|
267
301
|
subject.get '/declared' do
|
268
|
-
declared(params)
|
302
|
+
inner_params = declared(params)
|
269
303
|
""
|
270
304
|
end
|
271
|
-
|
272
305
|
get '/declared?first=one&other=two'
|
273
306
|
expect(last_response.status).to eq(200)
|
307
|
+
expect(inner_params.key?(:other)).to eq false
|
274
308
|
end
|
275
309
|
|
276
310
|
it 'stringifies if that option is passed' do
|
311
|
+
inner_params = nil
|
277
312
|
subject.get '/declared' do
|
278
|
-
declared(params, stringify: true)
|
313
|
+
inner_params = declared(params, stringify: true)
|
279
314
|
""
|
280
315
|
end
|
281
316
|
|
282
317
|
get '/declared?first=one&other=two'
|
283
318
|
expect(last_response.status).to eq(200)
|
319
|
+
expect(inner_params["first"]).to eq "one"
|
284
320
|
end
|
285
321
|
|
286
322
|
it 'does not include missing attributes if that option is passed' do
|
@@ -586,6 +622,19 @@ describe Grape::Endpoint do
|
|
586
622
|
expect(last_response.status).to eq(403)
|
587
623
|
expect(last_response.headers['X-Custom']).to eq('value')
|
588
624
|
end
|
625
|
+
|
626
|
+
it 'sets the status code for the endpoint' do
|
627
|
+
memoized_endpoint = nil
|
628
|
+
|
629
|
+
subject.get '/hey' do
|
630
|
+
memoized_endpoint = self
|
631
|
+
error!({ 'dude' => 'rad' }, 403, 'X-Custom' => 'value')
|
632
|
+
end
|
633
|
+
|
634
|
+
get '/hey.json'
|
635
|
+
|
636
|
+
expect(memoized_endpoint.status).to eq(403)
|
637
|
+
end
|
589
638
|
end
|
590
639
|
|
591
640
|
describe '#redirect' do
|
data/spec/grape/entity_spec.rb
CHANGED
@@ -10,17 +10,20 @@ describe Grape::Entity do
|
|
10
10
|
|
11
11
|
describe '#present' do
|
12
12
|
it 'sets the object as the body if no options are provided' do
|
13
|
+
inner_body = nil
|
13
14
|
subject.get '/example' do
|
14
15
|
present(abc: 'def')
|
15
|
-
|
16
|
+
inner_body = body
|
16
17
|
end
|
17
18
|
get '/example'
|
19
|
+
expect(inner_body).to eql(abc: 'def')
|
18
20
|
end
|
19
21
|
|
20
22
|
it 'calls through to the provided entity class if one is given' do
|
23
|
+
entity_mock = Object.new
|
24
|
+
allow(entity_mock).to receive(:represent)
|
25
|
+
|
21
26
|
subject.get '/example' do
|
22
|
-
entity_mock = Object.new
|
23
|
-
entity_mock.should_receive(:represent)
|
24
27
|
present Object.new, with: entity_mock
|
25
28
|
end
|
26
29
|
get '/example'
|
@@ -155,11 +158,13 @@ describe Grape::Entity do
|
|
155
158
|
end
|
156
159
|
|
157
160
|
it 'adds a root key to the output if one is given' do
|
161
|
+
inner_body = nil
|
158
162
|
subject.get '/example' do
|
159
163
|
present({ abc: 'def' }, root: :root)
|
160
|
-
|
164
|
+
inner_body = body
|
161
165
|
end
|
162
166
|
get '/example'
|
167
|
+
expect(inner_body).to eql(root: { abc: 'def' })
|
163
168
|
end
|
164
169
|
|
165
170
|
[:json, :serializable_hash].each do |format|
|
@@ -3,7 +3,7 @@ require 'ostruct'
|
|
3
3
|
|
4
4
|
describe Grape::Exceptions::ValidationErrors do
|
5
5
|
let(:validation_message) { "FooBar is invalid" }
|
6
|
-
let(:validation_error) { OpenStruct.new(
|
6
|
+
let(:validation_error) { OpenStruct.new(params: [validation_message]) }
|
7
7
|
|
8
8
|
context "message" do
|
9
9
|
context "is not repeated" do
|
@@ -16,4 +16,34 @@ describe Grape::Exceptions::ValidationErrors do
|
|
16
16
|
it { expect(message.size).to eq 1 }
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
context 'api' do
|
21
|
+
subject { Class.new(Grape::API) }
|
22
|
+
|
23
|
+
def app
|
24
|
+
subject
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'can return structured json with separate fields' do
|
28
|
+
subject.format :json
|
29
|
+
subject.rescue_from Grape::Exceptions::ValidationErrors do |e|
|
30
|
+
rack_response e.to_json, 400
|
31
|
+
end
|
32
|
+
subject.params do
|
33
|
+
optional :beer
|
34
|
+
optional :wine
|
35
|
+
optional :juice
|
36
|
+
exactly_one_of :beer, :wine, :juice
|
37
|
+
end
|
38
|
+
subject.get '/exactly_one_of' do
|
39
|
+
'exactly_one_of works!'
|
40
|
+
end
|
41
|
+
get '/exactly_one_of', beer: 'string', wine: 'anotherstring'
|
42
|
+
expect(last_response.status).to eq(400)
|
43
|
+
expect(JSON.parse(last_response.body)).to eq([
|
44
|
+
"params" => ["beer", "wine"],
|
45
|
+
"messages" => ["are mutually exclusive"]
|
46
|
+
])
|
47
|
+
end
|
48
|
+
end
|
19
49
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
describe Grape::Middleware::Auth::Base do
|
5
|
+
subject do
|
6
|
+
Class.new(Grape::API) do
|
7
|
+
|
8
|
+
http_basic realm: 'my_realm' do |user, password|
|
9
|
+
user && password && user == password
|
10
|
+
end
|
11
|
+
get '/authorized' do
|
12
|
+
'DONE'
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def app
|
20
|
+
subject
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'authenticates if given valid creds' do
|
24
|
+
get '/authorized', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('admin', 'admin')
|
25
|
+
expect(last_response.status).to eq(200)
|
26
|
+
expect(last_response.body).to eq('DONE')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'throws a 401 is wrong auth is given' do
|
30
|
+
get '/authorized', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('admin', 'wrong')
|
31
|
+
expect(last_response.status).to eq(401)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grape::Middleware::Auth::DSL do
|
4
|
+
subject { Class.new(Grape::API) }
|
5
|
+
|
6
|
+
let(:block) { ->() {} }
|
7
|
+
let(:settings) do
|
8
|
+
{
|
9
|
+
opaque: "secret",
|
10
|
+
proc: block,
|
11
|
+
realm: "API Authorization",
|
12
|
+
type: :http_digest
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.auth' do
|
17
|
+
it 'stets auth parameters' do
|
18
|
+
expect(subject).to receive(:use).with(Grape::Middleware::Auth::Base, settings)
|
19
|
+
|
20
|
+
subject.auth :http_digest, realm: settings[:realm], opaque: settings[:opaque], &settings[:proc]
|
21
|
+
expect(subject.auth).to eq(settings)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'can be called multiple times' do
|
25
|
+
expect(subject).to receive(:use).with(Grape::Middleware::Auth::Base, settings)
|
26
|
+
expect(subject).to receive(:use).with(Grape::Middleware::Auth::Base, settings.merge(realm: 'super_secret'))
|
27
|
+
|
28
|
+
subject.auth :http_digest, realm: settings[:realm], opaque: settings[:opaque], &settings[:proc]
|
29
|
+
first_settings = subject.auth
|
30
|
+
|
31
|
+
subject.auth :http_digest, realm: 'super_secret', opaque: settings[:opaque], &settings[:proc]
|
32
|
+
|
33
|
+
expect(subject.auth).to eq(settings.merge(realm: 'super_secret'))
|
34
|
+
expect(subject.auth.object_id).not_to eq(first_settings.object_id)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '.http_basic' do
|
40
|
+
it 'stets auth parameters' do
|
41
|
+
subject.http_basic realm: 'my_realm', &settings[:proc]
|
42
|
+
expect(subject.auth).to eq(realm: 'my_realm', type: :http_basic, proc: block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '.http_digest' do
|
47
|
+
it 'stets auth parameters' do
|
48
|
+
subject.http_digest realm: 'my_realm', opaque: 'my_opaque', &settings[:proc]
|
49
|
+
expect(subject.auth).to eq(realm: 'my_realm', type: :http_digest, proc: block, opaque: 'my_opaque')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
describe Grape::Middleware::Auth::Strategies do
|
6
|
+
context 'Basic Auth' do
|
7
|
+
def app
|
8
|
+
proc = ->(u, p) { u && p && u == p }
|
9
|
+
Rack::Builder.new do |b|
|
10
|
+
b.use Grape::Middleware::Error
|
11
|
+
b.use(Grape::Middleware::Auth::Base, type: :http_basic, proc: proc)
|
12
|
+
b.run lambda { |env| [200, {}, ["Hello there."]] }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'throws a 401 if no auth is given' do
|
17
|
+
@proc = lambda { false }
|
18
|
+
get '/whatever'
|
19
|
+
expect(last_response.status).to eq(401)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'authenticates if given valid creds' do
|
23
|
+
get '/whatever', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('admin', 'admin')
|
24
|
+
expect(last_response.status).to eq(200)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'throws a 401 is wrong auth is given' do
|
28
|
+
get '/whatever', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('admin', 'wrong')
|
29
|
+
expect(last_response.status).to eq(401)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'Digest MD5 Auth' do
|
34
|
+
RSpec::Matchers.define :be_challenge do
|
35
|
+
match do |actual_response|
|
36
|
+
actual_response.status == 401 &&
|
37
|
+
actual_response['WWW-Authenticate'] =~ /^Digest / &&
|
38
|
+
actual_response.body.empty?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module StrategiesSpec
|
43
|
+
class Test < Grape::API
|
44
|
+
http_digest(realm: 'Test Api', opaque: 'secret') do |username|
|
45
|
+
{ 'foo' => 'bar' }[username]
|
46
|
+
end
|
47
|
+
|
48
|
+
get '/test' do
|
49
|
+
[{ hey: 'you' }, { there: 'bar' }, { foo: 'baz' }]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def app
|
55
|
+
StrategiesSpec::Test
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'is a digest authentication challenge' do
|
59
|
+
get '/test'
|
60
|
+
expect(last_response).to be_challenge
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'throws a 401 if no auth is given' do
|
64
|
+
get '/test'
|
65
|
+
expect(last_response.status).to eq(401)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'authenticates if given valid creds' do
|
69
|
+
digest_authorize "foo", "bar"
|
70
|
+
get '/test'
|
71
|
+
expect(last_response.status).to eq(200)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'throws a 401 if given invalid creds' do
|
75
|
+
digest_authorize "bar", "foo"
|
76
|
+
get '/test'
|
77
|
+
expect(last_response.status).to eq(401)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -1,6 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'grape-entity'
|
2
3
|
|
3
4
|
describe Grape::Middleware::Error do
|
5
|
+
module ErrorSpec
|
6
|
+
class ErrorEntity < Grape::Entity
|
7
|
+
expose :code
|
8
|
+
expose :static
|
9
|
+
|
10
|
+
def static
|
11
|
+
'static text'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
4
15
|
class ErrApp
|
5
16
|
class << self
|
6
17
|
attr_accessor :error
|
@@ -13,12 +24,16 @@ describe Grape::Middleware::Error do
|
|
13
24
|
end
|
14
25
|
|
15
26
|
def app
|
27
|
+
opts = options
|
16
28
|
Rack::Builder.app do
|
17
|
-
use
|
29
|
+
use Spec::Support::EndpointFaker
|
30
|
+
use Grape::Middleware::Error, opts
|
18
31
|
run ErrApp
|
19
32
|
end
|
20
33
|
end
|
21
34
|
|
35
|
+
let(:options) { { default_message: 'Aww, hamburgers.' } }
|
36
|
+
|
22
37
|
it 'sets the status code appropriately' do
|
23
38
|
ErrApp.error = { status: 410 }
|
24
39
|
get '/'
|
@@ -42,4 +57,21 @@ describe Grape::Middleware::Error do
|
|
42
57
|
get '/'
|
43
58
|
expect(last_response.body).to eq('Aww, hamburgers.')
|
44
59
|
end
|
60
|
+
|
61
|
+
context 'with http code' do
|
62
|
+
let(:options) { { default_message: 'Aww, hamburgers.' } }
|
63
|
+
it 'adds the status code if wanted' do
|
64
|
+
ErrApp.error = { message: { code: 200 } }
|
65
|
+
get '/'
|
66
|
+
|
67
|
+
expect(last_response.body).to eq({ code: 200 }.to_json)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'presents an error message' do
|
71
|
+
ErrApp.error = { message: { code: 200, with: ErrorSpec::ErrorEntity } }
|
72
|
+
get '/'
|
73
|
+
|
74
|
+
expect(last_response.body).to eq({ code: 200, static: 'static text' }.to_json)
|
75
|
+
end
|
76
|
+
end
|
45
77
|
end
|