skooma 0.3.0 → 0.3.2
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 +49 -11
- data/README.md +13 -2
- data/data/oas-3.1/meta/base.json +0 -9
- data/data/oas-3.1/schema/2022-10-07.json +31 -64
- data/lib/skooma/coverage.rb +90 -0
- data/lib/skooma/matchers/conform_request_schema.rb +6 -2
- data/lib/skooma/matchers/conform_response_schema.rb +2 -2
- data/lib/skooma/matchers/wrapper.rb +15 -6
- data/lib/skooma/minitest.rb +7 -3
- data/lib/skooma/objects/openapi/keywords/paths.rb +2 -0
- data/lib/skooma/objects/path_item/keywords/base_operation.rb +6 -2
- data/lib/skooma/objects/path_item/keywords/delete.rb +1 -1
- data/lib/skooma/rspec.rb +10 -3
- data/lib/skooma/version.rb +1 -1
- data/lib/skooma.rb +5 -0
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: de042bc8ca38a43927cc9f6c1fdb829aecbbf214f771f9a092345f25d2d2f36a
|
|
4
|
+
data.tar.gz: a084b23b9eeb66af1a36d010b99bc86ae4e1b0c39e470096fc2ef788c9afb725
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4286775a7c888f90b46fb35b827ce0f0f21c10ffd4737f6823326a14e00a21786f3e976877d71aee7b07a6578b09188fbe5334c8c67e4f24b78ccfe6ccc00494
|
|
7
|
+
data.tar.gz: 92e474fe454174ad5d4f1703cf8b1a9c3f9bd47bbe6eb382f60912926e28e3f9888acc612cc751c18ca8d7182f8c0922507302fbde8570ade7c0c7950c76925c
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,41 @@ and this project adheres to [Semantic Versioning].
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.2] - 2024-06-24
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Fix deprecation `MiniTest::Unit.after_tests is now Minitest.after_run`. ([@barnaclebarnes])
|
|
15
|
+
- Exclude test helpers from eager loading. ([@skryukov])
|
|
16
|
+
- Update oas-3.1 base schema. ([@skryukov])
|
|
17
|
+
|
|
18
|
+
## [0.3.1] - 2024-04-11
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Add coverage for tested API operations. ([@skryukov])
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
|
|
26
|
+
# spec/rails_helper.rb
|
|
27
|
+
|
|
28
|
+
RSpec.configure do |config|
|
|
29
|
+
# To enable coverage, pass `coverage: :report` option,
|
|
30
|
+
# and to raise an error when an operation is not covered, pass `coverage: :strict` option:
|
|
31
|
+
config.include Skooma::RSpec[Rails.root.join("docs", "openapi.yml"), coverage: :report], type: :request
|
|
32
|
+
end
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```shell
|
|
36
|
+
$ bundle exec rspec
|
|
37
|
+
# ...
|
|
38
|
+
OpenAPI schema /openapi.yml coverage report: 110 / 194 operations (56.7%) covered.
|
|
39
|
+
Uncovered paths:
|
|
40
|
+
GET /api/uncovered 200
|
|
41
|
+
GET /api/partially_covered 403
|
|
42
|
+
# ...
|
|
43
|
+
```
|
|
44
|
+
|
|
10
45
|
## [0.3.0] - 2024-04-09
|
|
11
46
|
|
|
12
47
|
### Changed
|
|
@@ -39,16 +74,16 @@ and this project adheres to [Semantic Versioning].
|
|
|
39
74
|
|
|
40
75
|
- Add support for APIs mounted under a path prefix. ([@skryukov])
|
|
41
76
|
|
|
42
|
-
```ruby
|
|
43
|
-
# spec/rails_helper.rb
|
|
44
|
-
|
|
45
|
-
RSpec.configure do |config|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
end
|
|
51
|
-
```
|
|
77
|
+
```ruby
|
|
78
|
+
# spec/rails_helper.rb
|
|
79
|
+
|
|
80
|
+
RSpec.configure do |config|
|
|
81
|
+
# ...
|
|
82
|
+
path_to_openapi = Rails.root.join("docs", "openapi.yml")
|
|
83
|
+
# pass path_prefix option if your API is mounted under a prefix:
|
|
84
|
+
config.include Skooma::RSpec[path_to_openapi, path_prefix: "/internal/api"], type: :request
|
|
85
|
+
end
|
|
86
|
+
```
|
|
52
87
|
|
|
53
88
|
### Changed
|
|
54
89
|
|
|
@@ -83,10 +118,13 @@ end
|
|
|
83
118
|
|
|
84
119
|
- Initial implementation. ([@skryukov])
|
|
85
120
|
|
|
121
|
+
[@barnaclebarnes]: https://github.com/barnaclebarnes
|
|
86
122
|
[@skryukov]: https://github.com/skryukov
|
|
87
123
|
[@ursm]: https://github.com/ursm
|
|
88
124
|
|
|
89
|
-
[Unreleased]: https://github.com/skryukov/skooma/compare/v0.3.
|
|
125
|
+
[Unreleased]: https://github.com/skryukov/skooma/compare/v0.3.2...HEAD
|
|
126
|
+
[0.3.2]: https://github.com/skryukov/skooma/compare/v0.3.1...v0.3.2
|
|
127
|
+
[0.3.1]: https://github.com/skryukov/skooma/compare/v0.3.0...v0.3.1
|
|
90
128
|
[0.3.0]: https://github.com/skryukov/skooma/compare/v0.2.3...v0.3.0
|
|
91
129
|
[0.2.3]: https://github.com/skryukov/skooma/compare/v0.2.2...v0.2.3
|
|
92
130
|
[0.2.2]: https://github.com/skryukov/skooma/compare/v0.2.1...v0.2.2
|
data/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Skooma is a Ruby library for validating API implementations against OpenAPI docu
|
|
|
16
16
|
|
|
17
17
|
### Learn more
|
|
18
18
|
|
|
19
|
-
- [Let there be docs! A documentation-first approach to Rails API development](https://evilmartians.com/
|
|
19
|
+
- [Let there be docs! A documentation-first approach to Rails API development](https://evilmartians.com/chronicles/let-there-be-docs-a-documentation-first-approach-to-rails-api-development)
|
|
20
20
|
|
|
21
21
|
<a href="https://evilmartians.com/?utm_source=skooma&utm_campaign=project_page">
|
|
22
22
|
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54">
|
|
@@ -51,6 +51,10 @@ RSpec.configure do |config|
|
|
|
51
51
|
|
|
52
52
|
# OR pass path_prefix option if your API is mounted under a prefix:
|
|
53
53
|
config.include Skooma::RSpec[path_to_openapi, path_prefix: "/internal/api"], type: :request
|
|
54
|
+
|
|
55
|
+
# To enable coverage, pass `coverage: :report` option,
|
|
56
|
+
# and to raise an error when an operation is not covered, pass `coverage: :strict` option:
|
|
57
|
+
config.include Skooma::RSpec[path_to_openapi, coverage: :report], type: :request
|
|
54
58
|
end
|
|
55
59
|
```
|
|
56
60
|
|
|
@@ -115,8 +119,15 @@ end
|
|
|
115
119
|
|
|
116
120
|
```ruby
|
|
117
121
|
# test/test_helper.rb
|
|
122
|
+
path_to_openapi = Rails.root.join("docs", "openapi.yml")
|
|
123
|
+
ActionDispatch::IntegrationTest.include Skooma::Minitest[path_to_openapi]
|
|
124
|
+
|
|
125
|
+
# OR pass path_prefix option if your API is mounted under a prefix:
|
|
126
|
+
ActionDispatch::IntegrationTest.include Skooma::Minitest[path_to_openapi, path_prefix: "/internal/api"], type: :request
|
|
118
127
|
|
|
119
|
-
|
|
128
|
+
# To enable coverage, pass `coverage: :report` option,
|
|
129
|
+
# and to raise an error when an operation is not covered, pass `coverage: :strict` option:
|
|
130
|
+
ActionDispatch::IntegrationTest.include Skooma::Minitest[path_to_openapi, coverage: :report], type: :request
|
|
120
131
|
```
|
|
121
132
|
|
|
122
133
|
#### Validate OpenAPI document
|
data/data/oas-3.1/meta/base.json
CHANGED
|
@@ -18,15 +18,6 @@
|
|
|
18
18
|
"externalDocs": { "$ref": "#/$defs/external-docs" },
|
|
19
19
|
"xml": { "$ref": "#/$defs/xml" }
|
|
20
20
|
},
|
|
21
|
-
"dependentSchemas": {
|
|
22
|
-
"discriminator": {
|
|
23
|
-
"anyOf": [
|
|
24
|
-
{ "required": [ "oneOf" ] },
|
|
25
|
-
{ "required": [ "anyOf" ] },
|
|
26
|
-
{ "required": [ "allOf" ] }
|
|
27
|
-
]
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
21
|
|
|
31
22
|
"$defs": {
|
|
32
23
|
"extensible": {
|
|
@@ -167,8 +167,7 @@
|
|
|
167
167
|
"type": "object",
|
|
168
168
|
"properties": {
|
|
169
169
|
"url": {
|
|
170
|
-
"type": "string"
|
|
171
|
-
"format": "uri-reference"
|
|
170
|
+
"type": "string"
|
|
172
171
|
},
|
|
173
172
|
"description": {
|
|
174
173
|
"type": "string"
|
|
@@ -525,7 +524,7 @@
|
|
|
525
524
|
"$ref": "#/$defs/parameter/dependentSchemas/schema/$defs/styles-for-cookie"
|
|
526
525
|
},
|
|
527
526
|
{
|
|
528
|
-
"$ref": "#/$defs/
|
|
527
|
+
"$ref": "#/$defs/styles-for-form"
|
|
529
528
|
}
|
|
530
529
|
],
|
|
531
530
|
"$defs": {
|
|
@@ -542,9 +541,6 @@
|
|
|
542
541
|
},
|
|
543
542
|
"then": {
|
|
544
543
|
"properties": {
|
|
545
|
-
"name": {
|
|
546
|
-
"pattern": "[^/#?]+$"
|
|
547
|
-
},
|
|
548
544
|
"style": {
|
|
549
545
|
"default": "simple",
|
|
550
546
|
"enum": [
|
|
@@ -630,32 +626,6 @@
|
|
|
630
626
|
}
|
|
631
627
|
}
|
|
632
628
|
}
|
|
633
|
-
},
|
|
634
|
-
"styles-for-form": {
|
|
635
|
-
"if": {
|
|
636
|
-
"properties": {
|
|
637
|
-
"style": {
|
|
638
|
-
"const": "form"
|
|
639
|
-
}
|
|
640
|
-
},
|
|
641
|
-
"required": [
|
|
642
|
-
"style"
|
|
643
|
-
]
|
|
644
|
-
},
|
|
645
|
-
"then": {
|
|
646
|
-
"properties": {
|
|
647
|
-
"explode": {
|
|
648
|
-
"default": true
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
},
|
|
652
|
-
"else": {
|
|
653
|
-
"properties": {
|
|
654
|
-
"explode": {
|
|
655
|
-
"default": false
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
629
|
}
|
|
660
630
|
}
|
|
661
631
|
}
|
|
@@ -782,38 +752,10 @@
|
|
|
782
752
|
"$ref": "#/$defs/specification-extensions"
|
|
783
753
|
},
|
|
784
754
|
{
|
|
785
|
-
"$ref": "#/$defs/
|
|
755
|
+
"$ref": "#/$defs/styles-for-form"
|
|
786
756
|
}
|
|
787
757
|
],
|
|
788
|
-
"unevaluatedProperties": false
|
|
789
|
-
"$defs": {
|
|
790
|
-
"explode-default": {
|
|
791
|
-
"if": {
|
|
792
|
-
"properties": {
|
|
793
|
-
"style": {
|
|
794
|
-
"const": "form"
|
|
795
|
-
}
|
|
796
|
-
},
|
|
797
|
-
"required": [
|
|
798
|
-
"style"
|
|
799
|
-
]
|
|
800
|
-
},
|
|
801
|
-
"then": {
|
|
802
|
-
"properties": {
|
|
803
|
-
"explode": {
|
|
804
|
-
"default": true
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
},
|
|
808
|
-
"else": {
|
|
809
|
-
"properties": {
|
|
810
|
-
"explode": {
|
|
811
|
-
"default": false
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
}
|
|
758
|
+
"unevaluatedProperties": false
|
|
817
759
|
},
|
|
818
760
|
"responses": {
|
|
819
761
|
"$comment": "https://spec.openapis.org/oas/v3.1.0#responses-object",
|
|
@@ -1100,8 +1042,7 @@
|
|
|
1100
1042
|
"description": {
|
|
1101
1043
|
"type": "string"
|
|
1102
1044
|
}
|
|
1103
|
-
}
|
|
1104
|
-
"unevaluatedProperties": false
|
|
1045
|
+
}
|
|
1105
1046
|
},
|
|
1106
1047
|
"schema": {
|
|
1107
1048
|
"$comment": "https://spec.openapis.org/oas/v3.1.0#schema-object",
|
|
@@ -1436,6 +1377,32 @@
|
|
|
1436
1377
|
"additionalProperties": {
|
|
1437
1378
|
"type": "string"
|
|
1438
1379
|
}
|
|
1380
|
+
},
|
|
1381
|
+
"styles-for-form": {
|
|
1382
|
+
"if": {
|
|
1383
|
+
"properties": {
|
|
1384
|
+
"style": {
|
|
1385
|
+
"const": "form"
|
|
1386
|
+
}
|
|
1387
|
+
},
|
|
1388
|
+
"required": [
|
|
1389
|
+
"style"
|
|
1390
|
+
]
|
|
1391
|
+
},
|
|
1392
|
+
"then": {
|
|
1393
|
+
"properties": {
|
|
1394
|
+
"explode": {
|
|
1395
|
+
"default": true
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
},
|
|
1399
|
+
"else": {
|
|
1400
|
+
"properties": {
|
|
1401
|
+
"explode": {
|
|
1402
|
+
"default": false
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1439
1406
|
}
|
|
1440
1407
|
}
|
|
1441
1408
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module Skooma
|
|
2
|
+
class NoopCoverage
|
|
3
|
+
def track_request(*)
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def report
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class Coverage
|
|
11
|
+
class SimpleReport
|
|
12
|
+
def initialize(coverage)
|
|
13
|
+
@coverage = coverage
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
attr_reader :coverage
|
|
17
|
+
|
|
18
|
+
def report
|
|
19
|
+
puts <<~MSG
|
|
20
|
+
OpenAPI schema #{URI.parse(coverage.schema.uri.to_s).path} coverage report: #{coverage.covered_paths.count} / #{coverage.defined_paths.count} operations (#{coverage.covered_percent.round(2)}%) covered.
|
|
21
|
+
#{coverage.uncovered_paths.empty? ? "All paths are covered!" : "Uncovered paths:"}
|
|
22
|
+
#{coverage.uncovered_paths.map { |method, path, status| "#{method.upcase} #{path} #{status}" }.join("\n")}
|
|
23
|
+
MSG
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.new(schema, mode: nil, format: nil)
|
|
28
|
+
case mode
|
|
29
|
+
when nil, false
|
|
30
|
+
NoopCoverage.new
|
|
31
|
+
when :report, :strict
|
|
32
|
+
super
|
|
33
|
+
else
|
|
34
|
+
raise ArgumentError, "Invalid coverage: #{mode}, expected :report, :strict, or false"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
attr_reader :mode, :format, :defined_paths, :covered_paths, :schema
|
|
39
|
+
|
|
40
|
+
def initialize(schema, mode:, format:)
|
|
41
|
+
@schema = schema
|
|
42
|
+
@mode = mode
|
|
43
|
+
@format = format || SimpleReport
|
|
44
|
+
@defined_paths = find_defined_paths(schema)
|
|
45
|
+
@covered_paths = Set.new
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def track_request(result)
|
|
49
|
+
operation = [nil, nil, nil]
|
|
50
|
+
result.collect_annotations(result.instance, keys: %w[paths responses]) do |node|
|
|
51
|
+
case node.key
|
|
52
|
+
when "paths"
|
|
53
|
+
operation[0] = node.annotation["method"]
|
|
54
|
+
operation[1] = node.annotation["current_path"]
|
|
55
|
+
when "responses"
|
|
56
|
+
operation[2] = node.annotation
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
covered_paths << operation
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def uncovered_paths
|
|
63
|
+
defined_paths - covered_paths
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def covered_percent
|
|
67
|
+
covered_paths.count * 100.0 / defined_paths.count
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def report
|
|
71
|
+
format.new(self).report
|
|
72
|
+
exit 1 if mode == :strict && uncovered_paths.any?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def find_defined_paths(schema)
|
|
78
|
+
Set.new.tap do |paths|
|
|
79
|
+
schema["paths"].each do |path, path_item|
|
|
80
|
+
resolved_path_item = (path_item.key?("$ref") ? path_item.resolve_ref(path_item["$ref"]) : path_item)
|
|
81
|
+
resolved_path_item.slice("get", "post", "put", "patch", "delete", "options", "head", "trace").each do |method, operation|
|
|
82
|
+
operation["responses"]&.each do |code, _|
|
|
83
|
+
paths << [method, path, code]
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -5,13 +5,17 @@ require "pp"
|
|
|
5
5
|
module Skooma
|
|
6
6
|
module Matchers
|
|
7
7
|
class ConformRequestSchema
|
|
8
|
-
def initialize(
|
|
9
|
-
@
|
|
8
|
+
def initialize(skooma, mapped_response)
|
|
9
|
+
@skooma = skooma
|
|
10
|
+
@schema = skooma.schema
|
|
10
11
|
@mapped_response = mapped_response
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def matches?(*)
|
|
14
15
|
@result = @schema.evaluate(@mapped_response)
|
|
16
|
+
|
|
17
|
+
@skooma.coverage.track_request(@result) if @mapped_response["response"]
|
|
18
|
+
|
|
15
19
|
@result.valid?
|
|
16
20
|
end
|
|
17
21
|
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module Skooma
|
|
4
4
|
module Matchers
|
|
5
5
|
class ConformResponseSchema < ConformRequestSchema
|
|
6
|
-
def initialize(
|
|
7
|
-
super(
|
|
6
|
+
def initialize(skooma, mapped_response, expected)
|
|
7
|
+
super(skooma, mapped_response)
|
|
8
8
|
@expected = expected
|
|
9
9
|
end
|
|
10
10
|
|
|
@@ -38,30 +38,39 @@ module Skooma
|
|
|
38
38
|
|
|
39
39
|
raise "Response object not found"
|
|
40
40
|
end
|
|
41
|
+
|
|
42
|
+
def skooma_openapi_schema
|
|
43
|
+
skooma.schema
|
|
44
|
+
end
|
|
41
45
|
end
|
|
42
46
|
|
|
43
|
-
def initialize(helper_methods_module, openapi_path, base_uri: "https://skoomarb.dev/", path_prefix: "")
|
|
47
|
+
def initialize(helper_methods_module, openapi_path, base_uri: "https://skoomarb.dev/", path_prefix: "", **params)
|
|
44
48
|
super()
|
|
45
49
|
|
|
46
50
|
registry = create_test_registry
|
|
47
51
|
pathname = Pathname.new(openapi_path)
|
|
48
|
-
source_uri = "#{base_uri}#{path_prefix.delete_suffix("/")}"
|
|
52
|
+
source_uri = "#{base_uri}#{path_prefix.delete_suffix("/").delete_prefix("/")}"
|
|
49
53
|
source_uri += "/" unless source_uri.end_with?("/")
|
|
50
54
|
registry.add_source(
|
|
51
55
|
source_uri,
|
|
52
56
|
JSONSkooma::Sources::Local.new(pathname.dirname.to_s)
|
|
53
57
|
)
|
|
54
|
-
schema = registry.schema(URI.parse("#{source_uri}#{pathname.basename}"), schema_class: Skooma::Objects::OpenAPI)
|
|
55
|
-
schema.path_prefix = path_prefix
|
|
58
|
+
@schema = registry.schema(URI.parse("#{source_uri}#{pathname.basename}"), schema_class: Skooma::Objects::OpenAPI)
|
|
59
|
+
@schema.path_prefix = path_prefix
|
|
60
|
+
|
|
61
|
+
@coverage = Coverage.new(@schema, mode: params[:coverage], format: params[:coverage_format])
|
|
56
62
|
|
|
57
63
|
include DefaultHelperMethods
|
|
58
64
|
include helper_methods_module
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
|
|
66
|
+
skooma_self = self
|
|
67
|
+
define_method :skooma do
|
|
68
|
+
skooma_self
|
|
62
69
|
end
|
|
63
70
|
end
|
|
64
71
|
|
|
72
|
+
attr_accessor :schema, :coverage
|
|
73
|
+
|
|
65
74
|
private
|
|
66
75
|
|
|
67
76
|
def create_test_registry
|
data/lib/skooma/minitest.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "minitest/unit"
|
|
4
|
+
|
|
3
5
|
module Skooma
|
|
4
6
|
# Minitest helpers for OpenAPI schema validation
|
|
5
7
|
# @example
|
|
@@ -10,19 +12,19 @@ module Skooma
|
|
|
10
12
|
class Minitest < Matchers::Wrapper
|
|
11
13
|
module HelperMethods
|
|
12
14
|
def assert_conform_schema(expected_status)
|
|
13
|
-
matcher = Matchers::ConformSchema.new(
|
|
15
|
+
matcher = Matchers::ConformSchema.new(skooma, mapped_response, expected_status)
|
|
14
16
|
|
|
15
17
|
assert matcher.matches?, -> { matcher.failure_message }
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def assert_conform_request_schema
|
|
19
|
-
matcher = Matchers::ConformRequestSchema.new(
|
|
21
|
+
matcher = Matchers::ConformRequestSchema.new(skooma, mapped_response(with_response: false))
|
|
20
22
|
|
|
21
23
|
assert matcher.matches?, -> { matcher.failure_message }
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
def assert_conform_response_schema(expected_status)
|
|
25
|
-
matcher = Matchers::ConformResponseSchema.new(
|
|
27
|
+
matcher = Matchers::ConformResponseSchema.new(skooma, mapped_response(with_request: false), expected_status)
|
|
26
28
|
|
|
27
29
|
assert matcher.matches?, -> { matcher.failure_message }
|
|
28
30
|
end
|
|
@@ -36,6 +38,8 @@ module Skooma
|
|
|
36
38
|
|
|
37
39
|
def initialize(openapi_path, **params)
|
|
38
40
|
super(HelperMethods, openapi_path, **params)
|
|
41
|
+
|
|
42
|
+
MiniTest.after_run { coverage.report }
|
|
39
43
|
end
|
|
40
44
|
end
|
|
41
45
|
end
|
|
@@ -28,6 +28,8 @@ module Skooma
|
|
|
28
28
|
|
|
29
29
|
return result.failure("Path #{instance["path"]} not found in schema") unless path
|
|
30
30
|
|
|
31
|
+
result.annotate({"current_path" => path})
|
|
32
|
+
|
|
31
33
|
result.call(instance, path) do |subresult|
|
|
32
34
|
subresult.annotate({"path_attributes" => attributes})
|
|
33
35
|
path_schema.evaluate(instance, subresult)
|
|
@@ -13,12 +13,16 @@ module Skooma
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
json.evaluate(instance, result)
|
|
16
|
-
return result.success if result.passed?
|
|
17
16
|
|
|
18
17
|
path_item_result = result.parent
|
|
19
18
|
path_item_result = path_item_result.parent until path_item_result.key.start_with?("/")
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
paths_result = path_item_result.parent
|
|
21
|
+
paths_result.annotate(paths_result.annotation.merge("method" => key))
|
|
22
|
+
|
|
23
|
+
return result.success if result.passed?
|
|
24
|
+
|
|
25
|
+
path = paths_result.annotation["current_path"]
|
|
22
26
|
|
|
23
27
|
result.failure("Path #{path}/#{key} is invalid")
|
|
24
28
|
end
|
data/lib/skooma/rspec.rb
CHANGED
|
@@ -10,15 +10,15 @@ module Skooma
|
|
|
10
10
|
class RSpec < Matchers::Wrapper
|
|
11
11
|
module HelperMethods
|
|
12
12
|
def conform_schema(expected_status)
|
|
13
|
-
Matchers::ConformSchema.new(
|
|
13
|
+
Matchers::ConformSchema.new(skooma, mapped_response, expected_status)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def conform_response_schema(expected_status)
|
|
17
|
-
Matchers::ConformResponseSchema.new(
|
|
17
|
+
Matchers::ConformResponseSchema.new(skooma, mapped_response(with_request: false), expected_status)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def conform_request_schema
|
|
21
|
-
Matchers::ConformRequestSchema.new(
|
|
21
|
+
Matchers::ConformRequestSchema.new(skooma, mapped_response(with_response: false))
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def be_valid_document
|
|
@@ -28,6 +28,13 @@ module Skooma
|
|
|
28
28
|
|
|
29
29
|
def initialize(openapi_path, **params)
|
|
30
30
|
super(HelperMethods, openapi_path, **params)
|
|
31
|
+
|
|
32
|
+
skooma_self = self
|
|
33
|
+
::RSpec.configure do |c|
|
|
34
|
+
c.after(:suite) do
|
|
35
|
+
at_exit { skooma_self.coverage.report }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
31
38
|
end
|
|
32
39
|
end
|
|
33
40
|
end
|
data/lib/skooma/version.rb
CHANGED
data/lib/skooma.rb
CHANGED
|
@@ -7,6 +7,11 @@ require_relative "skooma/inflector"
|
|
|
7
7
|
|
|
8
8
|
loader = Zeitwerk::Loader.for_gem
|
|
9
9
|
loader.inflector = Skooma::Inflector.new(__FILE__)
|
|
10
|
+
|
|
11
|
+
# Do not eager load the test helpers
|
|
12
|
+
loader.do_not_eager_load(File.join(__dir__, "skooma", "minitest.rb"))
|
|
13
|
+
loader.do_not_eager_load(File.join(__dir__, "skooma", "rspec.rb"))
|
|
14
|
+
|
|
10
15
|
loader.setup
|
|
11
16
|
|
|
12
17
|
module Skooma
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: skooma
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Svyatoslav Kryukov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-
|
|
11
|
+
date: 2024-06-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: zeitwerk
|
|
@@ -54,6 +54,7 @@ files:
|
|
|
54
54
|
- data/oas-3.1/schema/2022-10-07.json
|
|
55
55
|
- lib/skooma.rb
|
|
56
56
|
- lib/skooma/body_parsers.rb
|
|
57
|
+
- lib/skooma/coverage.rb
|
|
57
58
|
- lib/skooma/dialects/oas_3_1.rb
|
|
58
59
|
- lib/skooma/env_mapper.rb
|
|
59
60
|
- lib/skooma/inflector.rb
|
|
@@ -163,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
163
164
|
- !ruby/object:Gem::Version
|
|
164
165
|
version: '0'
|
|
165
166
|
requirements: []
|
|
166
|
-
rubygems_version: 3.
|
|
167
|
+
rubygems_version: 3.5.7
|
|
167
168
|
signing_key:
|
|
168
169
|
specification_version: 4
|
|
169
170
|
summary: Validate API implementations against OpenAPI documents.
|