spec_forge 0.4.0 → 0.6.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/.standard.yml +4 -0
- data/CHANGELOG.md +145 -1
- data/README.md +49 -638
- data/flake.lock +3 -3
- data/flake.nix +8 -2
- data/lib/spec_forge/attribute/chainable.rb +208 -20
- data/lib/spec_forge/attribute/factory.rb +141 -12
- data/lib/spec_forge/attribute/faker.rb +64 -15
- data/lib/spec_forge/attribute/global.rb +96 -0
- data/lib/spec_forge/attribute/literal.rb +15 -2
- data/lib/spec_forge/attribute/matcher.rb +188 -13
- data/lib/spec_forge/attribute/parameterized.rb +45 -20
- data/lib/spec_forge/attribute/regex.rb +55 -5
- data/lib/spec_forge/attribute/resolvable.rb +48 -5
- data/lib/spec_forge/attribute/resolvable_array.rb +62 -4
- data/lib/spec_forge/attribute/resolvable_hash.rb +62 -4
- data/lib/spec_forge/attribute/store.rb +65 -0
- data/lib/spec_forge/attribute/transform.rb +33 -5
- data/lib/spec_forge/attribute/variable.rb +37 -6
- data/lib/spec_forge/attribute.rb +168 -66
- data/lib/spec_forge/backtrace_formatter.rb +26 -3
- data/lib/spec_forge/callbacks.rb +79 -0
- data/lib/spec_forge/cli/actions.rb +27 -0
- data/lib/spec_forge/cli/command.rb +78 -24
- data/lib/spec_forge/cli/init.rb +11 -1
- data/lib/spec_forge/cli/new.rb +54 -3
- data/lib/spec_forge/cli/run.rb +20 -0
- data/lib/spec_forge/cli.rb +16 -5
- data/lib/spec_forge/configuration.rb +94 -25
- data/lib/spec_forge/context/callbacks.rb +91 -0
- data/lib/spec_forge/context/global.rb +72 -0
- data/lib/spec_forge/context/store.rb +148 -0
- data/lib/spec_forge/context/variables.rb +91 -0
- data/lib/spec_forge/context.rb +36 -0
- data/lib/spec_forge/core_ext/rspec.rb +24 -4
- data/lib/spec_forge/error.rb +267 -113
- data/lib/spec_forge/factory.rb +33 -14
- data/lib/spec_forge/filter.rb +87 -0
- data/lib/spec_forge/forge.rb +170 -0
- data/lib/spec_forge/http/backend.rb +99 -29
- data/lib/spec_forge/http/client.rb +23 -13
- data/lib/spec_forge/http/request.rb +74 -62
- data/lib/spec_forge/http/verb.rb +79 -0
- data/lib/spec_forge/http.rb +105 -0
- data/lib/spec_forge/loader.rb +254 -0
- data/lib/spec_forge/matchers.rb +130 -0
- data/lib/spec_forge/normalizer/configuration.rb +24 -11
- data/lib/spec_forge/normalizer/constraint.rb +22 -9
- data/lib/spec_forge/normalizer/expectation.rb +31 -12
- data/lib/spec_forge/normalizer/factory.rb +24 -11
- data/lib/spec_forge/normalizer/factory_reference.rb +32 -13
- data/lib/spec_forge/normalizer/global_context.rb +88 -0
- data/lib/spec_forge/normalizer/spec.rb +39 -16
- data/lib/spec_forge/normalizer.rb +255 -41
- data/lib/spec_forge/runner/callbacks.rb +246 -0
- data/lib/spec_forge/runner/debug_proxy.rb +213 -0
- data/lib/spec_forge/runner/listener.rb +54 -0
- data/lib/spec_forge/runner/metadata.rb +58 -0
- data/lib/spec_forge/runner/state.rb +99 -0
- data/lib/spec_forge/runner.rb +133 -119
- data/lib/spec_forge/spec/expectation/constraint.rb +95 -20
- data/lib/spec_forge/spec/expectation.rb +43 -51
- data/lib/spec_forge/spec.rb +83 -96
- data/lib/spec_forge/type.rb +36 -4
- data/lib/spec_forge/version.rb +4 -1
- data/lib/spec_forge.rb +161 -76
- metadata +20 -5
- data/spec_forge/factories/user.yml +0 -4
- data/spec_forge/forge_helper.rb +0 -37
- data/spec_forge/specs/users.yml +0 -65
data/lib/spec_forge.rb
CHANGED
@@ -16,92 +16,177 @@ require "singleton"
|
|
16
16
|
require "thor"
|
17
17
|
require "yaml"
|
18
18
|
|
19
|
+
#
|
20
|
+
# SpecForge: Write expressive API tests in YAML with the power of RSpec matchers
|
21
|
+
#
|
22
|
+
# SpecForge is a testing framework that allows writing API tests in a YAML format
|
23
|
+
# that reads like documentation. It combines the readability of YAML with the
|
24
|
+
# power of RSpec matchers, Faker data generation, and FactoryBot test objects.
|
25
|
+
#
|
26
|
+
# @example Basic spec in YAML
|
27
|
+
# get_user:
|
28
|
+
# path: /users/1
|
29
|
+
# expectations:
|
30
|
+
# - expect:
|
31
|
+
# status: 200
|
32
|
+
# json:
|
33
|
+
# name: kind_of.string
|
34
|
+
# email: /@/
|
35
|
+
#
|
36
|
+
# @example Running specs
|
37
|
+
# # Run all specs
|
38
|
+
# SpecForge.run
|
39
|
+
#
|
40
|
+
# # Run specific file
|
41
|
+
# SpecForge.run(file_name: "users")
|
42
|
+
#
|
43
|
+
# # Run specific spec
|
44
|
+
# SpecForge.run(file_name: "users", spec_name: "create_user")
|
45
|
+
#
|
46
|
+
module SpecForge
|
47
|
+
class << self
|
48
|
+
#
|
49
|
+
# Loads all factories and specs and runs the tests with optional filtering
|
50
|
+
#
|
51
|
+
# This is the main entry point for running SpecForge tests. It loads the
|
52
|
+
# forge_helper.rb file if it exists, configures the environment, loads
|
53
|
+
# factories and specs, and runs the tests through RSpec.
|
54
|
+
#
|
55
|
+
# @param file_name [String, nil] Optional name of spec file to run
|
56
|
+
# @param spec_name [String, nil] Optional name of spec to run
|
57
|
+
# @param expectation_name [String, nil] Optional name of expectation to run
|
58
|
+
#
|
59
|
+
def run(file_name: nil, spec_name: nil, expectation_name: nil)
|
60
|
+
# Load spec_helper.rb
|
61
|
+
forge_helper = SpecForge.forge_path.join("forge_helper.rb")
|
62
|
+
require_relative forge_helper if File.exist?(forge_helper)
|
63
|
+
|
64
|
+
# Validate in case anything was changed
|
65
|
+
configuration.validate
|
66
|
+
|
67
|
+
# Load factories
|
68
|
+
Factory.load_and_register
|
69
|
+
|
70
|
+
# Load the specs from their files and create forges from them
|
71
|
+
forges = Loader.load_from_files.map { |f| Forge.new(*f) }
|
72
|
+
|
73
|
+
# Filter out the specs and expectations
|
74
|
+
forges = Filter.apply(forges, file_name:, spec_name:, expectation_name:)
|
75
|
+
|
76
|
+
# Tell the user that we filtered if we did
|
77
|
+
Filter.announce(forges, file_name:, spec_name:, expectation_name:)
|
78
|
+
|
79
|
+
# Define and run everything
|
80
|
+
Runner.define(forges)
|
81
|
+
Runner.run
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# Returns the directory root for the working directory
|
86
|
+
#
|
87
|
+
# @return [Pathname] The root directory path
|
88
|
+
#
|
89
|
+
def root
|
90
|
+
@root ||= Pathname.pwd
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Returns SpecForge's working directory
|
95
|
+
#
|
96
|
+
# @return [Pathname] The spec_forge directory path
|
97
|
+
#
|
98
|
+
def forge_path
|
99
|
+
@forge_path ||= root.join("spec_forge")
|
100
|
+
end
|
101
|
+
|
102
|
+
#
|
103
|
+
# Returns SpecForge's configuration
|
104
|
+
#
|
105
|
+
# @return [Configuration] The current configuration
|
106
|
+
#
|
107
|
+
def configuration
|
108
|
+
@configuration ||= Configuration.new
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Yields SpecForge's configuration to a block for modification
|
113
|
+
#
|
114
|
+
# @yield [config] Block that receives the configuration object
|
115
|
+
# @yieldparam config [Configuration] The configuration to modify
|
116
|
+
#
|
117
|
+
# @return [Configuration] The updated configuration
|
118
|
+
#
|
119
|
+
def configure(&block)
|
120
|
+
block&.call(configuration)
|
121
|
+
configuration
|
122
|
+
end
|
123
|
+
|
124
|
+
#
|
125
|
+
# Returns a backtrace cleaner configured for SpecForge
|
126
|
+
#
|
127
|
+
# Creates and configures an ActiveSupport::BacktraceCleaner to improve
|
128
|
+
# error messages by removing unnecessary lines and root paths.
|
129
|
+
#
|
130
|
+
# @return [ActiveSupport::BacktraceCleaner] The configured backtrace cleaner
|
131
|
+
#
|
132
|
+
def backtrace_cleaner
|
133
|
+
@backtrace_cleaner ||= begin
|
134
|
+
root = "#{SpecForge.root}/"
|
135
|
+
|
136
|
+
cleaner = ActiveSupport::BacktraceCleaner.new
|
137
|
+
cleaner.add_filter { |line| line.delete_prefix(root) }
|
138
|
+
cleaner.add_silencer { |line| /rubygems|backtrace_cleaner/.match?(line) }
|
139
|
+
cleaner
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
#
|
144
|
+
# Returns the current execution context
|
145
|
+
#
|
146
|
+
# @return [Context] The current context object
|
147
|
+
#
|
148
|
+
def context
|
149
|
+
@context ||= Context.new
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
# Registers a callback for a specific test lifecycle event
|
154
|
+
# Allows custom code execution at specific points during test execution
|
155
|
+
#
|
156
|
+
# @param name [Symbol, String] A unique identifier for this callback
|
157
|
+
# @yield A block to execute when the callback is triggered
|
158
|
+
# @yieldparam context [Object] An object containing context-specific state data, depending
|
159
|
+
# on which hook the callback is triggered from.
|
160
|
+
#
|
161
|
+
# @return [Proc] The registered callback
|
162
|
+
#
|
163
|
+
# @example Registering a custom debug handler
|
164
|
+
# SpecForge.register_callback(:clean_database) do |context|
|
165
|
+
# DatabaseCleaner.clean
|
166
|
+
# end
|
167
|
+
#
|
168
|
+
def register_callback(name, &)
|
169
|
+
Callbacks.register(name, &)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
19
174
|
require_relative "spec_forge/attribute"
|
20
175
|
require_relative "spec_forge/backtrace_formatter"
|
176
|
+
require_relative "spec_forge/callbacks"
|
21
177
|
require_relative "spec_forge/cli"
|
22
178
|
require_relative "spec_forge/configuration"
|
179
|
+
require_relative "spec_forge/context"
|
23
180
|
require_relative "spec_forge/core_ext"
|
24
181
|
require_relative "spec_forge/error"
|
25
182
|
require_relative "spec_forge/factory"
|
183
|
+
require_relative "spec_forge/filter"
|
184
|
+
require_relative "spec_forge/forge"
|
26
185
|
require_relative "spec_forge/http"
|
186
|
+
require_relative "spec_forge/loader"
|
187
|
+
require_relative "spec_forge/matchers"
|
27
188
|
require_relative "spec_forge/normalizer"
|
28
189
|
require_relative "spec_forge/runner"
|
29
190
|
require_relative "spec_forge/spec"
|
30
191
|
require_relative "spec_forge/type"
|
31
192
|
require_relative "spec_forge/version"
|
32
|
-
|
33
|
-
module SpecForge
|
34
|
-
#
|
35
|
-
# Loads all factories and specs located in "path", then runs all of the specs
|
36
|
-
#
|
37
|
-
# @param path [String] The file path that contains factories and specs
|
38
|
-
#
|
39
|
-
def self.run(file_name: nil, spec_name: nil, expectation_name: nil)
|
40
|
-
path = SpecForge.forge
|
41
|
-
|
42
|
-
# Initialize
|
43
|
-
forge_helper = path.join("forge_helper.rb")
|
44
|
-
require_relative forge_helper if File.exist?(forge_helper)
|
45
|
-
|
46
|
-
# Validate
|
47
|
-
configuration.validate
|
48
|
-
|
49
|
-
# Prepare
|
50
|
-
Factory.load_and_register
|
51
|
-
Spec.load_and_define(file_name:, spec_name:, expectation_name:)
|
52
|
-
|
53
|
-
# Run
|
54
|
-
Runner.run
|
55
|
-
end
|
56
|
-
|
57
|
-
#
|
58
|
-
# Returns the directory root for the working directory
|
59
|
-
#
|
60
|
-
# @return [Pathname]
|
61
|
-
#
|
62
|
-
def self.root
|
63
|
-
@root ||= Pathname.pwd
|
64
|
-
end
|
65
|
-
|
66
|
-
#
|
67
|
-
# Returns SpecForge's working directory
|
68
|
-
#
|
69
|
-
# @return [Pathname]
|
70
|
-
#
|
71
|
-
def self.forge
|
72
|
-
@forge ||= root.join("spec_forge")
|
73
|
-
end
|
74
|
-
|
75
|
-
#
|
76
|
-
# Returns SpecForge's configuration
|
77
|
-
#
|
78
|
-
# @return [Config]
|
79
|
-
#
|
80
|
-
def self.configuration
|
81
|
-
@configuration ||= Configuration.new
|
82
|
-
end
|
83
|
-
|
84
|
-
#
|
85
|
-
# Yields SpecForge's configuration to a block
|
86
|
-
#
|
87
|
-
def self.configure(&block)
|
88
|
-
block&.call(configuration)
|
89
|
-
configuration
|
90
|
-
end
|
91
|
-
|
92
|
-
#
|
93
|
-
# Returns a backtrace cleaner configured for SpecForge
|
94
|
-
#
|
95
|
-
# @return [ActiveSupport::BacktraceCleaner]
|
96
|
-
#
|
97
|
-
def self.backtrace_cleaner
|
98
|
-
@backtrace_cleaner ||= begin
|
99
|
-
root = "#{SpecForge.root}/"
|
100
|
-
|
101
|
-
cleaner = ActiveSupport::BacktraceCleaner.new
|
102
|
-
cleaner.add_filter { |line| line.delete_prefix(root) }
|
103
|
-
cleaner.add_silencer { |line| /rubygems|backtrace_cleaner/.match?(line) }
|
104
|
-
cleaner
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spec_forge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-03-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -163,6 +163,7 @@ files:
|
|
163
163
|
- lib/spec_forge/attribute/chainable.rb
|
164
164
|
- lib/spec_forge/attribute/factory.rb
|
165
165
|
- lib/spec_forge/attribute/faker.rb
|
166
|
+
- lib/spec_forge/attribute/global.rb
|
166
167
|
- lib/spec_forge/attribute/literal.rb
|
167
168
|
- lib/spec_forge/attribute/matcher.rb
|
168
169
|
- lib/spec_forge/attribute/parameterized.rb
|
@@ -170,9 +171,11 @@ files:
|
|
170
171
|
- lib/spec_forge/attribute/resolvable.rb
|
171
172
|
- lib/spec_forge/attribute/resolvable_array.rb
|
172
173
|
- lib/spec_forge/attribute/resolvable_hash.rb
|
174
|
+
- lib/spec_forge/attribute/store.rb
|
173
175
|
- lib/spec_forge/attribute/transform.rb
|
174
176
|
- lib/spec_forge/attribute/variable.rb
|
175
177
|
- lib/spec_forge/backtrace_formatter.rb
|
178
|
+
- lib/spec_forge/callbacks.rb
|
176
179
|
- lib/spec_forge/cli.rb
|
177
180
|
- lib/spec_forge/cli/actions.rb
|
178
181
|
- lib/spec_forge/cli/command.rb
|
@@ -180,23 +183,38 @@ files:
|
|
180
183
|
- lib/spec_forge/cli/new.rb
|
181
184
|
- lib/spec_forge/cli/run.rb
|
182
185
|
- lib/spec_forge/configuration.rb
|
186
|
+
- lib/spec_forge/context.rb
|
187
|
+
- lib/spec_forge/context/callbacks.rb
|
188
|
+
- lib/spec_forge/context/global.rb
|
189
|
+
- lib/spec_forge/context/store.rb
|
190
|
+
- lib/spec_forge/context/variables.rb
|
183
191
|
- lib/spec_forge/core_ext.rb
|
184
192
|
- lib/spec_forge/core_ext/rspec.rb
|
185
193
|
- lib/spec_forge/error.rb
|
186
194
|
- lib/spec_forge/factory.rb
|
195
|
+
- lib/spec_forge/filter.rb
|
196
|
+
- lib/spec_forge/forge.rb
|
187
197
|
- lib/spec_forge/http.rb
|
188
198
|
- lib/spec_forge/http/backend.rb
|
189
199
|
- lib/spec_forge/http/client.rb
|
190
200
|
- lib/spec_forge/http/request.rb
|
191
201
|
- lib/spec_forge/http/verb.rb
|
202
|
+
- lib/spec_forge/loader.rb
|
203
|
+
- lib/spec_forge/matchers.rb
|
192
204
|
- lib/spec_forge/normalizer.rb
|
193
205
|
- lib/spec_forge/normalizer/configuration.rb
|
194
206
|
- lib/spec_forge/normalizer/constraint.rb
|
195
207
|
- lib/spec_forge/normalizer/expectation.rb
|
196
208
|
- lib/spec_forge/normalizer/factory.rb
|
197
209
|
- lib/spec_forge/normalizer/factory_reference.rb
|
210
|
+
- lib/spec_forge/normalizer/global_context.rb
|
198
211
|
- lib/spec_forge/normalizer/spec.rb
|
199
212
|
- lib/spec_forge/runner.rb
|
213
|
+
- lib/spec_forge/runner/callbacks.rb
|
214
|
+
- lib/spec_forge/runner/debug_proxy.rb
|
215
|
+
- lib/spec_forge/runner/listener.rb
|
216
|
+
- lib/spec_forge/runner/metadata.rb
|
217
|
+
- lib/spec_forge/runner/state.rb
|
200
218
|
- lib/spec_forge/spec.rb
|
201
219
|
- lib/spec_forge/spec/expectation.rb
|
202
220
|
- lib/spec_forge/spec/expectation/constraint.rb
|
@@ -205,9 +223,6 @@ files:
|
|
205
223
|
- lib/templates/forge_helper.tt
|
206
224
|
- lib/templates/new_factory.tt
|
207
225
|
- lib/templates/new_spec.tt
|
208
|
-
- spec_forge/factories/user.yml
|
209
|
-
- spec_forge/forge_helper.rb
|
210
|
-
- spec_forge/specs/users.yml
|
211
226
|
homepage: https://github.com/itsthedevman/spec_forge
|
212
227
|
licenses:
|
213
228
|
- MIT
|
data/spec_forge/forge_helper.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
## Using Rails? Uncomment to load your app
|
4
|
-
# ENV["RAILS_ENV"] ||= "test"
|
5
|
-
# require_relative "../config/environment"
|
6
|
-
|
7
|
-
## Not using Rails? Load anything you need here
|
8
|
-
# Dir[SpecForge.root.join("lib", "my_api", "models", "**/*.rb")].sort.each { |path| require path }
|
9
|
-
|
10
|
-
## Using RSpec? Uncomment to use your existing configurations
|
11
|
-
# require_relative "../spec/spec_helper"
|
12
|
-
|
13
|
-
SpecForge.configure do |config|
|
14
|
-
## Base URL prefix for all API requests. All test paths will be appended to this URL
|
15
|
-
config.base_url = "http://localhost:3000"
|
16
|
-
|
17
|
-
## Default request headers - commonly used for authentication and content negotiation
|
18
|
-
api_token = ENV.fetch("API_TOKEN", "")
|
19
|
-
config.headers = {
|
20
|
-
"Authorization" => "Bearer #{api_token}"
|
21
|
-
}
|
22
|
-
|
23
|
-
## Default query parameters - useful for API keys or additional request context
|
24
|
-
# config.query = {api_token:}
|
25
|
-
|
26
|
-
## Factory configuration options
|
27
|
-
##
|
28
|
-
## Enable/disable automatic factory discovery. When enabled, SpecForge will automatically
|
29
|
-
## load factories from FactoryBot's default paths. Note: Factories defined in
|
30
|
-
## "spec_forge/factories" are always loaded regardless of this setting.
|
31
|
-
# config.factories.auto_discover = false # Default: true
|
32
|
-
|
33
|
-
##
|
34
|
-
## Additional paths, relative to the project folder, for discovering FactoryBot factories
|
35
|
-
## By default, FactoryBot looks in "spec/factories" and "test/factories"
|
36
|
-
# config.factories.paths += ["custom/factories/path"]
|
37
|
-
end
|
data/spec_forge/specs/users.yml
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
index_users:
|
2
|
-
url: /users
|
3
|
-
expectations:
|
4
|
-
- expect:
|
5
|
-
status: 200
|
6
|
-
|
7
|
-
show_user:
|
8
|
-
url: /users/{id}
|
9
|
-
expectations:
|
10
|
-
- query:
|
11
|
-
id: -1
|
12
|
-
expect:
|
13
|
-
status: 404
|
14
|
-
- query:
|
15
|
-
id: 1
|
16
|
-
expect:
|
17
|
-
status: 200
|
18
|
-
json:
|
19
|
-
name: kind_of.string
|
20
|
-
email: /\w+@example\.com/i
|
21
|
-
|
22
|
-
create_user:
|
23
|
-
url: /users
|
24
|
-
method: post
|
25
|
-
expectations:
|
26
|
-
- expect:
|
27
|
-
status: 400
|
28
|
-
- expect:
|
29
|
-
status: 200
|
30
|
-
json:
|
31
|
-
name: variables.name
|
32
|
-
role: variables.role
|
33
|
-
variables:
|
34
|
-
name: faker.name.name
|
35
|
-
role: user
|
36
|
-
body:
|
37
|
-
name: variables.name
|
38
|
-
|
39
|
-
update_user:
|
40
|
-
url: /users/{id}
|
41
|
-
method: patch
|
42
|
-
query:
|
43
|
-
id: 1
|
44
|
-
variables:
|
45
|
-
number:
|
46
|
-
faker.number.between:
|
47
|
-
from: 100000
|
48
|
-
to: 999999
|
49
|
-
expectations:
|
50
|
-
- expect:
|
51
|
-
status: 200
|
52
|
-
json:
|
53
|
-
name: kind_of.string
|
54
|
-
number: kind_of.integer
|
55
|
-
body:
|
56
|
-
number: variables.number
|
57
|
-
|
58
|
-
destroy_user:
|
59
|
-
url: /users/{id}
|
60
|
-
method: delete
|
61
|
-
query:
|
62
|
-
id: 1
|
63
|
-
expectations:
|
64
|
-
- expect:
|
65
|
-
status: 200
|