spec_forge 0.7.0 → 1.0.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/CHANGELOG.md +139 -9
- data/README.md +125 -203
- data/bin/spec_forge +1 -1
- data/flake.lock +76 -4
- data/flake.nix +5 -4
- data/lib/spec_forge/attribute/chainable.rb +6 -6
- data/lib/spec_forge/attribute/environment.rb +45 -0
- data/lib/spec_forge/attribute/factory.rb +26 -17
- data/lib/spec_forge/attribute/faker.rb +6 -1
- data/lib/spec_forge/attribute/generate.rb +114 -0
- data/lib/spec_forge/attribute/literal.rb +1 -14
- data/lib/spec_forge/attribute/matcher.rb +6 -2
- data/lib/spec_forge/attribute/parameterized.rb +20 -22
- data/lib/spec_forge/attribute/resolvable_array.rb +16 -16
- data/lib/spec_forge/attribute/resolvable_hash.rb +17 -16
- data/lib/spec_forge/attribute/resolvable_struct.rb +67 -0
- data/lib/spec_forge/attribute/template.rb +118 -0
- data/lib/spec_forge/attribute/transform.rb +14 -19
- data/lib/spec_forge/attribute/variable.rb +31 -31
- data/lib/spec_forge/attribute.rb +54 -100
- data/lib/spec_forge/blueprint.rb +27 -0
- data/lib/spec_forge/cli/docs/generate.rb +28 -8
- data/lib/spec_forge/cli/docs.rb +5 -2
- data/lib/spec_forge/cli/init.rb +4 -4
- data/lib/spec_forge/cli/new.rb +78 -27
- data/lib/spec_forge/cli/run.rb +84 -52
- data/lib/spec_forge/cli/serve.rb +6 -0
- data/lib/spec_forge/cli.rb +6 -14
- data/lib/spec_forge/configuration.rb +212 -78
- data/lib/spec_forge/documentation/{loader → builder}/cache.rb +26 -23
- data/lib/spec_forge/documentation/builder/compiler.rb +373 -0
- data/lib/spec_forge/documentation/builder/extractor.rb +75 -0
- data/lib/spec_forge/documentation/builder.rb +77 -329
- data/lib/spec_forge/documentation/document/operation.rb +4 -4
- data/lib/spec_forge/documentation/document.rb +0 -6
- data/lib/spec_forge/documentation/generator.rb +88 -0
- data/lib/spec_forge/documentation/{generators/openapi → openapi/v3_0}/error_formatter.rb +2 -2
- data/lib/spec_forge/documentation/openapi/v3_0/example.rb +1 -1
- data/lib/spec_forge/documentation/openapi/v3_0/media_type.rb +1 -1
- data/lib/spec_forge/documentation/openapi/v3_0/operation.rb +22 -6
- data/lib/spec_forge/documentation/openapi/v3_0/response.rb +29 -7
- data/lib/spec_forge/documentation/openapi/v3_0/schema.rb +20 -2
- data/lib/spec_forge/documentation/openapi/v3_0/tag.rb +1 -1
- data/lib/spec_forge/documentation/openapi/v3_0.rb +116 -0
- data/lib/spec_forge/documentation/openapi.rb +40 -12
- data/lib/spec_forge/documentation.rb +1 -7
- data/lib/spec_forge/error.rb +215 -41
- data/lib/spec_forge/factory.rb +38 -18
- data/lib/spec_forge/forge/action.rb +41 -0
- data/lib/spec_forge/forge/actions/call.rb +33 -0
- data/lib/spec_forge/forge/actions/debug.rb +47 -0
- data/lib/spec_forge/forge/actions/expect.rb +44 -0
- data/lib/spec_forge/forge/actions/request.rb +65 -0
- data/lib/spec_forge/forge/actions/store.rb +31 -0
- data/lib/spec_forge/forge/callbacks.rb +80 -0
- data/lib/spec_forge/forge/context.rb +41 -0
- data/lib/spec_forge/forge/display.rb +503 -0
- data/lib/spec_forge/forge/hooks.rb +131 -0
- data/lib/spec_forge/forge/runner/array_io.rb +81 -0
- data/lib/spec_forge/forge/runner/content_validator.rb +92 -0
- data/lib/spec_forge/forge/runner/header_validator.rb +66 -0
- data/lib/spec_forge/forge/runner/reporter.rb +56 -0
- data/lib/spec_forge/forge/runner/schema_validator.rb +113 -0
- data/lib/spec_forge/forge/runner.rb +118 -0
- data/lib/spec_forge/forge/timer.rb +94 -0
- data/lib/spec_forge/forge/variables.rb +38 -0
- data/lib/spec_forge/forge.rb +207 -133
- data/lib/spec_forge/http/backend.rb +49 -143
- data/lib/spec_forge/http/client.rb +14 -17
- data/lib/spec_forge/http/request.rb +37 -84
- data/lib/spec_forge/http/verb.rb +4 -0
- data/lib/spec_forge/http.rb +0 -5
- data/lib/spec_forge/loader/filter.rb +85 -0
- data/lib/spec_forge/loader/step_processor.rb +282 -0
- data/lib/spec_forge/loader.rb +105 -220
- data/lib/spec_forge/normalizer/default.rb +1 -1
- data/lib/spec_forge/normalizer/structure.rb +140 -0
- data/lib/spec_forge/normalizer/transformers.rb +168 -0
- data/lib/spec_forge/normalizer/validators.rb +50 -8
- data/lib/spec_forge/normalizer.rb +76 -119
- data/lib/spec_forge/normalizers/callback.yml +38 -0
- data/lib/spec_forge/normalizers/configuration.yml +59 -9
- data/lib/spec_forge/normalizers/factory.yml +53 -2
- data/lib/spec_forge/normalizers/factory_reference.yml +63 -2
- data/lib/spec_forge/normalizers/json_schema.yml +79 -0
- data/lib/spec_forge/normalizers/step.yml +506 -0
- data/lib/spec_forge/step/call.rb +36 -0
- data/lib/spec_forge/step/expect.rb +110 -0
- data/lib/spec_forge/step/source.rb +22 -0
- data/lib/spec_forge/step.rb +129 -0
- data/lib/spec_forge/type.rb +115 -66
- data/lib/spec_forge/version.rb +1 -1
- data/lib/spec_forge.rb +44 -106
- data/lib/templates/forge_helper.rb.tt +43 -22
- data/lib/templates/new_blueprint.yml.tt +54 -0
- metadata +75 -44
- data/lib/spec_forge/attribute/global.rb +0 -96
- data/lib/spec_forge/attribute/store.rb +0 -65
- data/lib/spec_forge/backtrace_formatter.rb +0 -50
- data/lib/spec_forge/callbacks.rb +0 -88
- data/lib/spec_forge/context/callbacks.rb +0 -91
- data/lib/spec_forge/context/global.rb +0 -72
- data/lib/spec_forge/context/store.rb +0 -131
- data/lib/spec_forge/context/variables.rb +0 -91
- data/lib/spec_forge/context.rb +0 -36
- data/lib/spec_forge/core_ext/rspec.rb +0 -55
- data/lib/spec_forge/core_ext.rb +0 -5
- data/lib/spec_forge/documentation/generators/base.rb +0 -81
- data/lib/spec_forge/documentation/generators/openapi/base.rb +0 -100
- data/lib/spec_forge/documentation/generators/openapi/v3_0.rb +0 -65
- data/lib/spec_forge/documentation/generators/openapi.rb +0 -59
- data/lib/spec_forge/documentation/generators.rb +0 -17
- data/lib/spec_forge/documentation/loader.rb +0 -159
- data/lib/spec_forge/documentation/openapi/base.rb +0 -33
- data/lib/spec_forge/filter.rb +0 -86
- data/lib/spec_forge/normalizer/definition.rb +0 -248
- data/lib/spec_forge/normalizers/_shared.yml +0 -74
- data/lib/spec_forge/normalizers/constraint.yml +0 -8
- data/lib/spec_forge/normalizers/expectation.yml +0 -47
- data/lib/spec_forge/normalizers/global_context.yml +0 -28
- data/lib/spec_forge/normalizers/spec.yml +0 -50
- data/lib/spec_forge/runner/adapter.rb +0 -183
- data/lib/spec_forge/runner/callbacks.rb +0 -246
- data/lib/spec_forge/runner/debug_proxy.rb +0 -213
- data/lib/spec_forge/runner/listener.rb +0 -54
- data/lib/spec_forge/runner/metadata.rb +0 -58
- data/lib/spec_forge/runner/state.rb +0 -98
- data/lib/spec_forge/runner.rb +0 -75
- data/lib/spec_forge/spec/expectation/constraint.rb +0 -127
- data/lib/spec_forge/spec/expectation.rb +0 -68
- data/lib/spec_forge/spec.rb +0 -68
- data/lib/templates/new_spec.yml.tt +0 -43
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
# Framework Integration
|
|
5
5
|
##########################################
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Rails Integration
|
|
8
8
|
# require_relative "../config/environment"
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## RSpec Integration (includes your existing configurations)
|
|
11
11
|
# require_relative "../spec/spec_helper"
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
## Custom requires (models, libraries, etc)
|
|
14
14
|
# Dir[File.join(__dir__, "..", "lib", "**", "*.rb")].sort.each { |f| require f }
|
|
15
15
|
|
|
16
16
|
##########################################
|
|
@@ -18,31 +18,52 @@
|
|
|
18
18
|
##########################################
|
|
19
19
|
|
|
20
20
|
SpecForge.configure do |config|
|
|
21
|
-
# Base
|
|
21
|
+
# Base URL for all requests
|
|
22
22
|
config.base_url = "http://localhost:3000"
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
## Global variables (available in all blueprints via {{ variable_name }})
|
|
25
|
+
## Use for shared values like auth tokens, API versions, etc.
|
|
26
|
+
# config.global_variables = {
|
|
27
|
+
# api_version: "v1",
|
|
28
|
+
# auth_header: "Bearer #{ENV['API_TOKEN']}"
|
|
29
|
+
# }
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
# config.query = {api_key: ENV['API_KEY']}
|
|
31
|
-
|
|
32
|
-
# Factory configuration
|
|
31
|
+
## Factory configuration
|
|
33
32
|
# config.factories.auto_discover = false # Default: true
|
|
34
33
|
# config.factories.paths += ["lib/factories"] # Adds to default paths
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
#
|
|
38
|
-
# Defaults to printing state overview (-> { puts inspect })
|
|
39
|
-
# Available context: expectation, variables, request, response,
|
|
40
|
-
# expected_status, expected_json
|
|
35
|
+
## Debug configuration
|
|
36
|
+
# Triggers when debug: true is set on a step
|
|
41
37
|
# config.on_debug { binding.pry }
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
# config.
|
|
39
|
+
## Callbacks and Hooks
|
|
40
|
+
# Register reusable callbacks for use with `call:` in blueprints or lifecycle hooks
|
|
41
|
+
|
|
42
|
+
## Basic callback registration
|
|
43
|
+
# config.register_callback(:seed_database) do |context|
|
|
44
|
+
# User.create!(email: "test@test.com")
|
|
45
|
+
# end
|
|
46
|
+
|
|
47
|
+
## With arguments
|
|
48
|
+
# config.register_callback(:create_records) do |context, count:, type:|
|
|
49
|
+
# count.times { type.constantize.create! }
|
|
50
|
+
# end
|
|
51
|
+
|
|
52
|
+
## Complete example: Database cleanup
|
|
53
|
+
# config.register_callback(:cleanup_db) do |context|
|
|
54
|
+
# DatabaseCleaner.clean
|
|
55
|
+
# end
|
|
56
|
+
#
|
|
57
|
+
# config.after(:forge, :cleanup_db) # Runs once after all tests
|
|
58
|
+
|
|
59
|
+
## Hooks can also be defined directly (useful for simple one-off hooks)
|
|
60
|
+
# config.after(:step) do |context|
|
|
61
|
+
# next unless context.step.request?
|
|
62
|
+
#
|
|
63
|
+
# request = context.variables[:request]
|
|
64
|
+
# puts "→ #{request[:http_verb]} #{request[:url]}"
|
|
65
|
+
# end
|
|
66
|
+
|
|
67
|
+
## Test Framework Configuration
|
|
68
|
+
# config.rspec.formatter = :documentation
|
|
48
69
|
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# <%= original_name %>.yml
|
|
2
|
+
|
|
3
|
+
# Store some test data
|
|
4
|
+
- store:
|
|
5
|
+
test_email: "test@example.com"
|
|
6
|
+
test_name: "Test <%= singular_name.titleize %>"
|
|
7
|
+
|
|
8
|
+
# Create a <%= singular_name %>
|
|
9
|
+
- name: "Create <%= singular_name %>"
|
|
10
|
+
request:
|
|
11
|
+
path: /<%= plural_name %>
|
|
12
|
+
method: POST
|
|
13
|
+
json:
|
|
14
|
+
name: "{{ test_name }}"
|
|
15
|
+
email: "{{ test_email }}"
|
|
16
|
+
expect:
|
|
17
|
+
- status: 201
|
|
18
|
+
json:
|
|
19
|
+
shape:
|
|
20
|
+
id: integer
|
|
21
|
+
name: string
|
|
22
|
+
email: string
|
|
23
|
+
store:
|
|
24
|
+
<%= singular_name %>_id: "{{ response.body.id }}"
|
|
25
|
+
|
|
26
|
+
# Get the <%= singular_name %> we just created
|
|
27
|
+
- name: "Show <%= singular_name %>"
|
|
28
|
+
request:
|
|
29
|
+
path: "/<%= plural_name %>/{{ <%= singular_name %>_id }}"
|
|
30
|
+
method: GET
|
|
31
|
+
expect:
|
|
32
|
+
- status: 200
|
|
33
|
+
json:
|
|
34
|
+
content:
|
|
35
|
+
id: "{{ <%= singular_name %>_id }}"
|
|
36
|
+
name: "{{ test_name }}"
|
|
37
|
+
|
|
38
|
+
# Update the <%= singular_name %>
|
|
39
|
+
- name: "Update <%= singular_name %>"
|
|
40
|
+
request:
|
|
41
|
+
path: "/<%= plural_name %>/{{ <%= singular_name %>_id }}"
|
|
42
|
+
method: PATCH
|
|
43
|
+
json:
|
|
44
|
+
name: "Updated <%= singular_name.titleize %>"
|
|
45
|
+
expect:
|
|
46
|
+
- status: 200
|
|
47
|
+
|
|
48
|
+
# Delete the <%= singular_name %>
|
|
49
|
+
- name: "Delete <%= singular_name %>"
|
|
50
|
+
request:
|
|
51
|
+
path: "/<%= plural_name %>/{{ <%= singular_name %>_id }}"
|
|
52
|
+
method: DELETE
|
|
53
|
+
expect:
|
|
54
|
+
- status: 200
|
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: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bryan
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-01-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
19
|
+
version: '6.1'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
26
|
+
version: '6.1'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: commander
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -44,14 +44,14 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '0.
|
|
47
|
+
version: '0.9'
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '0.
|
|
54
|
+
version: '0.9'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: factory_bot
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -122,6 +122,20 @@ dependencies:
|
|
|
122
122
|
- - "~>"
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
124
|
version: 0.10.1
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: pastel
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - "~>"
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0.8'
|
|
132
|
+
type: :runtime
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - "~>"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0.8'
|
|
125
139
|
- !ruby/object:Gem::Dependency
|
|
126
140
|
name: rspec
|
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -178,6 +192,20 @@ dependencies:
|
|
|
178
192
|
- - "~>"
|
|
179
193
|
- !ruby/object:Gem::Version
|
|
180
194
|
version: '1.9'
|
|
195
|
+
- !ruby/object:Gem::Dependency
|
|
196
|
+
name: zeitwerk
|
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
|
198
|
+
requirements:
|
|
199
|
+
- - "~>"
|
|
200
|
+
- !ruby/object:Gem::Version
|
|
201
|
+
version: '2.7'
|
|
202
|
+
type: :runtime
|
|
203
|
+
prerelease: false
|
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
205
|
+
requirements:
|
|
206
|
+
- - "~>"
|
|
207
|
+
- !ruby/object:Gem::Version
|
|
208
|
+
version: '2.7'
|
|
181
209
|
description: Write API tests in YAML without sacrificing power. SpecForge combines
|
|
182
210
|
RSpec's matcher system, Faker's data generation, and factory patterns into a clean,
|
|
183
211
|
declarative syntax that eliminates boilerplate while preserving control over your
|
|
@@ -203,9 +231,10 @@ files:
|
|
|
203
231
|
- lib/spec_forge.rb
|
|
204
232
|
- lib/spec_forge/attribute.rb
|
|
205
233
|
- lib/spec_forge/attribute/chainable.rb
|
|
234
|
+
- lib/spec_forge/attribute/environment.rb
|
|
206
235
|
- lib/spec_forge/attribute/factory.rb
|
|
207
236
|
- lib/spec_forge/attribute/faker.rb
|
|
208
|
-
- lib/spec_forge/attribute/
|
|
237
|
+
- lib/spec_forge/attribute/generate.rb
|
|
209
238
|
- lib/spec_forge/attribute/literal.rb
|
|
210
239
|
- lib/spec_forge/attribute/matcher.rb
|
|
211
240
|
- lib/spec_forge/attribute/parameterized.rb
|
|
@@ -213,11 +242,11 @@ files:
|
|
|
213
242
|
- lib/spec_forge/attribute/resolvable.rb
|
|
214
243
|
- lib/spec_forge/attribute/resolvable_array.rb
|
|
215
244
|
- lib/spec_forge/attribute/resolvable_hash.rb
|
|
216
|
-
- lib/spec_forge/attribute/
|
|
245
|
+
- lib/spec_forge/attribute/resolvable_struct.rb
|
|
246
|
+
- lib/spec_forge/attribute/template.rb
|
|
217
247
|
- lib/spec_forge/attribute/transform.rb
|
|
218
248
|
- lib/spec_forge/attribute/variable.rb
|
|
219
|
-
- lib/spec_forge/
|
|
220
|
-
- lib/spec_forge/callbacks.rb
|
|
249
|
+
- lib/spec_forge/blueprint.rb
|
|
221
250
|
- lib/spec_forge/cli.rb
|
|
222
251
|
- lib/spec_forge/cli/actions.rb
|
|
223
252
|
- lib/spec_forge/cli/command.rb
|
|
@@ -228,32 +257,22 @@ files:
|
|
|
228
257
|
- lib/spec_forge/cli/run.rb
|
|
229
258
|
- lib/spec_forge/cli/serve.rb
|
|
230
259
|
- lib/spec_forge/configuration.rb
|
|
231
|
-
- lib/spec_forge/context.rb
|
|
232
|
-
- lib/spec_forge/context/callbacks.rb
|
|
233
|
-
- lib/spec_forge/context/global.rb
|
|
234
|
-
- lib/spec_forge/context/store.rb
|
|
235
|
-
- lib/spec_forge/context/variables.rb
|
|
236
|
-
- lib/spec_forge/core_ext.rb
|
|
237
260
|
- lib/spec_forge/core_ext/array.rb
|
|
238
|
-
- lib/spec_forge/core_ext/rspec.rb
|
|
239
261
|
- lib/spec_forge/documentation.rb
|
|
240
262
|
- lib/spec_forge/documentation/builder.rb
|
|
263
|
+
- lib/spec_forge/documentation/builder/cache.rb
|
|
264
|
+
- lib/spec_forge/documentation/builder/compiler.rb
|
|
265
|
+
- lib/spec_forge/documentation/builder/extractor.rb
|
|
241
266
|
- lib/spec_forge/documentation/document.rb
|
|
242
267
|
- lib/spec_forge/documentation/document/operation.rb
|
|
243
268
|
- lib/spec_forge/documentation/document/parameter.rb
|
|
244
269
|
- lib/spec_forge/documentation/document/request_body.rb
|
|
245
270
|
- lib/spec_forge/documentation/document/response.rb
|
|
246
271
|
- lib/spec_forge/documentation/document/response_body.rb
|
|
247
|
-
- lib/spec_forge/documentation/
|
|
248
|
-
- lib/spec_forge/documentation/generators/base.rb
|
|
249
|
-
- lib/spec_forge/documentation/generators/openapi.rb
|
|
250
|
-
- lib/spec_forge/documentation/generators/openapi/base.rb
|
|
251
|
-
- lib/spec_forge/documentation/generators/openapi/error_formatter.rb
|
|
252
|
-
- lib/spec_forge/documentation/generators/openapi/v3_0.rb
|
|
253
|
-
- lib/spec_forge/documentation/loader.rb
|
|
254
|
-
- lib/spec_forge/documentation/loader/cache.rb
|
|
272
|
+
- lib/spec_forge/documentation/generator.rb
|
|
255
273
|
- lib/spec_forge/documentation/openapi.rb
|
|
256
|
-
- lib/spec_forge/documentation/openapi/
|
|
274
|
+
- lib/spec_forge/documentation/openapi/v3_0.rb
|
|
275
|
+
- lib/spec_forge/documentation/openapi/v3_0/error_formatter.rb
|
|
257
276
|
- lib/spec_forge/documentation/openapi/v3_0/example.rb
|
|
258
277
|
- lib/spec_forge/documentation/openapi/v3_0/media_type.rb
|
|
259
278
|
- lib/spec_forge/documentation/openapi/v3_0/operation.rb
|
|
@@ -262,42 +281,54 @@ files:
|
|
|
262
281
|
- lib/spec_forge/documentation/openapi/v3_0/tag.rb
|
|
263
282
|
- lib/spec_forge/error.rb
|
|
264
283
|
- lib/spec_forge/factory.rb
|
|
265
|
-
- lib/spec_forge/filter.rb
|
|
266
284
|
- lib/spec_forge/forge.rb
|
|
285
|
+
- lib/spec_forge/forge/action.rb
|
|
286
|
+
- lib/spec_forge/forge/actions/call.rb
|
|
287
|
+
- lib/spec_forge/forge/actions/debug.rb
|
|
288
|
+
- lib/spec_forge/forge/actions/expect.rb
|
|
289
|
+
- lib/spec_forge/forge/actions/request.rb
|
|
290
|
+
- lib/spec_forge/forge/actions/store.rb
|
|
291
|
+
- lib/spec_forge/forge/callbacks.rb
|
|
292
|
+
- lib/spec_forge/forge/context.rb
|
|
293
|
+
- lib/spec_forge/forge/display.rb
|
|
294
|
+
- lib/spec_forge/forge/hooks.rb
|
|
295
|
+
- lib/spec_forge/forge/runner.rb
|
|
296
|
+
- lib/spec_forge/forge/runner/array_io.rb
|
|
297
|
+
- lib/spec_forge/forge/runner/content_validator.rb
|
|
298
|
+
- lib/spec_forge/forge/runner/header_validator.rb
|
|
299
|
+
- lib/spec_forge/forge/runner/reporter.rb
|
|
300
|
+
- lib/spec_forge/forge/runner/schema_validator.rb
|
|
301
|
+
- lib/spec_forge/forge/timer.rb
|
|
302
|
+
- lib/spec_forge/forge/variables.rb
|
|
267
303
|
- lib/spec_forge/http.rb
|
|
268
304
|
- lib/spec_forge/http/backend.rb
|
|
269
305
|
- lib/spec_forge/http/client.rb
|
|
270
306
|
- lib/spec_forge/http/request.rb
|
|
271
307
|
- lib/spec_forge/http/verb.rb
|
|
272
308
|
- lib/spec_forge/loader.rb
|
|
309
|
+
- lib/spec_forge/loader/filter.rb
|
|
310
|
+
- lib/spec_forge/loader/step_processor.rb
|
|
273
311
|
- lib/spec_forge/matchers.rb
|
|
274
312
|
- lib/spec_forge/normalizer.rb
|
|
275
313
|
- lib/spec_forge/normalizer/default.rb
|
|
276
|
-
- lib/spec_forge/normalizer/
|
|
314
|
+
- lib/spec_forge/normalizer/structure.rb
|
|
315
|
+
- lib/spec_forge/normalizer/transformers.rb
|
|
277
316
|
- lib/spec_forge/normalizer/validators.rb
|
|
278
|
-
- lib/spec_forge/normalizers/
|
|
317
|
+
- lib/spec_forge/normalizers/callback.yml
|
|
279
318
|
- lib/spec_forge/normalizers/configuration.yml
|
|
280
|
-
- lib/spec_forge/normalizers/constraint.yml
|
|
281
|
-
- lib/spec_forge/normalizers/expectation.yml
|
|
282
319
|
- lib/spec_forge/normalizers/factory.yml
|
|
283
320
|
- lib/spec_forge/normalizers/factory_reference.yml
|
|
284
|
-
- lib/spec_forge/normalizers/
|
|
285
|
-
- lib/spec_forge/normalizers/
|
|
286
|
-
- lib/spec_forge/
|
|
287
|
-
- lib/spec_forge/
|
|
288
|
-
- lib/spec_forge/
|
|
289
|
-
- lib/spec_forge/
|
|
290
|
-
- lib/spec_forge/runner/listener.rb
|
|
291
|
-
- lib/spec_forge/runner/metadata.rb
|
|
292
|
-
- lib/spec_forge/runner/state.rb
|
|
293
|
-
- lib/spec_forge/spec.rb
|
|
294
|
-
- lib/spec_forge/spec/expectation.rb
|
|
295
|
-
- lib/spec_forge/spec/expectation/constraint.rb
|
|
321
|
+
- lib/spec_forge/normalizers/json_schema.yml
|
|
322
|
+
- lib/spec_forge/normalizers/step.yml
|
|
323
|
+
- lib/spec_forge/step.rb
|
|
324
|
+
- lib/spec_forge/step/call.rb
|
|
325
|
+
- lib/spec_forge/step/expect.rb
|
|
326
|
+
- lib/spec_forge/step/source.rb
|
|
296
327
|
- lib/spec_forge/type.rb
|
|
297
328
|
- lib/spec_forge/version.rb
|
|
298
329
|
- lib/templates/forge_helper.rb.tt
|
|
330
|
+
- lib/templates/new_blueprint.yml.tt
|
|
299
331
|
- lib/templates/new_factory.yml.tt
|
|
300
|
-
- lib/templates/new_spec.yml.tt
|
|
301
332
|
- lib/templates/openapi.yml.tt
|
|
302
333
|
- lib/templates/redoc.html.tt
|
|
303
334
|
- lib/templates/swagger.html.tt
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SpecForge
|
|
4
|
-
class Attribute
|
|
5
|
-
#
|
|
6
|
-
# Represents an attribute that references values from the global context
|
|
7
|
-
#
|
|
8
|
-
# This class allows accessing shared data defined at the global level through
|
|
9
|
-
# namespaced references. It provides access to global variables that are shared
|
|
10
|
-
# across all specs in a file, enabling consistent test data without repetition.
|
|
11
|
-
#
|
|
12
|
-
# Currently supports the "variables" namespace.
|
|
13
|
-
#
|
|
14
|
-
# @example Basic usage in YAML
|
|
15
|
-
# # Reference a global variable in a spec
|
|
16
|
-
# session_token: global.variables.session_token
|
|
17
|
-
#
|
|
18
|
-
# # Using within a request body
|
|
19
|
-
# body:
|
|
20
|
-
# api_version: global.variables.api_version
|
|
21
|
-
# auth_token: global.variables.auth_token
|
|
22
|
-
#
|
|
23
|
-
class Global < Attribute
|
|
24
|
-
#
|
|
25
|
-
# Regular expression pattern that matches attribute keywords with this prefix
|
|
26
|
-
# Used for identifying this attribute type during parsing
|
|
27
|
-
#
|
|
28
|
-
# @return [Regexp]
|
|
29
|
-
#
|
|
30
|
-
KEYWORD_REGEX = /^global\./i
|
|
31
|
-
|
|
32
|
-
#
|
|
33
|
-
# An array of valid namespaces that can be access on global
|
|
34
|
-
#
|
|
35
|
-
# @return [Array<String>]
|
|
36
|
-
#
|
|
37
|
-
VALID_NAMESPACES = %w[
|
|
38
|
-
variables
|
|
39
|
-
].freeze
|
|
40
|
-
|
|
41
|
-
#
|
|
42
|
-
# Creates a new global attribute from the input string
|
|
43
|
-
#
|
|
44
|
-
# Parses the input string to extract the namespace to validate it
|
|
45
|
-
# Conversion happens when `#value` is called
|
|
46
|
-
#
|
|
47
|
-
# @raise [Error::InvalidGlobalNamespaceError] If an unsupported namespace is referenced
|
|
48
|
-
#
|
|
49
|
-
def initialize(...)
|
|
50
|
-
super
|
|
51
|
-
|
|
52
|
-
# Check to make sure the namespace is valid
|
|
53
|
-
namespace = input.split(".").second
|
|
54
|
-
|
|
55
|
-
if !VALID_NAMESPACES.include?(namespace)
|
|
56
|
-
raise Error::InvalidGlobalNamespaceError, namespace
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
#
|
|
61
|
-
# Converts the global reference into an underlying attribute
|
|
62
|
-
#
|
|
63
|
-
# Parses the input and returns the corresponding attribute based on the namespace.
|
|
64
|
-
# Currently supports extracting variables from the global context.
|
|
65
|
-
#
|
|
66
|
-
# @return [Attribute] An attribute representing the referenced global value
|
|
67
|
-
#
|
|
68
|
-
def value
|
|
69
|
-
# Skip the "global" prefix
|
|
70
|
-
components = input.split(".")[1..]
|
|
71
|
-
namespace = components.first
|
|
72
|
-
|
|
73
|
-
global_context = SpecForge.context.global
|
|
74
|
-
|
|
75
|
-
case namespace
|
|
76
|
-
when "variables"
|
|
77
|
-
variable_input = components.join(".")
|
|
78
|
-
variable = Attribute::Variable.new(variable_input)
|
|
79
|
-
variable.bind_variables(global_context.variables.to_h)
|
|
80
|
-
variable
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
#
|
|
85
|
-
# Resolves the global reference to its actual value
|
|
86
|
-
#
|
|
87
|
-
# Delegates resolution to the underlying attribute and caches the result
|
|
88
|
-
#
|
|
89
|
-
# @return [Object] The fully resolved value from the global context
|
|
90
|
-
#
|
|
91
|
-
def resolved
|
|
92
|
-
@resolved ||= value.resolved
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
end
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SpecForge
|
|
4
|
-
class Attribute
|
|
5
|
-
#
|
|
6
|
-
# Represents an attribute that references values from stored test results
|
|
7
|
-
#
|
|
8
|
-
# This class allows accessing data from previous test executions that were
|
|
9
|
-
# saved using the `store_as` directive. It provides access to response data
|
|
10
|
-
# including status, headers, and body from previously run expectations.
|
|
11
|
-
#
|
|
12
|
-
# @example Basic usage in YAML
|
|
13
|
-
# create_user:
|
|
14
|
-
# path: /users
|
|
15
|
-
# method: post
|
|
16
|
-
# expectations:
|
|
17
|
-
# - store_as: new_user
|
|
18
|
-
# body:
|
|
19
|
-
# name: faker.name.name
|
|
20
|
-
# expect:
|
|
21
|
-
# status: 201
|
|
22
|
-
#
|
|
23
|
-
# get_user:
|
|
24
|
-
# path: /users/{id}
|
|
25
|
-
# expectations:
|
|
26
|
-
# - query:
|
|
27
|
-
# id: store.new_user.body.id
|
|
28
|
-
# expect:
|
|
29
|
-
# status: 200
|
|
30
|
-
#
|
|
31
|
-
# @example Accessing specific response components
|
|
32
|
-
# check_status:
|
|
33
|
-
# path: /health
|
|
34
|
-
# expectations:
|
|
35
|
-
# - variables:
|
|
36
|
-
# expected_status: store.new_user.status
|
|
37
|
-
# auth_token: store.new_user.headers.authorization
|
|
38
|
-
# user_name: store.new_user.body.user.name
|
|
39
|
-
# expect:
|
|
40
|
-
# status: 200
|
|
41
|
-
#
|
|
42
|
-
class Store < Attribute
|
|
43
|
-
include Chainable
|
|
44
|
-
|
|
45
|
-
#
|
|
46
|
-
# Regular expression pattern that matches attribute keywords with this prefix
|
|
47
|
-
# Used for identifying this attribute type during parsing
|
|
48
|
-
#
|
|
49
|
-
# @return [Regexp]
|
|
50
|
-
#
|
|
51
|
-
KEYWORD_REGEX = /^store\./i
|
|
52
|
-
|
|
53
|
-
alias_method :stored_id, :header
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
# Returns the base object for the variable chain
|
|
57
|
-
#
|
|
58
|
-
# @return [Context::Store::Entry, nil] The stored entry or nil if not found
|
|
59
|
-
#
|
|
60
|
-
def base_object
|
|
61
|
-
@base_object ||= SpecForge.context.store[stored_id.to_s]
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SpecForge
|
|
4
|
-
#
|
|
5
|
-
# Used internally by RSpec to format backtraces for test failures
|
|
6
|
-
# Customizes error output to make it more readable and useful for SpecForge
|
|
7
|
-
#
|
|
8
|
-
module BacktraceFormatter
|
|
9
|
-
#
|
|
10
|
-
# Returns the RSpec backtrace formatter instance
|
|
11
|
-
# Lazily initializes the formatter on first access
|
|
12
|
-
#
|
|
13
|
-
# @return [RSpec::Core::BacktraceFormatter] The backtrace formatter
|
|
14
|
-
#
|
|
15
|
-
def self.formatter
|
|
16
|
-
@formatter ||= RSpec::Core::BacktraceFormatter.new
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
#
|
|
20
|
-
# Formats a single backtrace line
|
|
21
|
-
# Delegates to the RSpec formatter
|
|
22
|
-
#
|
|
23
|
-
# @param line [String] The backtrace line to format
|
|
24
|
-
#
|
|
25
|
-
# @return [String] The formatted backtrace line
|
|
26
|
-
#
|
|
27
|
-
def self.backtrace_line(line)
|
|
28
|
-
formatter.backtrace_line(line)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
#
|
|
32
|
-
# Formats a complete backtrace for an example
|
|
33
|
-
# Adds the YAML location to the front of the backtrace for better context
|
|
34
|
-
#
|
|
35
|
-
# @param backtrace [Array<String>] The raw backtrace lines
|
|
36
|
-
# @param example_metadata [Hash] Metadata about the failing example
|
|
37
|
-
#
|
|
38
|
-
# @return [Array<String>] The formatted backtrace with YAML location first
|
|
39
|
-
#
|
|
40
|
-
def self.format_backtrace(backtrace, example_metadata)
|
|
41
|
-
backtrace = SpecForge.backtrace_cleaner.clean(backtrace)
|
|
42
|
-
|
|
43
|
-
location = example_metadata[:example_group][:location]
|
|
44
|
-
line_number = example_metadata[:example_group][:line_number]
|
|
45
|
-
|
|
46
|
-
# Add the yaml location to the front so it's the first thing people see
|
|
47
|
-
["#{location}:#{line_number}"] + backtrace[0..50]
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
data/lib/spec_forge/callbacks.rb
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SpecForge
|
|
4
|
-
#
|
|
5
|
-
# Manages user-defined callbacks for test lifecycle events
|
|
6
|
-
#
|
|
7
|
-
# This singleton class stores and executes callback functions that
|
|
8
|
-
# users can register to run at specific points in the test lifecycle.
|
|
9
|
-
# Each callback receives a context object containing relevant state
|
|
10
|
-
# information for that point in execution.
|
|
11
|
-
#
|
|
12
|
-
# @example Registering and using a callback
|
|
13
|
-
# SpecForge::Callbacks.register(:my_callback) do |context|
|
|
14
|
-
# puts "Running test: #{context.expectation_name}"
|
|
15
|
-
# end
|
|
16
|
-
#
|
|
17
|
-
class Callbacks < Hash
|
|
18
|
-
include Singleton
|
|
19
|
-
|
|
20
|
-
class << self
|
|
21
|
-
#
|
|
22
|
-
# Registers a new callback for a specific event
|
|
23
|
-
#
|
|
24
|
-
# @param name [String, Symbol] The name of the callback event
|
|
25
|
-
# @param block [Proc] The callback function to execute
|
|
26
|
-
#
|
|
27
|
-
# @raise [ArgumentError] If no block is provided
|
|
28
|
-
#
|
|
29
|
-
def register(name, &block)
|
|
30
|
-
raise ArgumentError, "A block must be provided" unless block.is_a?(Proc)
|
|
31
|
-
|
|
32
|
-
if registered?(name)
|
|
33
|
-
warn("Callback #{name.in_quotes} is already registered. It will be overwritten")
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
instance[name.to_s] = block
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
#
|
|
40
|
-
# Deregisters a callback
|
|
41
|
-
#
|
|
42
|
-
# @param name [String, Symbol] The name of the callback
|
|
43
|
-
#
|
|
44
|
-
def deregister(name)
|
|
45
|
-
instance.delete(name.to_s)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
#
|
|
49
|
-
# Checks if a callback is registered for the given event
|
|
50
|
-
#
|
|
51
|
-
# @param name [String, Symbol] The name of the callback event
|
|
52
|
-
#
|
|
53
|
-
# @return [Boolean] True if the callback exists
|
|
54
|
-
#
|
|
55
|
-
def registered?(name)
|
|
56
|
-
instance.key?(name.to_s)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
#
|
|
60
|
-
# Returns all registered callback names
|
|
61
|
-
#
|
|
62
|
-
# @return [Array<String>] List of registered callback names
|
|
63
|
-
#
|
|
64
|
-
def registered_names
|
|
65
|
-
instance.keys
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
#
|
|
69
|
-
# Executes a named callback with the provided context
|
|
70
|
-
#
|
|
71
|
-
# @param name [String, Symbol] The name of the callback to run
|
|
72
|
-
# @param context [Object] Context object containing state data
|
|
73
|
-
#
|
|
74
|
-
# @raise [ArgumentError] If the callback is not registered
|
|
75
|
-
#
|
|
76
|
-
def run(name, context)
|
|
77
|
-
callback = instance[name.to_s]
|
|
78
|
-
raise ArgumentError, "Callback #{name.in_quotes} is not defined" if callback.nil?
|
|
79
|
-
|
|
80
|
-
if callback.arity == 0
|
|
81
|
-
callback.call
|
|
82
|
-
else
|
|
83
|
-
callback.call(context)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|