skooma 0.2.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 784c4f022f60aced719808f543bcdc9a153df4a58dd44179888f73f9c7c8fa3f
4
- data.tar.gz: c60b8a11cd1ccbefcc83207a0ad2734281d8e194b58fd2637dd25bd48e7577a3
3
+ metadata.gz: d780ea317b116a8bdafac72f240b68366cf6f2892ea671f29ed51dd48a198093
4
+ data.tar.gz: '078593785c8fc17c73c171616131880dbeaf1b85923e593a3612eb9b2309ff0d'
5
5
  SHA512:
6
- metadata.gz: c17febaba56cd351329f42acd06a74fdbd02782ccaef3d855098cc41159ee31ef8862cba849a4591f15a6580ffe69705fc783a5ab026f52fa5eefbf55963cd8f
7
- data.tar.gz: 35f93cdc5ace695d8e3bf7f315a573e9498e1799fb4bbd9f012d097b7b04ea0a3626b57239e67fbf49a5193d07947aa7c671543630353b10401a16bc66fb0625
6
+ metadata.gz: f16cb70ad584c45615c4c376ebbab69e48caca0daa32c687d55c9c96453b3a608096afeedc45a7286e0e4ace4c2dc500c2d36ed013d0b951d915b60bbba42a63
7
+ data.tar.gz: c301176ff04134e0e6d18c57e4e0ced55f1dca82d8ff807eefa820cc02f8227101275ccf43b4e3b60c6716b19d7da94f714da37435f417995e97faf44f2b20d3
data/CHANGELOG.md CHANGED
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning].
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.2] - 2024-01-04
11
+
12
+ ### Added
13
+
14
+ - Add support for APIs mounted under a path prefix. ([@skryukov])
15
+
16
+ ```ruby
17
+ # spec/rails_helper.rb
18
+
19
+ RSpec.configure do |config|
20
+ # ...
21
+ path_to_openapi = Rails.root.join("docs", "openapi.yml")
22
+ # pass path_prefix option if your API is mounted under a prefix:
23
+ config.include Skooma::RSpec[path_to_openapi, path_prefix: "/internal/api"], type: :request
24
+ end
25
+ ```
26
+
27
+ ### Changed
28
+
29
+ - Bump `json_skooma` version to `~> 0.2.0`. ([@skryukov])
30
+
31
+ ### Fixed
32
+
33
+ - Better checks to automatic request/response detection to prevent methods overrides via RSpec helpers (i.e. `subject(:response)`). ([@skryukov])
34
+ - Fail response validation when expected response code or `responses` keyword aren't listed. ([@skryukov])
35
+
36
+ ## [0.2.1] - 2023-10-23
37
+
38
+ ### Fixed
39
+
40
+ - Raise error when parameter attributes misses required keys. ([@skryukov])
41
+ - Fix output format. ([@skryukov])
42
+
10
43
  ## [0.2.0] - 2023-10-23
11
44
 
12
45
  ### Added
@@ -26,7 +59,9 @@ and this project adheres to [Semantic Versioning].
26
59
 
27
60
  [@skryukov]: https://github.com/skryukov
28
61
 
29
- [Unreleased]: https://github.com/skryukov/skooma/compare/v0.2.0...HEAD
62
+ [Unreleased]: https://github.com/skryukov/skooma/compare/v0.2.2...HEAD
63
+ [0.2.2]: https://github.com/skryukov/skooma/compare/v0.2.1...v0.2.2
64
+ [0.2.1]: https://github.com/skryukov/skooma/compare/v0.2.0...v0.2.1
30
65
  [0.2.0]: https://github.com/skryukov/skooma/compare/v0.1.0...v0.2.0
31
66
  [0.1.0]: https://github.com/skryukov/skooma/commits/v0.1.0
32
67
 
data/README.md CHANGED
@@ -14,6 +14,10 @@ Skooma is a Ruby library for validating API implementations against OpenAPI docu
14
14
  - Supports request/response validations against OpenAPI document
