minitest-rack 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,524 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rack/test'
4
+ require 'minitest/assertions'
5
+ require 'minitest/spec'
6
+
7
+ # reopening to add validations functionality
8
+ module Minitest
9
+ # add support for Assert syntax
10
+ module Assertions
11
+ # Tests that the HTTP response status matches the expected value.
12
+ #
13
+ # @param status [Integer] the expected HTTP status code
14
+ #
15
+ # @return [Boolean] true if the status matches, false otherwise
16
+ #
17
+ # @example
18
+ # assert_status(200) # passes if response status is 200 OK
19
+ # assert_status(404) # passes if response status is 404 Not Found
20
+ #
21
+ def assert_status(status)
22
+ msg = "Expected response status to be '#{status}', but was '#{last_response.status}'"
23
+
24
+ assert_equal(status, last_response.status, msg)
25
+ end
26
+
27
+ ## 2xx SUCCCESS
28
+
29
+ # Tests that the HTTP response status is 200 OK.
30
+ #
31
+ # @return [Boolean] true if the response status is 200 OK
32
+ #
33
+ # @example
34
+ # assert_ok # passes if response status is 200 OK
35
+ #
36
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-200-ok
37
+ #
38
+ def assert_ok
39
+ assert_status 200
40
+ end
41
+
42
+ # Tests that the HTTP response status is 201 Created.
43
+ #
44
+ # @return [Boolean] true if the response status is 201 Created
45
+ #
46
+ # @example
47
+ # assert_created # passes if response status is 201 Created
48
+ #
49
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-201-created
50
+ #
51
+ def assert_created
52
+ assert_status 201
53
+ end
54
+
55
+ # Tests that the HTTP response status is 202 Accepted.
56
+ # The request has been accepted but has not been processed yet.
57
+ #
58
+ # NOTE! This code does not guarantee that the request will process successfully.
59
+ #
60
+ # @return [Boolean] true if the response status is 202 Accepted
61
+ #
62
+ # @example
63
+ # assert_accepted # passes if response status is 202 Accepted
64
+ #
65
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-202-accepted
66
+ #
67
+ def assert_accepted
68
+ assert_status 202
69
+ end
70
+
71
+ # Tests that the HTTP response status is 204 No Content.
72
+ # The server accepted the request but is not returning any content.
73
+ # This is often used as a response to a DELETE request.
74
+ #
75
+ # @return [Boolean] true if the response status is 204 No Content
76
+ #
77
+ # @example
78
+ # assert_no_content # passes if response status is 204 No Content
79
+ #
80
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-204-no-content
81
+ #
82
+ def assert_no_content
83
+ assert_status 204
84
+ end
85
+
86
+ # Tests that the HTTP response status is 205 Reset Content.
87
+ #
88
+ # The server accepted the request but requires the client to reset the document view.
89
+ # Similar to a 204 No Content response but this response requires the requester
90
+ # to reset the document view.
91
+ #
92
+ # @return [Boolean] true if the response status is 205 Reset Content
93
+ #
94
+ # @example
95
+ # assert_reset_content # passes if response status is 205 Reset Content
96
+ #
97
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-205-reset-content
98
+ #
99
+ def assert_reset_content
100
+ assert_status 205
101
+ end
102
+
103
+ # Tests that the HTTP response status is 206 Partial Content.
104
+
105
+ # The server is delivering only a portion of the content, as requested by the client
106
+ # via a range header.
107
+ #
108
+ # @return [Boolean] true if the response status is 206 Partial Content
109
+ #
110
+ # @example
111
+ # assert_partial_content # passes if response status is 206 Partial Content
112
+ #
113
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-206-partial-content
114
+ #
115
+ def assert_partial_content
116
+ assert_status 206
117
+ end
118
+
119
+ ## 3xx REDIRECTION
120
+
121
+ # Tests that the HTTP response status is 300 Multiple Choices.
122
+ # Indicates multiple options for the user to follow. This can happen when the server
123
+ # has several suitable responses and the client must select one themselves.
124
+ #
125
+ # @return [Boolean] true if the response status is 300 Multiple Choices
126
+ #
127
+ # @example
128
+ # assert_multiple_choices # passes if response status is 300 Multiple Choices
129
+ #
130
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-300-multiple-choices
131
+ #
132
+ def assert_multiple_choices
133
+ assert_status 300
134
+ end
135
+
136
+ # Tests that the HTTP response status is 301 Moved Permanently.
137
+ # The resource has been moved and all further requests should reference its new URI.
138
+ #
139
+ # @return [Boolean] true if the response status is 301 Moved Permanently
140
+ #
141
+ # @example
142
+ # assert_moved_permanently # passes if response status is 301 Moved Permanently
143
+ #
144
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-301-moved-permanently
145
+ #
146
+ def assert_moved_permanently
147
+ assert_status 301
148
+ end
149
+
150
+ # Tests that the HTTP response status is 302 Found.
151
+ # The HTTP 1.0 specification described this status as "Moved Temporarily",
152
+ # but popular browsers respond to this status similar to behavior intended for 303.
153
+ # The resource can be retrieved by referencing the returned URI.
154
+ #
155
+ # @return [Boolean] true if the response status is 302 Found
156
+ #
157
+ # @example
158
+ # assert_found # passes if response status is 302 Found
159
+ #
160
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-302-found
161
+ #
162
+ def assert_found
163
+ assert_status 302
164
+ end
165
+
166
+ # Tests that the HTTP response status is 304 Not Modified.
167
+ # The resource has not been modified since the version specified in
168
+ # If-Modified-Since or If-Match headers.
169
+ # The resource will not be returned in response body.
170
+ #
171
+ # @return [Boolean] true if the response status is 304 Not Modified
172
+ #
173
+ # @example
174
+ # assert_not_modified # passes if response status is 304 Not Modified
175
+ #
176
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-304-not-modified
177
+ #
178
+ def assert_not_modified
179
+ assert_status 304
180
+ end
181
+
182
+ # Tests that the HTTP response status is 305 Use Proxy.
183
+ # Indicates that the requested resource can only be accessed through a proxy
184
+ # specified in the response's Location header.
185
+ #
186
+ # @return [Boolean] true if the response status is 305 Use Proxy
187
+ #
188
+ # @example
189
+ # assert_use_proxy # passes if response status is 305 Use Proxy
190
+ #
191
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-305-use-proxy
192
+ #
193
+ def assert_use_proxy
194
+ assert_status 305
195
+ end
196
+
197
+ # Tests that the HTTP response status is 306 Switch Proxy.
198
+ # This status code is no longer used. Originally meant to indicate that subsequent
199
+ # requests should use the specified proxy.
200
+ #
201
+ # NOTE: This code is deprecated in HTTP 1.1 and should not be used.
202
+ #
203
+ # @return [Boolean] true if the response status is 306 Switch Proxy
204
+ #
205
+ # @example
206
+ # assert_switch_proxy # passes if response status is 306 Switch Proxy
207
+ #
208
+ # @deprecated No longer used in HTTP 1.1
209
+ #
210
+ def assert_switch_proxy
211
+ assert_status 306
212
+ end
213
+
214
+ # Tests that the HTTP response status is 307 Temporary Redirect.
215
+ # HTTP 1.1. The request should be repeated with the URI provided in the response,
216
+ # but future requests should still call the original URI.
217
+ #
218
+ # @return [Boolean] true if the response status is 307 Temporary Redirect
219
+ #
220
+ # @example
221
+ # assert_temporary_redirect # passes if response status is 307 Temporary Redirect
222
+ #
223
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-307-temporary-redirect
224
+ #
225
+ def assert_temporary_redirect
226
+ assert_status 307
227
+ end
228
+
229
+ # Tests that the HTTP response status is 308 Permanent Redirect.
230
+ # Experimental. The request and all future requests should be repeated with the URI
231
+ # provided in the response.
232
+ # The HTTP method is not allowed to be changed in the subsequent request.
233
+ #
234
+ # @return [Boolean] true if the response status is 308 Permanent Redirect
235
+ #
236
+ # @example
237
+ # assert_permanent_redirect # passes if response status is 308 Permanent Redirect
238
+ #
239
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-308-permanent-redirect
240
+ #
241
+ def assert_permanent_redirect
242
+ assert_status 308
243
+ end
244
+
245
+ ## 4XX CLIENT ERROR
246
+
247
+ # Tests that the HTTP response status is 400 Bad Request.
248
+ # The request could not be fulfilled due to the incorrect syntax of the request.
249
+ # This indicates that the request was malformed, contains invalid syntax,
250
+ # or cannot be processed by the server.
251
+ #
252
+ # @return [Boolean] true if the response status is 400 Bad Request
253
+ #
254
+ # @example
255
+ # assert_bad_request # passes if response status is 400 Bad Request
256
+ #
257
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-400-bad-request
258
+ #
259
+ def assert_bad_request
260
+ assert_status 400
261
+ end
262
+
263
+ # Tests that the HTTP response status is 401 Unauthorized.
264
+ # The requester is not authorized to access the resource. This status code is used when
265
+ # authentication is required but has either failed or not been provided. Similar to 403
266
+ # Forbidden, but indicates specifically that authentication is possible.
267
+ #
268
+ # @return [Boolean] true if the response status is 401 Unauthorized
269
+ #
270
+ # @example
271
+ # assert_unauthorized # passes if response status is 401 Unauthorized
272
+ #
273
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-401-unauthorized
274
+ #
275
+ def assert_unauthorized
276
+ assert_status 401
277
+ end
278
+
279
+ # Tests that the HTTP response status is 403 Forbidden.
280
+ # The request was formatted correctly but the server is refusing to supply
281
+ # the requested resource.
282
+ # Unlike 401, authenticating will not make a difference in the server's response.
283
+ #
284
+ # @return [Boolean] true if the response status is 403 Forbidden
285
+ #
286
+ # @example
287
+ # assert_forbidden # passes if response status is 403 Forbidden
288
+ #
289
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-403-forbidden
290
+ #
291
+ def assert_forbidden
292
+ assert_status 403
293
+ end
294
+
295
+ # Tests that the HTTP response status is 404 Not Found.
296
+ # The resource could not be found. This is often used as a catch-all for all invalid URIs
297
+ # requested of the server.
298
+ #
299
+ # @return [Boolean] true if the response status is 404 Not Found
300
+ #
301
+ # @example
302
+ # assert_not_found # passes if response status is 404 Not Found
303
+ #
304
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-404-not-found
305
+ #
306
+ def assert_not_found
307
+ assert_status 404
308
+ end
309
+
310
+ # Tests that the HTTP response status is 405 Method Not Allowed.
311
+ # The resource was requested using a method that is not allowed.
312
+ # For example, requesting a resource via a POST method when the resource only supports GET.
313
+ #
314
+ # @return [Boolean] true if the response status is 405 Method Not Allowed
315
+ #
316
+ # @example
317
+ # assert_method_not_allowed # passes if response status is 405 Method Not Allowed
318
+ #
319
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-405-method-not-allowed
320
+ #
321
+ def assert_method_not_allowed
322
+ assert_status 405
323
+ end
324
+
325
+ # Tests that the HTTP response status is 406 Not Acceptable.
326
+ # The resource is valid, but cannot be provided in a format specified in the Accept headers
327
+ # in the request.
328
+ #
329
+ # The server sends this error when the client requests a format that the server
330
+ # does not support.
331
+ #
332
+ # @return [Boolean] true if the response status is 406 Not Acceptable
333
+ #
334
+ # @example
335
+ # assert_not_acceptable # passes if response status is 406 Not Acceptable
336
+ #
337
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-406-not-acceptable
338
+ #
339
+ def assert_not_acceptable
340
+ assert_status 406
341
+ end
342
+
343
+ # Tests that the HTTP response status is 407 Proxy Authentication Required.
344
+ # Authentication is required with the proxy before requests can be fulfilled.
345
+ # The proxy server must return information about the authentication scheme required
346
+ # in a Proxy-Authenticate header.
347
+ #
348
+ # @return [Boolean] true if the response status is 407 Proxy Authentication Required
349
+ #
350
+ # @example
351
+ # assert_proxy_authentication_required # passes if response status is 407
352
+ #
353
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-407-proxy-authentication-re
354
+ #
355
+ def assert_proxy_authentication_required
356
+ assert_status 407
357
+ end
358
+
359
+ # Tests that the HTTP response status is 408 Request Timeout.
360
+ # The server timed out waiting for a request from the client.
361
+ # The client is allowed to repeat the request.
362
+ #
363
+ # @return [Boolean] true if the response status is 408 Request Timeout
364
+ #
365
+ # @example
366
+ # assert_request_timeout # passes if response status is 408 Request Timeout
367
+ #
368
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-408-request-timeout
369
+ #
370
+ def assert_request_timeout
371
+ assert_status 408
372
+ end
373
+
374
+ # Tests that the HTTP response status is 415 Unsupported Media Type.
375
+ # The client provided data with a media type that the server does not support.
376
+ # For example, submitting JSON data when only XML is supported.
377
+ #
378
+ # @return [Boolean] true if the response status is 415 Unsupported Media Type
379
+ #
380
+ # @example
381
+ # assert_unsupported_media_type # passes if response status is 415 Unsupported Media Type
382
+ #
383
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-415-unsupported-media-type
384
+ #
385
+ def assert_unsupported_media_type
386
+ assert_status 415
387
+ end
388
+
389
+ # Tests that the HTTP response status is 422 Unprocessable Entity.
390
+ # The request was well-formed but was unable to be processed due to semantic errors.
391
+ # Commonly used when validation fails or malformed content is submitted.
392
+ #
393
+ # @return [Boolean] true if the response status is 422 Unprocessable Entity
394
+ #
395
+ # @example
396
+ # assert_unprocessable_entity # passes if response status is 422 Unprocessable Entity
397
+ #
398
+ # @see https://www.rfc-editor.org/rfc/rfc4918#section-11.2
399
+ #
400
+ def assert_unprocessable_entity
401
+ assert_status 422
402
+ end
403
+
404
+ # Tests that the HTTP response status is 429 Too Many Requests.
405
+ # The user has sent too many requests in a given amount of time ("rate limiting").
406
+ # This status indicates that the client should retry after some time.
407
+ #
408
+ # @return [Boolean] true if the response status is 429 Too Many Requests
409
+ #
410
+ # @example
411
+ # assert_too_many_requests # passes if response status is 429 Too Many Requests
412
+ #
413
+ # @see https://www.rfc-editor.org/rfc/rfc6585#section-4
414
+ #
415
+ def assert_too_many_requests
416
+ assert_status 429
417
+ end
418
+
419
+ ## 5XX SERVER ERROR
420
+
421
+ # Tests that the HTTP response status is 500 Internal Server Error.
422
+ # A generic status for an error in the server itself. This indicates that the server
423
+ # encountered an unexpected condition that prevented it from fulfilling the request.
424
+ #
425
+ # @return [Boolean] true if the response status is 500 Internal Server Error
426
+ #
427
+ # @example
428
+ # assert_internal_server_error # passes if response status is 500 Internal Server Error
429
+ #
430
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-500-internal-server-error
431
+ #
432
+ def assert_internal_server_error
433
+ assert_status 500
434
+ end
435
+
436
+ # Tests that the HTTP response status is 501 Not Implemented.
437
+ # The server cannot respond to the request. This usually implies that the server could
438
+ # possibly support the request in the future — otherwise a 4xx status may be more appropriate.
439
+ #
440
+ # @return [Boolean] true if the response status is 501 Not Implemented
441
+ #
442
+ # @example
443
+ # assert_not_implemented # passes if response status is 501 Not Implemented
444
+ #
445
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-501-not-implemented
446
+ #
447
+ def assert_not_implemented
448
+ assert_status 501
449
+ end
450
+
451
+ # Tests that the HTTP response status is 502 Bad Gateway.
452
+ # The server is acting as a proxy and did not receive an acceptable response from
453
+ # the upstream server. This indicates that the proxy server was unable to complete
454
+ # the request due to issues with the upstream server.
455
+ #
456
+ # @return [Boolean] true if the response status is 502 Bad Gateway
457
+ #
458
+ # @example
459
+ # assert_bad_gateway # passes if response status is 502 Bad Gateway
460
+ #
461
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-502-bad-gateway
462
+ #
463
+ def assert_bad_gateway
464
+ assert_status 502
465
+ end
466
+
467
+ # Tests that the HTTP response status is 503 Service Unavailable.
468
+ # The server is currently unavailable (because it is overloaded or down for maintenance).
469
+ # Generally, this is a temporary state and the server should return information about when
470
+ # to retry with a Retry-After header.
471
+ #
472
+ # @return [Boolean] true if the response status is 503 Service Unavailable
473
+ #
474
+ # @example
475
+ # assert_service_unavailable # passes if response status is 503 Service Unavailable
476
+ #
477
+ # @see https://www.rfc-editor.org/rfc/rfc9110.html#name-503-service-unavailable
478
+ #
479
+ def assert_service_unavailable
480
+ assert_status 503
481
+ end
482
+
483
+ # Tests that the HTTP response status is 508 Loop Detected.
484
+ # The server detected an infinite loop while processing the request. This error occurs
485
+ # when the server detects that the client's request would result in an infinite loop
486
+ # of operations, typically in WebDAV scenarios.
487
+ #
488
+ # @return [Boolean] true if the response status is 508 Loop Detected
489
+ #
490
+ # @example
491
+ # assert_loop_detected # passes if response status is 508 Loop Detected
492
+ #
493
+ # @see https://www.rfc-editor.org/rfc/rfc5842
494
+ #
495
+ def assert_loop_detected
496
+ assert_status 508
497
+ end
498
+ end
499
+ # /module Assertions
500
+
501
+ # add support for Spec syntax
502
+ module Expectations
503
+ infect_an_assertion :assert_ok, :must_be_ok, :reverse
504
+ infect_an_assertion :assert_created, :must_be_created, :reverse
505
+ infect_an_assertion :assert_accepted, :must_be_accepted, :reverse
506
+ infect_an_assertion :assert_no_content, :must_be_no_content, :reverse
507
+ infect_an_assertion :assert_moved_permanently, :must_be_moved_permanently, :reverse
508
+ infect_an_assertion :assert_bad_request, :must_be_bad_request, :reverse
509
+ infect_an_assertion :assert_unauthorized, :must_be_unauthorized, :reverse
510
+ infect_an_assertion :assert_forbidden, :must_be_forbidden, :reverse
511
+ infect_an_assertion :assert_not_found, :must_be_not_found, :reverse
512
+ infect_an_assertion :assert_method_not_allowed, :must_be_method_not_allowed, :reverse
513
+ infect_an_assertion :assert_not_acceptable, :must_be_not_acceptable, :reverse
514
+ infect_an_assertion :assert_request_timeout, :must_be_request_timeout, :reverse
515
+ infect_an_assertion :assert_unsupported_media_type, :must_be_unsupported_media_type, :reverse
516
+ infect_an_assertion :assert_unprocessable_entity, :must_be_unprocessable_entity, :reverse
517
+ infect_an_assertion :assert_too_many_requests, :must_be_too_many_requests, :reverse
518
+ infect_an_assertion :assert_internal_server_error, :must_be_internal_server_error, :reverse
519
+ infect_an_assertion :assert_not_implemented, :must_be_not_implemented, :reverse
520
+ infect_an_assertion :assert_bad_gateway, :must_be_bad_gateway, :reverse
521
+ infect_an_assertion :assert_service_unavailable, :must_be_service_unavailable, :reverse
522
+ infect_an_assertion :assert_loop_detected, :must_be_loop_detected, :reverse
523
+ end
524
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Minitest
4
+ module Rack
5
+ VERSION = '0.2.0'
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest'
4
+ require 'minitest/rack/version'
5
+ require 'rack/test'
6
+
7
+ # reopening to add validations functionality
8
+ module Minitest
9
+ # Module containing test assertions for HTTP response bodies
10
+ module Assertions
11
+ # Assert that the response body matches the expected value
12
+ #
13
+ # @param res [String] The expected response body
14
+ #
15
+ # @return [Boolean] true if the assertion passes
16
+ #
17
+ # @raise [Minitest::Assertion] if the response body doesn't match
18
+ def assert_body(res)
19
+ msg = "Expected response to be '#{res}', but was '#{last_response.body}'"
20
+
21
+ assert_equal(last_response.body, res, msg)
22
+ end
23
+ # /module Assertions
24
+
25
+ # add support for Spec syntax
26
+ module Expectations
27
+ # TODO: figure out how to use and test this
28
+ # infect_an_assertion :assert_body, :must_have_body, :reverse
29
+ end
30
+ end
31
+ end
32
+
33
+ require 'minitest/rack/headers'
34
+ require 'minitest/rack/json'
35
+ require 'minitest/rack/status'
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+
7
+ require 'minitest/rack/version'
8
+
9
+ Gem::Specification.new do |spec|
10
+ spec.name = 'minitest-rack'
11
+ spec.version = Minitest::Rack::VERSION
12
+ spec.authors = ['Kematzy']
13
+ spec.email = ['kematzy@gmail.com']
14
+
15
+ spec.summary = "Minitest & rack-test convenience assertions/expectations for DRY'er faster testing."
16
+ spec.description = 'Save time and energy by writing short effecient obvious assertions/expectations with rack/test'
17
+ spec.homepage = 'https://github.com/kematzy/minitest-rack'
18
+ spec.license = 'MIT'
19
+ spec.required_ruby_version = '>= 3.0.0'
20
+
21
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
22
+ # delete this section to allow pushing this gem to any host.
23
+ # if spec.respond_to?(:metadata)
24
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
25
+ # else
26
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
27
+ # end
28
+
29
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|features)/}) }
30
+ spec.bindir = 'exe'
31
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ['lib']
33
+
34
+ spec.platform = Gem::Platform::RUBY
35
+ spec.extra_rdoc_files = ['README.md', 'LICENSE']
36
+ spec.rdoc_options += ['--quiet', '--line-numbers', '--inline-source', '--title',
37
+ 'Minitest::Rack: rack-test convenience assertions', '--main', 'README.md']
38
+
39
+ spec.add_dependency('json', '~> 2.8.1', '>= 2.8.0')
40
+ spec.add_dependency('minitest', '~> 5.25.0', '>= 5.20.0')
41
+ spec.add_dependency('rack-test', '~> 2.1.0', '>= 2.1.0')
42
+
43
+ spec.metadata['rubygems_mfa_required'] = 'true'
44
+ end