openapi_minitest 0.1.0 → 0.1.1
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/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +9 -2
- data/CLAUDE.md +35 -1
- data/Makefile +0 -4
- data/README.md +16 -0
- data/lib/generators/openapi_minitest/install/install_generator.rb +32 -0
- data/lib/generators/openapi_minitest/install/templates/api_docs_controller.rb.tt +9 -0
- data/lib/generators/openapi_minitest/install/templates/index.html.erb.tt +47 -0
- data/lib/openapi_minitest/configuration.rb +3 -1
- data/lib/openapi_minitest/openapi/generator.rb +1 -1
- data/lib/openapi_minitest/result_collector.rb +47 -36
- data/lib/openapi_minitest/version.rb +1 -1
- data/release-please-config.json +1 -2
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e720190cb7ad695482a4e3200826cd437acc19b6cb6d00423b628d5e5efb7416
|
|
4
|
+
data.tar.gz: ee6598e687c92d030492cef298cb78fbbec2c0b76ec529f64d2f47172847f631
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 251b5d8354681ffa184b5ccedf8df342034083c9b0e1a3f1b28216f6d9b593214e60f040f12be12737fc9fe5897f34eee5cd030de985cb341d81045fe7c2c1da
|
|
7
|
+
data.tar.gz: 3fbcf78209751bab3a1f95f2fb86c5ce0bc7500b22b0f87938fb59ac9ffeedbd7112380fe7d0829bf75744093dd6c24e1f7e31689f78c41898f2a5b6e4a39de2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.1](https://github.com/k0va1/openapi_minitest/compare/v0.1.0...v0.1.1) (2026-02-10)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add configurable path sorting with sort_paths option ([432d5ea](https://github.com/k0va1/openapi_minitest/commit/432d5ea33586adc2a09dd0d6c9ff086767b7fbc5))
|
|
9
|
+
* add Rails generator for API docs controller with Scalar UI ([77b5627](https://github.com/k0va1/openapi_minitest/commit/77b562717bddf97ecc1c67b27855bf1e4673d1c5))
|
|
10
|
+
* add thread safety to ResultCollector using MonitorMixin ([18dd97d](https://github.com/k0va1/openapi_minitest/commit/18dd97dcd2b1925b2caee98eb6d45c3194e5da74))
|
|
11
|
+
|
|
3
12
|
## 0.1.0 (2026-02-06)
|
|
4
13
|
|
|
5
14
|
|
|
@@ -17,5 +26,3 @@
|
|
|
17
26
|
* reset ResultCollector between tests to prevent test pollution ([ecc5bc2](https://github.com/k0va1/openapi_minitest/commit/ecc5bc268a6e8833eebdc6566441c0032b93f2ec))
|
|
18
27
|
* set manifest version to 0.0.0 for initial release as 0.1.0 ([7e340df](https://github.com/k0va1/openapi_minitest/commit/7e340dfdecc3bafdd1b3bf6147fc9e92e2e10f7e))
|
|
19
28
|
* use security schemes instead of Authorization header parameter ([eb092ef](https://github.com/k0va1/openapi_minitest/commit/eb092efaa34ae92745c890d88dea18b8b55ca7f8))
|
|
20
|
-
|
|
21
|
-
## Changelog
|
data/CLAUDE.md
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
openapi_minitest is a Ruby gem that generates OpenAPI 3.1.0 documentation from Minitest integration tests. Users call a single `document_response` helper method in their tests to capture API endpoints into an OpenAPI YAML file.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
- **Run all tests + lint:** `bundle exec rake` (default task runs both `test` and `standard`)
|
|
12
|
+
- **Run tests only:** `bundle exec rake test`
|
|
13
|
+
- **Run a single test:** `bundle exec ruby -Ilib:test test/test_openapi_minitest.rb -n test_method_name`
|
|
14
|
+
- **Lint:** `bundle exec rake standard`
|
|
15
|
+
- **Lint autofix:** `bundle exec standardrb --fix`
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
The generation pipeline flows through four components in order:
|
|
20
|
+
|
|
21
|
+
1. **DSL (`lib/openapi_minitest/dsl.rb`)** — Provides the `document_response` method mixed into test classes. Handles schema validation (optional) and normalization of Symbol schema references to `$ref` format.
|
|
22
|
+
|
|
23
|
+
2. **ResultCollector (`lib/openapi_minitest/result_collector.rb`)** — Singleton that accumulates all recorded API calls during a test run. Stores two parallel hashes keyed by `"method /path"`: `@operations` (endpoint metadata) and `@responses` (grouped by HTTP status). Handles path normalization (e.g., `/api/users/123` → `/api/users/{user_id}`).
|
|
24
|
+
|
|
25
|
+
3. **Generator (`lib/openapi_minitest/openapi/generator.rb`)** — Reads from ResultCollector and builds the complete OpenAPI 3.1.0 document hash. Handles path sorting, request body extraction, example merging, and security scheme attachment. Outputs YAML.
|
|
26
|
+
|
|
27
|
+
4. **Railtie (`lib/openapi_minitest/railtie.rb`)** — Rails integration. Auto-includes DSL in `ActionDispatch::IntegrationTest`, registers `rails openapi:generate` rake task, and hooks into `Minitest.after_run` to trigger generation when `OPENAPI_GENERATE=true`.
|
|
28
|
+
|
|
29
|
+
Configuration and schema registry live in `lib/openapi_minitest/configuration.rb`.
|
|
30
|
+
|
|
31
|
+
## Test Setup
|
|
32
|
+
|
|
33
|
+
Tests use `OpenapiMinitest::TestHelpers` (defined in `test/test_helper.rb`) which resets both configuration and the ResultCollector singleton in `setup`, ensuring test isolation.
|
|
34
|
+
|
|
35
|
+
## Conventions
|
|
2
36
|
|
|
3
37
|
- Use Conventional Commits format for all commit messages (e.g., `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `test:`)
|
data/Makefile
CHANGED
data/README.md
CHANGED
|
@@ -155,6 +155,22 @@ OPENAPI_GENERATE=true rails test test/integration/
|
|
|
155
155
|
rails openapi:generate
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
+
### 5. Browse Documentation (optional)
|
|
159
|
+
|
|
160
|
+
Run the install generator to add an API docs page powered by [Scalar](https://github.com/scalar/scalar):
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
rails generate openapi_minitest:install
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
This creates:
|
|
167
|
+
|
|
168
|
+
- `app/controllers/api_docs_controller.rb` — serves the docs UI and the OpenAPI spec file
|
|
169
|
+
- `app/views/api_docs/index.html.erb` — Scalar API reference page (titled with your Rails app name)
|
|
170
|
+
- Routes: `GET /api-docs` and `GET /openapi.yml`
|
|
171
|
+
|
|
172
|
+
Visit `/api-docs` in your browser to explore your API documentation interactively.
|
|
173
|
+
|
|
158
174
|
## API Reference
|
|
159
175
|
|
|
160
176
|
### Configuration Options
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OpenapiMinitest
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
7
|
+
|
|
8
|
+
desc "Generates an ApiDocsController and view for serving OpenAPI documentation with Scalar UI"
|
|
9
|
+
|
|
10
|
+
def copy_controller
|
|
11
|
+
template "api_docs_controller.rb.tt", "app/controllers/api_docs_controller.rb"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def copy_view
|
|
15
|
+
template "index.html.erb.tt", "app/views/api_docs/index.html.erb"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def add_routes
|
|
19
|
+
route <<~RUBY
|
|
20
|
+
get "api-docs" => "api_docs#index"
|
|
21
|
+
get "openapi.yml" => "api_docs#spec"
|
|
22
|
+
RUBY
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def app_name
|
|
28
|
+
Rails.application.class.respond_to?(:module_parent_name) ? Rails.application.class.module_parent_name : Rails.application.class.parent_name
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title><%= app_name %> API Documentation</title>
|
|
5
|
+
<meta charset="utf-8"/>
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<script id="api-reference" data-url="/openapi.yml"></script>
|
|
10
|
+
<script>
|
|
11
|
+
var configuration = {
|
|
12
|
+
theme: 'elysiajs',
|
|
13
|
+
expandAllResponses: true,
|
|
14
|
+
layout: 'modern',
|
|
15
|
+
defaultOpenAllTags: true,
|
|
16
|
+
hideClientButton: true,
|
|
17
|
+
showSidebar: true,
|
|
18
|
+
showDeveloperTools: 'localhost',
|
|
19
|
+
showToolbar: 'localhost',
|
|
20
|
+
operationTitleSource: 'summary',
|
|
21
|
+
persistAuth: false,
|
|
22
|
+
telemetry: true,
|
|
23
|
+
isEditable: false,
|
|
24
|
+
isLoading: false,
|
|
25
|
+
hideModels: false,
|
|
26
|
+
documentDownloadType: 'both',
|
|
27
|
+
hideTestRequestButton: false,
|
|
28
|
+
hideSearch: false,
|
|
29
|
+
showOperationId: false,
|
|
30
|
+
hideDarkModeToggle: false,
|
|
31
|
+
withDefaultFonts: true,
|
|
32
|
+
expandAllModelSections: false,
|
|
33
|
+
orderSchemaPropertiesBy: 'alpha',
|
|
34
|
+
orderRequiredPropertiesFirst: true,
|
|
35
|
+
_integration: 'html',
|
|
36
|
+
darkMode: true,
|
|
37
|
+
hiddenClients: ['unirest'],
|
|
38
|
+
defaultHttpClient: {
|
|
39
|
+
targetKey: 'ruby',
|
|
40
|
+
clientKey: 'faraday'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
document.getElementById('api-reference').dataset.configuration = JSON.stringify(configuration)
|
|
44
|
+
</script>
|
|
45
|
+
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
|
46
|
+
</body>
|
|
47
|
+
</html>
|
|
@@ -10,7 +10,8 @@ module OpenapiMinitest
|
|
|
10
10
|
:security_schemes,
|
|
11
11
|
:tags,
|
|
12
12
|
:validate_schema,
|
|
13
|
-
:strict_validation
|
|
13
|
+
:strict_validation,
|
|
14
|
+
:sort_paths
|
|
14
15
|
|
|
15
16
|
def initialize
|
|
16
17
|
@title = "API Documentation"
|
|
@@ -22,6 +23,7 @@ module OpenapiMinitest
|
|
|
22
23
|
@tags = []
|
|
23
24
|
@validate_schema = true
|
|
24
25
|
@strict_validation = false
|
|
26
|
+
@sort_paths = :alphabetical
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
|
|
@@ -1,61 +1,72 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "singleton"
|
|
4
|
+
require "monitor"
|
|
4
5
|
require "json"
|
|
5
6
|
|
|
6
7
|
module OpenapiMinitest
|
|
7
8
|
class ResultCollector
|
|
8
9
|
include Singleton
|
|
10
|
+
include MonitorMixin
|
|
9
11
|
|
|
10
12
|
def initialize
|
|
13
|
+
super # MonitorMixin requires super
|
|
11
14
|
reset!
|
|
12
15
|
end
|
|
13
16
|
|
|
14
17
|
def reset!
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
synchronize do
|
|
19
|
+
@operations = {} # "METHOD /path" => operation data
|
|
20
|
+
@responses = {} # "METHOD /path" => { status => [response_data] }
|
|
21
|
+
end
|
|
17
22
|
end
|
|
18
23
|
|
|
19
24
|
def record(request:, response:, schema:, summary:, description:, tags:, operation_id:, deprecated:, test_name:)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
25
|
+
synchronize do
|
|
26
|
+
method = request.request_method.downcase
|
|
27
|
+
path = normalize_path(request.path)
|
|
28
|
+
key = "#{method} #{path}"
|
|
29
|
+
|
|
30
|
+
# Store operation metadata (first one wins for summary, tags merge)
|
|
31
|
+
@operations[key] ||= {
|
|
32
|
+
method: method,
|
|
33
|
+
path: path,
|
|
34
|
+
summary: summary,
|
|
35
|
+
tags: [],
|
|
36
|
+
operation_id: operation_id,
|
|
37
|
+
deprecated: deprecated,
|
|
38
|
+
parameters: extract_parameters(request, path),
|
|
39
|
+
requires_auth: has_authorization_header?(request)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# Merge tags from all tests
|
|
43
|
+
@operations[key][:tags] = (@operations[key][:tags] + tags).uniq
|
|
44
|
+
|
|
45
|
+
# Store response data grouped by status
|
|
46
|
+
status = response.status.to_s
|
|
47
|
+
@responses[key] ||= {}
|
|
48
|
+
@responses[key][status] ||= []
|
|
49
|
+
|
|
50
|
+
@responses[key][status] << {
|
|
51
|
+
description: description || default_description(response.status),
|
|
52
|
+
schema: schema,
|
|
53
|
+
example: parse_body(response.body),
|
|
54
|
+
test_name: test_name,
|
|
55
|
+
request_example: extract_request_example(request)
|
|
56
|
+
}
|
|
57
|
+
end
|
|
51
58
|
end
|
|
52
59
|
|
|
53
|
-
|
|
60
|
+
def operations
|
|
61
|
+
synchronize { @operations }
|
|
62
|
+
end
|
|
54
63
|
|
|
55
|
-
|
|
64
|
+
def responses
|
|
65
|
+
synchronize { @responses }
|
|
66
|
+
end
|
|
56
67
|
|
|
57
68
|
def empty?
|
|
58
|
-
@operations.empty?
|
|
69
|
+
synchronize { @operations.empty? }
|
|
59
70
|
end
|
|
60
71
|
|
|
61
72
|
private
|
data/release-please-config.json
CHANGED
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
"bump-patch-for-minor-pre-major": true,
|
|
10
10
|
"draft": false,
|
|
11
11
|
"prerelease": false,
|
|
12
|
-
"version-file": "lib/openapi_minitest/version.rb"
|
|
13
|
-
"release-as": "0.1.0"
|
|
12
|
+
"version-file": "lib/openapi_minitest/version.rb"
|
|
14
13
|
}
|
|
15
14
|
},
|
|
16
15
|
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openapi_minitest
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex Koval
|
|
@@ -67,6 +67,9 @@ files:
|
|
|
67
67
|
- Makefile
|
|
68
68
|
- README.md
|
|
69
69
|
- Rakefile
|
|
70
|
+
- lib/generators/openapi_minitest/install/install_generator.rb
|
|
71
|
+
- lib/generators/openapi_minitest/install/templates/api_docs_controller.rb.tt
|
|
72
|
+
- lib/generators/openapi_minitest/install/templates/index.html.erb.tt
|
|
70
73
|
- lib/openapi_minitest.rb
|
|
71
74
|
- lib/openapi_minitest/configuration.rb
|
|
72
75
|
- lib/openapi_minitest/dsl.rb
|