15
15
  - Includes RSpec and Minitest helpers
16
16
 
17
+ ### Learn more
18
+
19
+ - [Let there be docs! A documentation-first approach to Rails API development](https://evilmartians.com/events/let-there-be-docs-a-documentation-first-approach-to-rails-api-development) – Talk and slides from Friendly.rb 2023
20
+
17
21
  <a href="https://evilmartians.com/?utm_source=skooma&utm_campaign=project_page">
18
22
  <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54">
19
23
  </a>
@@ -44,6 +48,9 @@ RSpec.configure do |config|
44
48
  # ...
45
49
  path_to_openapi = Rails.root.join("docs", "openapi.yml")
46
50
  config.include Skooma::RSpec[path_to_openapi], type: :request
51
+
52
+ # OR pass path_prefix option if your API is mounted under a prefix:
53
+ config.include Skooma::RSpec[path_to_openapi, path_prefix: "/internal/api"], type: :request
47
54
  end
48
55
  ```
49
56
 
@@ -19,7 +19,7 @@ module Skooma
19
19
  end
20
20
 
21
21
  def failure_message
22
- return "Expected #{@expected} status code" unless status_matches?
22
+ return "Expected #{@expected} status code, but got #{@mapped_response["response"]["status"]}" unless status_matches?
23
23
 
24
24
  super
25
25
  end
@@ -23,24 +23,24 @@ module Skooma
23
23
 
24
24
  def request_object
25
25
  # `rails` integration
26
- return request if defined?(::ActionDispatch)
26
+ return @request if defined?(::ActionDispatch) && @request.is_a?(::ActionDispatch::Request)
27
27
  # `rack-test` integration
28
- return last_request if defined?(::Rack::Test)
28
+ return last_request if defined?(::Rack::Test) && defined?(:last_request)
29
29
 
30
30
  raise "Request object not found"
31
31
  end
32
32
 
33
33
  def response_object
34
34
  # `rails` integration
35
- return response if defined?(::ActionDispatch)
35
+ return @response if defined?(::ActionDispatch) && @response.is_a?(::ActionDispatch::Response)
36
36
  # `rack-test` integration
37
- return last_response if defined?(::Rack::Test)
37
+ return last_response if defined?(::Rack::Test) && defined?(:last_response)
38
38
 
39
39
  raise "Response object not found"
40
40
  end
41
41
  end
42
42
 
43
- def initialize(helper_methods_module, openapi_path, base_uri: "https://skoomarb.dev/")
43
+ def initialize(helper_methods_module, openapi_path, base_uri: "https://skoomarb.dev/", path_prefix: "")
44
44
  super()
45
45
 
46
46
  registry = create_test_registry
@@ -50,6 +50,7 @@ module Skooma
50
50
  JSONSkooma::Sources::Local.new(pathname.dirname.to_s)
51
51
  )
52
52
  schema = registry.schema(URI.parse("#{base_uri}#{pathname.basename}"), schema_class: Skooma::Objects::OpenAPI)
53
+ schema.path_prefix = path_prefix
53
54
 
54
55
  include DefaultHelperMethods
55
56
  include helper_methods_module
@@ -32,7 +32,7 @@ module Skooma
32
32
  subresult.annotate({"path_attributes" => attributes})
33
33
  path_schema.evaluate(instance, subresult)
34
34
 
35
- if subresult.passed?
35
+ if subresult.passed? && subresult.children.any?
36
36
  result.success
37
37
  else
38
38
  result.failure("Path #{instance["path"]} is invalid")
@@ -43,6 +43,7 @@ module Skooma
43
43
  private
44
44
 
45
45
  def find_route(instance_path)
46
+ instance_path = instance_path.delete_prefix(json.root.path_prefix)
46
47
  return [instance_path, {}, json[instance_path]] if json.key?(instance_path)
47
48
 
48
49
  @regexp_map.reduce(nil) do |result, (path, path_regex, subschema)|
@@ -31,6 +31,18 @@ module Skooma
31
31
  super(Instance.new(instance), result)
32
32
  end
33
33
 
34
+ def path_prefix=(value)
35
+ raise ArgumentError, "Path prefix must be a string" unless value.is_a?(String)
36
+
37
+ @path_prefix = value
38
+ @path_prefix = "/#{@path_prefix}" unless @path_prefix.start_with?("/")
39
+ @path_prefix = @path_prefix.delete_suffix("/") if @path_prefix.end_with?("/")
40
+ end
41
+
42
+ def path_prefix
43
+ @path_prefix || ""
44
+ end
45
+
34
46
  def json_schema_dialect_uri
35
47
  @json_schema_dialect_uri || parent_schema&.json_schema_dialect_uri
36
48
  end
@@ -12,7 +12,7 @@ module Skooma
12
12
  def initialize(parent_schema, value)
13
13
  super
14
14
  keys = json.filter_map { |v| v["in"] && [v["in"].value, v["name"].value] }
15
- parent_params = (parent_schema.parent["parameters"] || [])
15
+ parent_params = parent_schema.parent["parameters"] || []
16
16
  parent_params.reject! do |v|
17
17
  v["in"] && keys.include?([v["in"].value, v["name"].value])
18
18
  end
@@ -9,9 +9,11 @@ module Skooma
9
9
  module ValueParser
10
10
  class << self
11
11
  def call(instance, result)
12
- type = result.sibling(instance, "in").annotation
13
- key = result.sibling(instance, "name").annotation
14
- raise Error, "Missing key: #{key}" unless key
12
+ type = result.sibling(instance, "in")&.annotation
13
+ raise Error, "Missing `in` key #{result.path}" unless type
14
+
15
+ key = result.sibling(instance, "name")&.annotation
16
+ raise Error, "Missing `name` key #{instance.path}: #{key}" unless key
15
17
 
16
18
  case type
17
19
  when "query"
@@ -30,7 +32,7 @@ module Skooma
30
32
  when "cookie"
31
33
  # instance["headers"]["Cookie"]
32
34
  else
33
- raise Error, "Unknown location: #{result.sibling(instance, "in").annotation}"
35
+ raise Error, "Unknown location: #{type}"
34
36
  end
35
37
  end
36
38
 
@@ -8,6 +8,10 @@ module Skooma
8
8
  def evaluate(instance, result)
9
9
  return result.discard unless instance["method"] == key
10
10
 
11
+ if json["responses"].nil? && instance["response"]
12
+ return result.failure("Responses are not listed for #{key.upcase} #{instance["path"]}")
13
+ end
14
+
11
15
  json.evaluate(instance, result)
12
16
  return result.success if result.passed?
13
17
 
@@ -18,8 +18,9 @@ module Skooma
18
18
  "keywordLocation" => node.path.to_s
19
19
  }
20
20
 
21
- child_data = node.children.filter_map do |_, child|
22
- node_data(child) unless child.valid?
21
+ child_data = []
22
+ node.each_children do |child|
23
+ child_data << node_data(child) unless child.valid?
23
24
  end
24
25
 
25
26
  if first || child_data.length > 1
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Skooma
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.2"
5
5
  end
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.2.0
4
+ version: 0.2.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: 2023-10-22 00:00:00.000000000 Z
11
+ date: 2024-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -30,15 +30,15 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.2'
33
+ version: 0.2.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0.2'
41
- description: I bring some sugar for your APIs.
40
+ version: 0.2.0
41
+ description: Apply a documentation-first approach to API development.
42
42
  email:
43
43
  - me@skryukov.dev
44
44
  executables: []
@@ -166,5 +166,5 @@ requirements: []
166
166
  rubygems_version: 3.3.7
167
167
  signing_key:
168
168
  specification_version: 4
169
- summary: I bring some sugar for your APIs.
169
+ summary: Validate API implementations against OpenAPI documents.
170
170
  test_files: []