spec_forge 0.1.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 +7 -0
- data/.envrc +1 -0
- data/.rspec +1 -0
- data/.standard.yml +3 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +426 -0
- data/Rakefile +6 -0
- data/bin/spec_forge +5 -0
- data/flake.lock +61 -0
- data/flake.nix +41 -0
- data/lib/spec_forge/attribute/chainable.rb +86 -0
- data/lib/spec_forge/attribute/factory.rb +63 -0
- data/lib/spec_forge/attribute/faker.rb +54 -0
- data/lib/spec_forge/attribute/literal.rb +27 -0
- data/lib/spec_forge/attribute/matcher.rb +118 -0
- data/lib/spec_forge/attribute/parameterized.rb +76 -0
- data/lib/spec_forge/attribute/resolvable.rb +21 -0
- data/lib/spec_forge/attribute/resolvable_array.rb +24 -0
- data/lib/spec_forge/attribute/resolvable_hash.rb +24 -0
- data/lib/spec_forge/attribute/transform.rb +39 -0
- data/lib/spec_forge/attribute/variable.rb +36 -0
- data/lib/spec_forge/attribute.rb +208 -0
- data/lib/spec_forge/cli/actions.rb +23 -0
- data/lib/spec_forge/cli/command.rb +127 -0
- data/lib/spec_forge/cli/init.rb +29 -0
- data/lib/spec_forge/cli/new.rb +161 -0
- data/lib/spec_forge/cli/run.rb +17 -0
- data/lib/spec_forge/cli.rb +43 -0
- data/lib/spec_forge/config.rb +84 -0
- data/lib/spec_forge/environment.rb +71 -0
- data/lib/spec_forge/error.rb +150 -0
- data/lib/spec_forge/factory.rb +104 -0
- data/lib/spec_forge/http/backend.rb +106 -0
- data/lib/spec_forge/http/client.rb +33 -0
- data/lib/spec_forge/http/request.rb +93 -0
- data/lib/spec_forge/http/verb.rb +118 -0
- data/lib/spec_forge/http.rb +6 -0
- data/lib/spec_forge/normalizer/config.rb +104 -0
- data/lib/spec_forge/normalizer/constraint.rb +47 -0
- data/lib/spec_forge/normalizer/expectation.rb +85 -0
- data/lib/spec_forge/normalizer/factory.rb +65 -0
- data/lib/spec_forge/normalizer/factory_reference.rb +66 -0
- data/lib/spec_forge/normalizer/spec.rb +73 -0
- data/lib/spec_forge/normalizer.rb +183 -0
- data/lib/spec_forge/runner.rb +91 -0
- data/lib/spec_forge/spec/expectation/constraint.rb +52 -0
- data/lib/spec_forge/spec/expectation.rb +53 -0
- data/lib/spec_forge/spec.rb +77 -0
- data/lib/spec_forge/type.rb +45 -0
- data/lib/spec_forge/version.rb +5 -0
- data/lib/spec_forge.rb +90 -0
- data/lib/templates/config.tt +19 -0
- data/spec_forge/config.yml +19 -0
- data/spec_forge/factories/user.yml +4 -0
- data/spec_forge/specs/users.yml +63 -0
- metadata +234 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SpecForge
|
4
|
+
class Spec
|
5
|
+
class Expectation
|
6
|
+
#
|
7
|
+
# Represents the "expect" hash
|
8
|
+
#
|
9
|
+
class Constraint < Data.define(:status, :json) # :xml, :html
|
10
|
+
#
|
11
|
+
# Creates a new Constraint
|
12
|
+
#
|
13
|
+
# @param status [Integer] The expected HTTP status code
|
14
|
+
# @param json [Hash] The expected JSON with matchers
|
15
|
+
#
|
16
|
+
def initialize(status:, json:)
|
17
|
+
super(status:, json: normalize_hash(json))
|
18
|
+
end
|
19
|
+
|
20
|
+
def resolve
|
21
|
+
{
|
22
|
+
status: status.resolve,
|
23
|
+
json: json.resolve.deep_stringify_keys
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def normalize_hash(hash)
|
30
|
+
hash =
|
31
|
+
hash.transform_values do |attribute|
|
32
|
+
if attribute.is_a?(Attribute::Literal)
|
33
|
+
normalize_literal(attribute.value)
|
34
|
+
else
|
35
|
+
attribute
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Attribute.from(hash)
|
40
|
+
end
|
41
|
+
|
42
|
+
def normalize_literal(value)
|
43
|
+
if value.is_a?(Regexp)
|
44
|
+
Attribute.from("matcher.match" => value)
|
45
|
+
else
|
46
|
+
Attribute.from("matcher.eq" => value)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "expectation/constraint"
|
4
|
+
|
5
|
+
module SpecForge
|
6
|
+
class Spec
|
7
|
+
class Expectation
|
8
|
+
attr_reader :name, :variables, :constraints, :http_client
|
9
|
+
|
10
|
+
#
|
11
|
+
# Creates a new Expectation
|
12
|
+
#
|
13
|
+
# @param input [Hash] A hash containing the various attributes to control the expectation
|
14
|
+
# @param name [String] The name of the expectation
|
15
|
+
#
|
16
|
+
def initialize(name, input, global_options: {})
|
17
|
+
load_name(name, input)
|
18
|
+
|
19
|
+
# This allows defining spec level attributes that can be overwritten by the expectation
|
20
|
+
input = Attribute.from(overlay_options(global_options, input))
|
21
|
+
|
22
|
+
load_variables(input)
|
23
|
+
|
24
|
+
# Must be after load_variables
|
25
|
+
load_constraints(input)
|
26
|
+
|
27
|
+
# Must be last
|
28
|
+
@http_client = HTTP::Client.new(variables:, **input.except(:name, :variables, :expect))
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def overlay_options(source, overlay)
|
34
|
+
# Remove any blank values to avoid overwriting anything from source
|
35
|
+
overlay = overlay.delete_if { |_k, v| v.blank? }
|
36
|
+
source.deep_merge(overlay)
|
37
|
+
end
|
38
|
+
|
39
|
+
def load_name(name, input)
|
40
|
+
@name = input[:name].presence || name
|
41
|
+
end
|
42
|
+
|
43
|
+
def load_variables(input)
|
44
|
+
@variables = Attribute.bind_variables(input[:variables], input[:variables])
|
45
|
+
end
|
46
|
+
|
47
|
+
def load_constraints(input)
|
48
|
+
constraints = Attribute.bind_variables(input[:expect], variables)
|
49
|
+
@constraints = Constraint.new(**constraints)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "spec/expectation"
|
4
|
+
|
5
|
+
module SpecForge
|
6
|
+
class Spec
|
7
|
+
#
|
8
|
+
# Loads the specs from their yml files and runs them
|
9
|
+
#
|
10
|
+
# @param path [String, Path] The base path where the specs directory is located
|
11
|
+
#
|
12
|
+
def self.load_and_run(base_path)
|
13
|
+
specs = load_from_path(base_path.join("specs", "**/*.yml"))
|
14
|
+
specs.each(&:run)
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# Loads any specs defined in the path. A single file can contain one or more specs
|
19
|
+
#
|
20
|
+
# @param path [String, Path] The path where the specs are located
|
21
|
+
#
|
22
|
+
# @return [Array<Spec>] An array of specs that were loaded.
|
23
|
+
#
|
24
|
+
def self.load_from_path(path)
|
25
|
+
specs = []
|
26
|
+
|
27
|
+
Dir[path].map do |file_path|
|
28
|
+
hash = YAML.load_file(file_path).deep_symbolize_keys
|
29
|
+
|
30
|
+
hash.each do |spec_name, spec_hash|
|
31
|
+
spec_hash[:name] = spec_name
|
32
|
+
spec_hash[:file_path] = file_path
|
33
|
+
|
34
|
+
specs << new(**spec_hash)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
specs
|
39
|
+
end
|
40
|
+
|
41
|
+
############################################################################
|
42
|
+
|
43
|
+
attr_reader :name, :file_path, :expectations
|
44
|
+
|
45
|
+
#
|
46
|
+
# Creates a Spec based on the input
|
47
|
+
#
|
48
|
+
# @param name [String] The identifier for this spec
|
49
|
+
# @param file_path [String] The path where this spec is defined
|
50
|
+
# @param **input [Hash] Any attributes related to the spec, including expectations
|
51
|
+
# See Normalizer::Spec
|
52
|
+
#
|
53
|
+
def initialize(name:, file_path:, **input)
|
54
|
+
@name = name
|
55
|
+
@file_path = file_path
|
56
|
+
|
57
|
+
input = Normalizer.normalize_spec!(input)
|
58
|
+
global_options = input.except(:expectations)
|
59
|
+
|
60
|
+
@expectations =
|
61
|
+
input[:expectations].map.with_index do |expectation_input, index|
|
62
|
+
Expectation.new(
|
63
|
+
"expectations (item #{index})",
|
64
|
+
expectation_input,
|
65
|
+
global_options:
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Runs the spec
|
72
|
+
#
|
73
|
+
def run
|
74
|
+
Runner.new(self).run
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SpecForge
|
4
|
+
module Type
|
5
|
+
#
|
6
|
+
# Checks if the object is a Hash, or a ResolvableHash (delegator)
|
7
|
+
#
|
8
|
+
# @param object [Object] The object to check
|
9
|
+
#
|
10
|
+
# @return [Boolean]
|
11
|
+
#
|
12
|
+
def self.hash?(object)
|
13
|
+
object.is_a?(Hash) || object.is_a?(Attribute::ResolvableHash)
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Checks if the object is an Array, or a ResolvableArray (delegator)
|
18
|
+
#
|
19
|
+
# @param object [Object] The object to check
|
20
|
+
#
|
21
|
+
# @return [Boolean]
|
22
|
+
#
|
23
|
+
def self.array?(object)
|
24
|
+
object.is_a?(Array) || object.is_a?(Attribute::ResolvableArray)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Represents Hash/ResolvableHash in a form that can be used in a case statement
|
31
|
+
#
|
32
|
+
class HashLike
|
33
|
+
def self.===(object)
|
34
|
+
SpecForge::Type.hash?(object)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Represents Array/ResolvableArray in a form that can be used in a case statement
|
40
|
+
#
|
41
|
+
class ArrayLike
|
42
|
+
def self.===(object)
|
43
|
+
SpecForge::Type.array?(object)
|
44
|
+
end
|
45
|
+
end
|
data/lib/spec_forge.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
require "active_support"
|
5
|
+
require "active_support/core_ext"
|
6
|
+
require "commander"
|
7
|
+
require "everythingrb"
|
8
|
+
require "factory_bot"
|
9
|
+
require "faker"
|
10
|
+
require "faraday"
|
11
|
+
require "mime/types"
|
12
|
+
require "pathname"
|
13
|
+
require "rspec"
|
14
|
+
require "singleton"
|
15
|
+
require "thor"
|
16
|
+
require "yaml"
|
17
|
+
|
18
|
+
require_relative "spec_forge/attribute"
|
19
|
+
require_relative "spec_forge/cli"
|
20
|
+
require_relative "spec_forge/config"
|
21
|
+
require_relative "spec_forge/environment"
|
22
|
+
require_relative "spec_forge/error"
|
23
|
+
require_relative "spec_forge/factory"
|
24
|
+
require_relative "spec_forge/http"
|
25
|
+
require_relative "spec_forge/normalizer"
|
26
|
+
require_relative "spec_forge/runner"
|
27
|
+
require_relative "spec_forge/spec"
|
28
|
+
require_relative "spec_forge/type"
|
29
|
+
require_relative "spec_forge/version"
|
30
|
+
|
31
|
+
module SpecForge
|
32
|
+
#
|
33
|
+
# Loads all factories and specs located in "path", then runs all of the specs
|
34
|
+
#
|
35
|
+
# @param path [String] The file path that contains factories and specs
|
36
|
+
#
|
37
|
+
def self.run(path = SpecForge.forge)
|
38
|
+
SpecForge.environment.load
|
39
|
+
|
40
|
+
Factory.load_and_register(path)
|
41
|
+
Spec.load_and_run(path)
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Returns the directory root for the working directory
|
46
|
+
#
|
47
|
+
# @return [Pathname]
|
48
|
+
#
|
49
|
+
def self.root
|
50
|
+
@root ||= Pathname.pwd
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Returns SpecForge's working directory
|
55
|
+
#
|
56
|
+
# @return [Pathname]
|
57
|
+
#
|
58
|
+
def self.forge
|
59
|
+
@forge ||= root.join("spec_forge")
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Returns SpecForge's config
|
64
|
+
#
|
65
|
+
# @return [Config]
|
66
|
+
#
|
67
|
+
def self.config
|
68
|
+
@config ||= Config.new
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Returns a backtrace cleaner configured for SpecForge
|
73
|
+
#
|
74
|
+
# @return [ActiveSupport::BacktraceCleaner]
|
75
|
+
#
|
76
|
+
def self.backtrace_cleaner
|
77
|
+
@backtrace_cleaner ||= begin
|
78
|
+
root = "#{SpecForge.root}/"
|
79
|
+
|
80
|
+
cleaner = ActiveSupport::BacktraceCleaner.new
|
81
|
+
cleaner.add_filter { |line| line.delete_prefix(root) }
|
82
|
+
cleaner.add_silencer { |line| /rubygems|backtrace_cleaner/.match?(line) }
|
83
|
+
cleaner
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.environment
|
88
|
+
@environment ||= Environment.new
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Sets the base URL prefix for all API requests. All test paths will be appended to this URL.
|
2
|
+
base_url: http://localhost:3000
|
3
|
+
|
4
|
+
# Configures the global authorization header and value for API requests.
|
5
|
+
authorization:
|
6
|
+
default:
|
7
|
+
header: Authorization
|
8
|
+
value: <%= default_authorization_value %>
|
9
|
+
|
10
|
+
factories:
|
11
|
+
## Optional: Overrides default FactoryBot definition paths for discovering factories
|
12
|
+
## By default, FactoryBot will look in "spec/factories" and "test/factories"
|
13
|
+
# paths:
|
14
|
+
# - custom/factories/path
|
15
|
+
|
16
|
+
## Optional: Enable/disable automatic factory discovery, default: true
|
17
|
+
## Note: Disabling auto discovery will only disable FactoryBot's auto discovery. Any factories
|
18
|
+
## defined in "spec_forge/factories" will still be loaded.
|
19
|
+
# auto_discover: false
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Sets the base URL prefix for all API requests. All test paths will be appended to this URL.
|
2
|
+
base_url: http://localhost:3000
|
3
|
+
|
4
|
+
# Configures the global authorization header and value for API requests.
|
5
|
+
authorization:
|
6
|
+
default:
|
7
|
+
header: Authorization
|
8
|
+
value: Bearer <%= ENV.fetch("API_TOKEN", "") %>
|
9
|
+
|
10
|
+
factories:
|
11
|
+
## Optional: Overrides default FactoryBot definition paths for discovering factories
|
12
|
+
## By default, FactoryBot will look in "spec/factories" and "test/factories"
|
13
|
+
# paths:
|
14
|
+
# - custom/factories/path
|
15
|
+
|
16
|
+
## Optional: Enable/disable automatic factory discovery, default: true
|
17
|
+
## Note: Disabling auto discovery will only disable FactoryBot's auto discovery. Any factories
|
18
|
+
## defined in "spec_forge/factories" will still be loaded.
|
19
|
+
# auto_discover: false
|
@@ -0,0 +1,63 @@
|
|
1
|
+
index_users:
|
2
|
+
url: /users
|
3
|
+
expectations:
|
4
|
+
- expect:
|
5
|
+
status: 200
|
6
|
+
|
7
|
+
show_user:
|
8
|
+
url: /users/{id}
|
9
|
+
expectations:
|
10
|
+
- expect:
|
11
|
+
status: 404
|
12
|
+
- expect:
|
13
|
+
status: 200
|
14
|
+
json:
|
15
|
+
name: kind_of.string
|
16
|
+
email: /\w+@example\.com/i
|
17
|
+
query:
|
18
|
+
id: 1
|
19
|
+
|
20
|
+
create_user:
|
21
|
+
url: /users
|
22
|
+
method: post
|
23
|
+
expectations:
|
24
|
+
- expect:
|
25
|
+
status: 400
|
26
|
+
- expect:
|
27
|
+
status: 200
|
28
|
+
json:
|
29
|
+
name: variables.name
|
30
|
+
role: variables.role
|
31
|
+
variables:
|
32
|
+
name: faker.name.name
|
33
|
+
role: user
|
34
|
+
body:
|
35
|
+
name: variables.name
|
36
|
+
|
37
|
+
update_user:
|
38
|
+
url: /users/{id}
|
39
|
+
method: patch
|
40
|
+
query:
|
41
|
+
id: 1
|
42
|
+
variables:
|
43
|
+
number:
|
44
|
+
faker.number.between:
|
45
|
+
from: 100000
|
46
|
+
to: 999999
|
47
|
+
expectations:
|
48
|
+
- expect:
|
49
|
+
status: 200
|
50
|
+
json:
|
51
|
+
name: kind_of.string
|
52
|
+
number: kind_of.integer
|
53
|
+
body:
|
54
|
+
number: variables.number
|
55
|
+
|
56
|
+
destroy_user:
|
57
|
+
url: /users/{id}
|
58
|
+
method: delete
|
59
|
+
query:
|
60
|
+
id: 1
|
61
|
+
expectations:
|
62
|
+
- expect:
|
63
|
+
status: 200
|
metadata
ADDED
@@ -0,0 +1,234 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spec_forge
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bryan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 1980-01-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '7.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '7.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: commander
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: everythingrb
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: factory_bot
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '6.5'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '6.5'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: faker
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.5'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.5'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: faraday
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.12'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.12'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: mime-types
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.6'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.6'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '3.13'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '3.13'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: thor
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.3'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.3'
|
139
|
+
description: Write API tests in YAML without sacrificing power. SpecForge combines
|
140
|
+
RSpec's matcher system, Faker's data generation, and factory patterns into a clean,
|
141
|
+
declarative syntax that eliminates boilerplate while preserving control over your
|
142
|
+
test suite.
|
143
|
+
email:
|
144
|
+
- bryan@itsthedevman.com
|
145
|
+
executables:
|
146
|
+
- spec_forge
|
147
|
+
extensions: []
|
148
|
+
extra_rdoc_files: []
|
149
|
+
files:
|
150
|
+
- ".envrc"
|
151
|
+
- ".rspec"
|
152
|
+
- ".standard.yml"
|
153
|
+
- CHANGELOG.md
|
154
|
+
- CODE_OF_CONDUCT.md
|
155
|
+
- LICENSE.txt
|
156
|
+
- README.md
|
157
|
+
- Rakefile
|
158
|
+
- bin/spec_forge
|
159
|
+
- flake.lock
|
160
|
+
- flake.nix
|
161
|
+
- lib/spec_forge.rb
|
162
|
+
- lib/spec_forge/attribute.rb
|
163
|
+
- lib/spec_forge/attribute/chainable.rb
|
164
|
+
- lib/spec_forge/attribute/factory.rb
|
165
|
+
- lib/spec_forge/attribute/faker.rb
|
166
|
+
- lib/spec_forge/attribute/literal.rb
|
167
|
+
- lib/spec_forge/attribute/matcher.rb
|
168
|
+
- lib/spec_forge/attribute/parameterized.rb
|
169
|
+
- lib/spec_forge/attribute/resolvable.rb
|
170
|
+
- lib/spec_forge/attribute/resolvable_array.rb
|
171
|
+
- lib/spec_forge/attribute/resolvable_hash.rb
|
172
|
+
- lib/spec_forge/attribute/transform.rb
|
173
|
+
- lib/spec_forge/attribute/variable.rb
|
174
|
+
- lib/spec_forge/cli.rb
|
175
|
+
- lib/spec_forge/cli/actions.rb
|
176
|
+
- lib/spec_forge/cli/command.rb
|
177
|
+
- lib/spec_forge/cli/init.rb
|
178
|
+
- lib/spec_forge/cli/new.rb
|
179
|
+
- lib/spec_forge/cli/run.rb
|
180
|
+
- lib/spec_forge/config.rb
|
181
|
+
- lib/spec_forge/environment.rb
|
182
|
+
- lib/spec_forge/error.rb
|
183
|
+
- lib/spec_forge/factory.rb
|
184
|
+
- lib/spec_forge/http.rb
|
185
|
+
- lib/spec_forge/http/backend.rb
|
186
|
+
- lib/spec_forge/http/client.rb
|
187
|
+
- lib/spec_forge/http/request.rb
|
188
|
+
- lib/spec_forge/http/verb.rb
|
189
|
+
- lib/spec_forge/normalizer.rb
|
190
|
+
- lib/spec_forge/normalizer/config.rb
|
191
|
+
- lib/spec_forge/normalizer/constraint.rb
|
192
|
+
- lib/spec_forge/normalizer/expectation.rb
|
193
|
+
- lib/spec_forge/normalizer/factory.rb
|
194
|
+
- lib/spec_forge/normalizer/factory_reference.rb
|
195
|
+
- lib/spec_forge/normalizer/spec.rb
|
196
|
+
- lib/spec_forge/runner.rb
|
197
|
+
- lib/spec_forge/spec.rb
|
198
|
+
- lib/spec_forge/spec/expectation.rb
|
199
|
+
- lib/spec_forge/spec/expectation/constraint.rb
|
200
|
+
- lib/spec_forge/type.rb
|
201
|
+
- lib/spec_forge/version.rb
|
202
|
+
- lib/templates/config.tt
|
203
|
+
- spec_forge/config.yml
|
204
|
+
- spec_forge/factories/user.yml
|
205
|
+
- spec_forge/specs/users.yml
|
206
|
+
homepage: https://github.com/itsthedevman/spec_forge
|
207
|
+
licenses:
|
208
|
+
- MIT
|
209
|
+
metadata:
|
210
|
+
source_code_uri: https://github.com/itsthedevman/spec_forge
|
211
|
+
changelog_uri: https://github.com/itsthedevman/spec_forge/blob/main/CHANGELOG.md
|
212
|
+
bug_tracker_uri: https://github.com/itsthedevman/spec_forge/issues
|
213
|
+
documentation_uri: https://github.com/itsthedevman/spec_forge#readme
|
214
|
+
rubygems_mfa_required: 'true'
|
215
|
+
post_install_message:
|
216
|
+
rdoc_options: []
|
217
|
+
require_paths:
|
218
|
+
- lib
|
219
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
220
|
+
requirements:
|
221
|
+
- - ">="
|
222
|
+
- !ruby/object:Gem::Version
|
223
|
+
version: 3.0.0
|
224
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
225
|
+
requirements:
|
226
|
+
- - ">="
|
227
|
+
- !ruby/object:Gem::Version
|
228
|
+
version: '0'
|
229
|
+
requirements: []
|
230
|
+
rubygems_version: 3.5.22
|
231
|
+
signing_key:
|
232
|
+
specification_version: 4
|
233
|
+
summary: Write expressive API tests in YAML with the power of RSpec matchers
|
234
|
+
test_files: []
|