rspec-rest 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/CHANGELOG.md +12 -1
- data/Gemfile.lock +1 -1
- data/README.md +21 -21
- data/lib/rspec/rest/dsl.rb +67 -5
- data/lib/rspec/rest/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e72f8991e5d53bdb5bd0ccfa7524a42fcf5c99afead0caba45bb8876ef66bf8c
|
|
4
|
+
data.tar.gz: c33cdc064fc0d12c76f42f036b1490732ecbd6aaa1c6c8213bfaef6260e99d03
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 240876e213f49ac41ddc68015bd1d91744df3af41454e53f4cd561a10042f839544fae0ac7537dd3eee68f4c76727e9f1ff07136b8a1e060fcbc068e401aca69
|
|
7
|
+
data.tar.gz: d9c09b903fe84ef94c2290633b1770fd0d05263a909ffa4a9d2aeec6c8aa26e8a7e26dbff6622073d6bf99b8d24b988898a5040a12b7dc4b19a09981c78b02fd
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,18 @@ Semantic Versioning.
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## [0.4.0] - 2026-03-11
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Verb DSL now supports keyword request paths:
|
|
14
|
+
- `get path: "/users", description: "..." do ... end`
|
|
15
|
+
- same keyword `path:` support for `post`, `put`, `patch`, and `delete`.
|
|
16
|
+
|
|
17
|
+
### Deprecated
|
|
18
|
+
- Positional verb path arguments are deprecated and scheduled for removal in `1.0`:
|
|
19
|
+
- `get "/users", description: "..." do ... end`
|
|
20
|
+
Use keyword paths instead:
|
|
21
|
+
- `get path: "/users", description: "..." do ... end`
|
|
11
22
|
|
|
12
23
|
## [0.3.0] - 2026-03-10
|
|
13
24
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -48,13 +48,13 @@ RSpec.describe "Users API" do
|
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
resource "/users" do
|
|
51
|
-
get "/" do
|
|
51
|
+
get path: "/" do
|
|
52
52
|
expect_status 200
|
|
53
53
|
expect_header "Content-Type", "application/json"
|
|
54
54
|
expect_json array_of(hash_including("id" => integer, "email" => string))
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
post "/" do
|
|
57
|
+
post path: "/" do
|
|
58
58
|
json "email" => "carl@example.com", "name" => "Carl"
|
|
59
59
|
expect_status 201
|
|
60
60
|
capture :user_id, "$.id"
|
|
@@ -112,7 +112,7 @@ RSpec.describe "Posts API" do
|
|
|
112
112
|
resource "/posts" do
|
|
113
113
|
with_auth auth_token
|
|
114
114
|
|
|
115
|
-
get "/", description: "returns posts page 1" do
|
|
115
|
+
get path: "/", description: "returns posts page 1" do
|
|
116
116
|
query page: 1, per_page: 10
|
|
117
117
|
|
|
118
118
|
expect_status 200
|
|
@@ -152,14 +152,14 @@ RSpec.describe "Posts API" do
|
|
|
152
152
|
resource "/posts" do
|
|
153
153
|
with_auth auth_token
|
|
154
154
|
|
|
155
|
-
get "/" do
|
|
155
|
+
get path: "/" do
|
|
156
156
|
query page: 1, per_page: 10
|
|
157
157
|
expect_status 200
|
|
158
158
|
expect_json array_of(contract(:post_summary))
|
|
159
159
|
expect_page_size 10
|
|
160
160
|
end
|
|
161
161
|
|
|
162
|
-
get "/{id}" do
|
|
162
|
+
get path: "/{id}" do
|
|
163
163
|
path_params id: 999_999
|
|
164
164
|
expect_error status: 404, message: "Post not found"
|
|
165
165
|
end
|
|
@@ -168,7 +168,7 @@ RSpec.describe "Posts API" do
|
|
|
168
168
|
resource "/uploads" do
|
|
169
169
|
with_auth auth_token
|
|
170
170
|
|
|
171
|
-
post "/" do
|
|
171
|
+
post path: "/" do
|
|
172
172
|
multipart!
|
|
173
173
|
file :file, Rails.root.join("spec/fixtures/files/sample_upload.txt"), content_type: "text/plain"
|
|
174
174
|
expect_status 201
|
|
@@ -206,16 +206,17 @@ Supported config:
|
|
|
206
206
|
|
|
207
207
|
- `resource "/users" do ... end`
|
|
208
208
|
- `get`, `post`, `put`, `patch`, `delete`
|
|
209
|
-
- preferred
|
|
210
|
-
- legacy positional form `get(
|
|
209
|
+
- preferred form: `get(path: "/users", description: "...") { ... }`
|
|
210
|
+
- legacy positional path form `get("/users", description: "...")` is deprecated and will be removed in `1.0`.
|
|
211
211
|
It is deprecated to avoid `Rails/HttpPositionalArguments` false-positives in RuboCop.
|
|
212
|
+
- legacy positional description form `get "/users", "description"` is deprecated and will be removed in `1.0`.
|
|
212
213
|
|
|
213
214
|
Resource paths are composable and support placeholders:
|
|
214
215
|
|
|
215
216
|
```ruby
|
|
216
217
|
resource "/users" do
|
|
217
218
|
resource "/{id}/posts" do
|
|
218
|
-
get "/" do
|
|
219
|
+
get path: "/" do
|
|
219
220
|
path_params id: 1
|
|
220
221
|
expect_status 404
|
|
221
222
|
end
|
|
@@ -227,7 +228,7 @@ Example with an explicit behavior name:
|
|
|
227
228
|
|
|
228
229
|
```ruby
|
|
229
230
|
resource "/users" do
|
|
230
|
-
get "/", description: "returns public users for authenticated client" do
|
|
231
|
+
get path: "/", description: "returns public users for authenticated client" do
|
|
231
232
|
expect_status 200
|
|
232
233
|
end
|
|
233
234
|
end
|
|
@@ -243,9 +244,8 @@ Note: Example names (including `base_path`) are composed when the verb macro is
|
|
|
243
244
|
`rspec-rest` verbs (`get`, `post`, etc.) define examples via DSL macros, and can trigger
|
|
244
245
|
false-positives in some RuboCop cops:
|
|
245
246
|
|
|
246
|
-
- `Rails/HttpPositionalArguments`: use keyword descriptions (`description:`), not positional
|
|
247
|
+
- `Rails/HttpPositionalArguments`: use keyword paths (`path:`) and keyword descriptions (`description:`), not positional arguments.
|
|
247
248
|
- `RSpec/EmptyExampleGroup`: a `context` that only contains `resource` + verb DSL may be flagged as empty.
|
|
248
|
-
|
|
249
249
|
Recommended mitigation is scoped configuration for files that use `rspec-rest`:
|
|
250
250
|
|
|
251
251
|
```yaml
|
|
@@ -261,7 +261,7 @@ If you only have a few affected groups, use an inline disable around the DSL gro
|
|
|
261
261
|
# rubocop:disable RSpec/EmptyExampleGroup
|
|
262
262
|
context "when authenticated" do
|
|
263
263
|
resource "/posts" do
|
|
264
|
-
get "/", description: "returns posts" do
|
|
264
|
+
get path: "/", description: "returns posts" do
|
|
265
265
|
expect_status 200
|
|
266
266
|
end
|
|
267
267
|
end
|
|
@@ -303,12 +303,12 @@ resource "/posts" do
|
|
|
303
303
|
with_auth ENV.fetch("API_TOKEN", "token-123")
|
|
304
304
|
with_headers "X-Client" => "mobile"
|
|
305
305
|
|
|
306
|
-
get "/" do
|
|
306
|
+
get path: "/" do
|
|
307
307
|
query page: 2
|
|
308
308
|
expect_status 200
|
|
309
309
|
end
|
|
310
310
|
|
|
311
|
-
get "/admin" do
|
|
311
|
+
get path: "/admin" do
|
|
312
312
|
header "X-Client", "internal-tool" # request-level override
|
|
313
313
|
query locale: "fr" # request-level override
|
|
314
314
|
expect_status 200
|
|
@@ -333,7 +333,7 @@ Inside verb blocks:
|
|
|
333
333
|
Example:
|
|
334
334
|
|
|
335
335
|
```ruby
|
|
336
|
-
post "/" do
|
|
336
|
+
post path: "/" do
|
|
337
337
|
headers "X-Trace-Id" => "abc-123"
|
|
338
338
|
bearer "token-123"
|
|
339
339
|
query include_details: "true"
|
|
@@ -345,7 +345,7 @@ end
|
|
|
345
345
|
Multipart upload example:
|
|
346
346
|
|
|
347
347
|
```ruby
|
|
348
|
-
post "/uploads" do
|
|
348
|
+
post path: "/uploads" do
|
|
349
349
|
multipart!
|
|
350
350
|
file :file, Rails.root.join("spec/fixtures/files/sample_upload.txt"), content_type: "text/plain"
|
|
351
351
|
expect_status 201
|
|
@@ -404,7 +404,7 @@ expect_json_last { |item| expect(item["id"]).to integer }
|
|
|
404
404
|
`expect_error` is a convenience helper for common API error payload assertions:
|
|
405
405
|
|
|
406
406
|
```ruby
|
|
407
|
-
get "/{id}" do
|
|
407
|
+
get path: "/{id}" do
|
|
408
408
|
path_params id: 999
|
|
409
409
|
expect_error status: 404, message: "Post not found"
|
|
410
410
|
end
|
|
@@ -413,7 +413,7 @@ end
|
|
|
413
413
|
Pagination helpers:
|
|
414
414
|
|
|
415
415
|
```ruby
|
|
416
|
-
get "/" do
|
|
416
|
+
get path: "/" do
|
|
417
417
|
query page: 2, per_page: 10
|
|
418
418
|
expect_status 200
|
|
419
419
|
expect_page_size 10
|
|
@@ -436,7 +436,7 @@ contract :post_summary do
|
|
|
436
436
|
)
|
|
437
437
|
end
|
|
438
438
|
|
|
439
|
-
get "/" do
|
|
439
|
+
get path: "/" do
|
|
440
440
|
expect_status 200
|
|
441
441
|
expect_json array_of(contract(:post_summary))
|
|
442
442
|
end
|
|
@@ -465,7 +465,7 @@ Selector syntax (minimal JSON selector):
|
|
|
465
465
|
Example:
|
|
466
466
|
|
|
467
467
|
```ruby
|
|
468
|
-
post "/" do
|
|
468
|
+
post path: "/" do
|
|
469
469
|
json "email" => "flow@example.com", "name" => "Flow"
|
|
470
470
|
expect_status 201
|
|
471
471
|
capture :user_id, "$.id"
|
data/lib/rspec/rest/dsl.rb
CHANGED
|
@@ -117,11 +117,44 @@ module RSpec
|
|
|
117
117
|
end
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
+
module PathArgumentSupport
|
|
121
|
+
private
|
|
122
|
+
|
|
123
|
+
def warn_on_deprecated_positional_path(_method)
|
|
124
|
+
Deprecation.warn(
|
|
125
|
+
key: :verb_positional_path,
|
|
126
|
+
message: "Positional request paths (for example: get(\"/users\")) are deprecated and will be " \
|
|
127
|
+
"removed in 1.0. Use keyword paths instead (for example: get(path: \"/users\")). " \
|
|
128
|
+
"This avoids RuboCop Rails/HttpPositionalArguments false-positives."
|
|
129
|
+
)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def resolve_path_options(method:, positional_path:, keyword_path:)
|
|
133
|
+
if !positional_path.nil? && !keyword_path.nil?
|
|
134
|
+
raise ArgumentError,
|
|
135
|
+
"#{method}(...) received both positional and keyword paths. Use only `path:`."
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
effective_path = keyword_path.nil? ? positional_path : keyword_path
|
|
139
|
+
if effective_path.nil?
|
|
140
|
+
raise ArgumentError,
|
|
141
|
+
"#{method}(...) requires a request path. Pass it as `path:` (preferred) " \
|
|
142
|
+
"or as the first positional argument."
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
{
|
|
146
|
+
path: effective_path,
|
|
147
|
+
using_positional_path: !positional_path.nil? && keyword_path.nil?
|
|
148
|
+
}
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
120
152
|
module ClassMethods
|
|
121
153
|
include ClassLevelContracts
|
|
122
154
|
include ClassLevelPresets
|
|
123
155
|
include RouteNamingSupport
|
|
124
156
|
include DescriptionArgumentSupport
|
|
157
|
+
include PathArgumentSupport
|
|
125
158
|
|
|
126
159
|
def api(&)
|
|
127
160
|
builder = ApiConfigBuilder.new(rest_config)
|
|
@@ -141,25 +174,28 @@ module RSpec
|
|
|
141
174
|
end
|
|
142
175
|
|
|
143
176
|
HTTP_METHODS.each do |method|
|
|
144
|
-
define_method(method) do |
|
|
145
|
-
|
|
177
|
+
define_method(method) do |positional_path = nil, positional_description = nil, path: nil,
|
|
178
|
+
description: nil, &block|
|
|
179
|
+
path_options, description_options = resolve_verb_options(
|
|
180
|
+
method, positional_path, path, positional_description, description
|
|
181
|
+
)
|
|
146
182
|
resource_path = current_resource_path
|
|
147
183
|
request_presets = deep_dup_presets(current_request_presets)
|
|
148
184
|
example_name = build_example_name(
|
|
149
185
|
method: method,
|
|
150
|
-
path: path,
|
|
186
|
+
path: path_options[:path],
|
|
151
187
|
resource_path: resource_path,
|
|
152
188
|
description: description_options[:description]
|
|
153
189
|
)
|
|
154
190
|
it(example_name) do
|
|
155
191
|
start_rest_request(
|
|
156
192
|
method: method,
|
|
157
|
-
path: path,
|
|
193
|
+
path: path_options[:path],
|
|
158
194
|
resource_path: resource_path,
|
|
159
195
|
presets: request_presets
|
|
160
196
|
)
|
|
161
197
|
instance_eval(&block) if block
|
|
162
|
-
self.class.send(:
|
|
198
|
+
self.class.send(:emit_verb_deprecation_warnings, method, path_options, description_options)
|
|
163
199
|
execute_rest_request_if_pending
|
|
164
200
|
end
|
|
165
201
|
end
|
|
@@ -181,12 +217,31 @@ module RSpec
|
|
|
181
217
|
|
|
182
218
|
private
|
|
183
219
|
|
|
220
|
+
def emit_verb_deprecation_warnings(method, path_options, description_options)
|
|
221
|
+
emit_positional_path_warning(method, path_options)
|
|
222
|
+
emit_positional_description_warning(method, description_options)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def emit_positional_path_warning(method, path_options)
|
|
226
|
+
return unless path_options[:using_positional_path]
|
|
227
|
+
|
|
228
|
+
send(:warn_on_deprecated_positional_path, method)
|
|
229
|
+
end
|
|
230
|
+
|
|
184
231
|
def emit_positional_description_warning(method, description_options)
|
|
185
232
|
return unless description_options[:using_positional_description]
|
|
186
233
|
|
|
187
234
|
send(:warn_on_deprecated_positional_description, method)
|
|
188
235
|
end
|
|
189
236
|
|
|
237
|
+
def resolve_verb_path_options(method, positional_path, path)
|
|
238
|
+
resolve_path_options(
|
|
239
|
+
method: method,
|
|
240
|
+
positional_path: positional_path,
|
|
241
|
+
keyword_path: path
|
|
242
|
+
)
|
|
243
|
+
end
|
|
244
|
+
|
|
190
245
|
def resolve_verb_description_options(method, positional_description, description)
|
|
191
246
|
resolve_description_options(
|
|
192
247
|
method: method,
|
|
@@ -194,6 +249,13 @@ module RSpec
|
|
|
194
249
|
keyword_description: description
|
|
195
250
|
)
|
|
196
251
|
end
|
|
252
|
+
|
|
253
|
+
def resolve_verb_options(method, positional_path, path, positional_description, description)
|
|
254
|
+
[
|
|
255
|
+
resolve_verb_path_options(method, positional_path, path),
|
|
256
|
+
resolve_verb_description_options(method, positional_description, description)
|
|
257
|
+
]
|
|
258
|
+
end
|
|
197
259
|
end
|
|
198
260
|
|
|
199
261
|
module InstanceMethods
|
data/lib/rspec/rest/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rspec-rest
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Carl
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack-test
|