reqcord 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/.gitignore +8 -0
- data/CHANGELOG.md +77 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +171 -0
- data/LICENSE.txt +21 -0
- data/README.md +239 -95
- data/Rakefile +13 -0
- data/docs/configuration.md +319 -0
- data/examples/complex-spec-app/.rspec +1 -0
- data/examples/complex-spec-app/README.md +21 -0
- data/examples/complex-spec-app/app.rb +363 -0
- data/examples/complex-spec-app/docs/api/README.md +104 -0
- data/examples/complex-spec-app/docs/api/api/v1/admin/products/create.md +117 -0
- data/examples/complex-spec-app/docs/api/api/v1/admin/products/destroy.md +51 -0
- data/examples/complex-spec-app/docs/api/api/v1/admin/products/index.md +11 -0
- data/examples/complex-spec-app/docs/api/api/v1/admin/products/list.md +106 -0
- data/examples/complex-spec-app/docs/api/api/v1/auth/index.md +9 -0
- data/examples/complex-spec-app/docs/api/api/v1/auth/login.md +76 -0
- data/examples/complex-spec-app/docs/api/api/v1/cart-items/create.md +91 -0
- data/examples/complex-spec-app/docs/api/api/v1/cart-items/destroy.md +51 -0
- data/examples/complex-spec-app/docs/api/api/v1/cart-items/index.md +10 -0
- data/examples/complex-spec-app/docs/api/api/v1/carts/checkout.md +102 -0
- data/examples/complex-spec-app/docs/api/api/v1/carts/index.md +10 -0
- data/examples/complex-spec-app/docs/api/api/v1/carts/show.md +73 -0
- data/examples/complex-spec-app/docs/api/api/v1/home/index.md +9 -0
- data/examples/complex-spec-app/docs/api/api/v1/home/list.md +47 -0
- data/examples/complex-spec-app/docs/api/api/v1/notes/create.md +94 -0
- data/examples/complex-spec-app/docs/api/api/v1/notes/index.md +10 -0
- data/examples/complex-spec-app/docs/api/api/v1/notes/list.md +61 -0
- data/examples/complex-spec-app/docs/api/api/v1/orders/cancel.md +69 -0
- data/examples/complex-spec-app/docs/api/api/v1/orders/create.md +150 -0
- data/examples/complex-spec-app/docs/api/api/v1/orders/destroy.md +37 -0
- data/examples/complex-spec-app/docs/api/api/v1/orders/index.md +13 -0
- data/examples/complex-spec-app/docs/api/api/v1/orders/list.md +78 -0
- data/examples/complex-spec-app/docs/api/api/v1/orders/show.md +83 -0
- data/examples/complex-spec-app/docs/api/api/v1/products/index.md +11 -0
- data/examples/complex-spec-app/docs/api/api/v1/products/list.md +83 -0
- data/examples/complex-spec-app/docs/api/api/v1/products/search.md +88 -0
- data/examples/complex-spec-app/docs/api/api/v1/products/show.md +71 -0
- data/examples/complex-spec-app/docs/api/api/v1/profiles/index.md +10 -0
- data/examples/complex-spec-app/docs/api/api/v1/profiles/show.md +61 -0
- data/examples/complex-spec-app/docs/api/api/v1/profiles/update.md +91 -0
- data/examples/complex-spec-app/docs/api/api/v2/products/index.md +9 -0
- data/examples/complex-spec-app/docs/api/api/v2/products/list.md +77 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/admin/products/create.sh +18 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/admin/products/destroy.sh +9 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/admin/products/list.sh +9 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/auth/login.sh +9 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/cart-items/create.sh +16 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/cart-items/destroy.sh +9 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/carts/checkout.sh +13 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/carts/show.sh +9 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/home/list.sh +8 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/notes/create.sh +15 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/notes/list.sh +9 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/orders/cancel.sh +9 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/orders/create.sh +29 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/orders/destroy.sh +9 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/orders/list.sh +9 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/orders/show.sh +9 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/products/list.sh +8 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/products/search.sh +8 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/products/show.sh +8 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/profiles/show.sh +9 -0
- data/examples/complex-spec-app/docs/api/curl/api/v1/profiles/update.sh +16 -0
- data/examples/complex-spec-app/docs/api/curl/api/v2/products/list.sh +8 -0
- data/examples/complex-spec-app/docs/api/dataset.json +5116 -0
- data/examples/complex-spec-app/docs/api/postman/collection.json +2519 -0
- data/examples/complex-spec-app/generate.rb +14 -0
- data/examples/complex-spec-app/reqcord.yml +28 -0
- data/examples/complex-spec-app/spec/requests/admin_spec.rb +67 -0
- data/examples/complex-spec-app/spec/requests/cart_spec.rb +61 -0
- data/examples/complex-spec-app/spec/requests/home_and_auth_spec.rb +49 -0
- data/examples/complex-spec-app/spec/requests/orders_spec.rb +124 -0
- data/examples/complex-spec-app/spec/requests/products_spec.rb +65 -0
- data/examples/complex-spec-app/spec/spec_helper.rb +17 -0
- data/examples/complex-test-app/README.md +40 -0
- data/examples/complex-test-app/app.rb +384 -0
- data/examples/complex-test-app/docs/api/README.md +104 -0
- data/examples/complex-test-app/docs/api/api/v1/admin/products/create.md +117 -0
- data/examples/complex-test-app/docs/api/api/v1/admin/products/destroy.md +51 -0
- data/examples/complex-test-app/docs/api/api/v1/admin/products/index.md +11 -0
- data/examples/complex-test-app/docs/api/api/v1/admin/products/list.md +106 -0
- data/examples/complex-test-app/docs/api/api/v1/auth/index.md +9 -0
- data/examples/complex-test-app/docs/api/api/v1/auth/login.md +76 -0
- data/examples/complex-test-app/docs/api/api/v1/cart-items/create.md +91 -0
- data/examples/complex-test-app/docs/api/api/v1/cart-items/destroy.md +51 -0
- data/examples/complex-test-app/docs/api/api/v1/cart-items/index.md +10 -0
- data/examples/complex-test-app/docs/api/api/v1/carts/checkout.md +102 -0
- data/examples/complex-test-app/docs/api/api/v1/carts/index.md +10 -0
- data/examples/complex-test-app/docs/api/api/v1/carts/show.md +73 -0
- data/examples/complex-test-app/docs/api/api/v1/home/index.md +9 -0
- data/examples/complex-test-app/docs/api/api/v1/home/list.md +47 -0
- data/examples/complex-test-app/docs/api/api/v1/notes/create.md +94 -0
- data/examples/complex-test-app/docs/api/api/v1/notes/index.md +10 -0
- data/examples/complex-test-app/docs/api/api/v1/notes/list.md +61 -0
- data/examples/complex-test-app/docs/api/api/v1/orders/cancel.md +69 -0
- data/examples/complex-test-app/docs/api/api/v1/orders/create.md +150 -0
- data/examples/complex-test-app/docs/api/api/v1/orders/destroy.md +37 -0
- data/examples/complex-test-app/docs/api/api/v1/orders/index.md +13 -0
- data/examples/complex-test-app/docs/api/api/v1/orders/list.md +71 -0
- data/examples/complex-test-app/docs/api/api/v1/orders/show.md +83 -0
- data/examples/complex-test-app/docs/api/api/v1/products/index.md +11 -0
- data/examples/complex-test-app/docs/api/api/v1/products/list.md +83 -0
- data/examples/complex-test-app/docs/api/api/v1/products/search.md +88 -0
- data/examples/complex-test-app/docs/api/api/v1/products/show.md +71 -0
- data/examples/complex-test-app/docs/api/api/v1/profiles/index.md +10 -0
- data/examples/complex-test-app/docs/api/api/v1/profiles/show.md +61 -0
- data/examples/complex-test-app/docs/api/api/v1/profiles/update.md +91 -0
- data/examples/complex-test-app/docs/api/api/v2/products/index.md +9 -0
- data/examples/complex-test-app/docs/api/api/v2/products/list.md +77 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/admin/products/create.sh +18 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/admin/products/destroy.sh +9 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/admin/products/list.sh +9 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/auth/login.sh +9 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/cart-items/create.sh +16 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/cart-items/destroy.sh +9 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/carts/checkout.sh +13 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/carts/show.sh +9 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/home/list.sh +8 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/notes/create.sh +15 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/notes/list.sh +9 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/orders/cancel.sh +9 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/orders/create.sh +29 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/orders/destroy.sh +9 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/orders/list.sh +9 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/orders/show.sh +9 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/products/list.sh +8 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/products/search.sh +8 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/products/show.sh +8 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/profiles/show.sh +9 -0
- data/examples/complex-test-app/docs/api/curl/api/v1/profiles/update.sh +16 -0
- data/examples/complex-test-app/docs/api/curl/api/v2/products/list.sh +8 -0
- data/examples/complex-test-app/docs/api/dataset.json +5109 -0
- data/examples/complex-test-app/docs/api/postman/collection.json +2568 -0
- data/examples/complex-test-app/generate.rb +14 -0
- data/examples/complex-test-app/reqcord.yml +28 -0
- data/examples/complex-test-app/test/integration/admin_test.rb +70 -0
- data/examples/complex-test-app/test/integration/cart_test.rb +64 -0
- data/examples/complex-test-app/test/integration/home_and_auth_test.rb +53 -0
- data/examples/complex-test-app/test/integration/orders_test.rb +127 -0
- data/examples/complex-test-app/test/integration/products_test.rb +66 -0
- data/examples/reqcord.yml +58 -0
- data/examples/spec-app/.rspec +1 -0
- data/examples/spec-app/README.md +36 -0
- data/examples/spec-app/app.rb +209 -0
- data/examples/spec-app/docs/api/README.md +45 -0
- data/examples/spec-app/docs/api/api/v1/customers/create.md +95 -0
- data/examples/spec-app/docs/api/api/v1/customers/index.md +11 -0
- data/examples/spec-app/docs/api/api/v1/customers/list.md +67 -0
- data/examples/spec-app/docs/api/api/v1/customers/show.md +65 -0
- data/examples/spec-app/docs/api/api/v1/tasks/complete.md +51 -0
- data/examples/spec-app/docs/api/api/v1/tasks/create.md +90 -0
- data/examples/spec-app/docs/api/api/v1/tasks/destroy.md +35 -0
- data/examples/spec-app/docs/api/api/v1/tasks/index.md +14 -0
- data/examples/spec-app/docs/api/api/v1/tasks/list.md +65 -0
- data/examples/spec-app/docs/api/api/v1/tasks/show.md +65 -0
- data/examples/spec-app/docs/api/api/v1/tasks/update.md +74 -0
- data/examples/spec-app/docs/api/api/v1/users/create.md +95 -0
- data/examples/spec-app/docs/api/api/v1/users/index.md +11 -0
- data/examples/spec-app/docs/api/api/v1/users/list.md +67 -0
- data/examples/spec-app/docs/api/api/v1/users/show.md +65 -0
- data/examples/spec-app/docs/api/curl/api/v1/customers/create.sh +17 -0
- data/examples/spec-app/docs/api/curl/api/v1/customers/list.sh +9 -0
- data/examples/spec-app/docs/api/curl/api/v1/customers/show.sh +9 -0
- data/examples/spec-app/docs/api/curl/api/v1/tasks/complete.sh +8 -0
- data/examples/spec-app/docs/api/curl/api/v1/tasks/create.sh +15 -0
- data/examples/spec-app/docs/api/curl/api/v1/tasks/destroy.sh +8 -0
- data/examples/spec-app/docs/api/curl/api/v1/tasks/list.sh +8 -0
- data/examples/spec-app/docs/api/curl/api/v1/tasks/show.sh +8 -0
- data/examples/spec-app/docs/api/curl/api/v1/tasks/update.sh +14 -0
- data/examples/spec-app/docs/api/curl/api/v1/users/create.sh +17 -0
- data/examples/spec-app/docs/api/curl/api/v1/users/list.sh +9 -0
- data/examples/spec-app/docs/api/curl/api/v1/users/show.sh +9 -0
- data/examples/spec-app/docs/api/dataset.json +2402 -0
- data/examples/spec-app/docs/api/postman/collection.json +1290 -0
- data/examples/spec-app/generate.rb +14 -0
- data/examples/spec-app/reqcord.yml +27 -0
- data/examples/spec-app/spec/requests/customers_spec.rb +71 -0
- data/examples/spec-app/spec/requests/tasks_spec.rb +78 -0
- data/examples/spec-app/spec/requests/users_spec.rb +68 -0
- data/examples/spec-app/spec/spec_helper.rb +17 -0
- data/examples/test-app/README.md +57 -0
- data/examples/test-app/app.rb +212 -0
- data/examples/test-app/docs/api/README.md +45 -0
- data/examples/test-app/docs/api/api/v1/customers/create.md +95 -0
- data/examples/test-app/docs/api/api/v1/customers/index.md +11 -0
- data/examples/test-app/docs/api/api/v1/customers/list.md +67 -0
- data/examples/test-app/docs/api/api/v1/customers/show.md +65 -0
- data/examples/test-app/docs/api/api/v1/tasks/complete.md +51 -0
- data/examples/test-app/docs/api/api/v1/tasks/create.md +90 -0
- data/examples/test-app/docs/api/api/v1/tasks/destroy.md +35 -0
- data/examples/test-app/docs/api/api/v1/tasks/index.md +14 -0
- data/examples/test-app/docs/api/api/v1/tasks/list.md +65 -0
- data/examples/test-app/docs/api/api/v1/tasks/show.md +65 -0
- data/examples/test-app/docs/api/api/v1/tasks/update.md +74 -0
- data/examples/test-app/docs/api/api/v1/users/create.md +95 -0
- data/examples/test-app/docs/api/api/v1/users/index.md +11 -0
- data/examples/test-app/docs/api/api/v1/users/list.md +67 -0
- data/examples/test-app/docs/api/api/v1/users/show.md +65 -0
- data/examples/test-app/docs/api/curl/api/v1/customers/create.sh +17 -0
- data/examples/test-app/docs/api/curl/api/v1/customers/list.sh +9 -0
- data/examples/test-app/docs/api/curl/api/v1/customers/show.sh +9 -0
- data/examples/test-app/docs/api/curl/api/v1/tasks/complete.sh +8 -0
- data/examples/test-app/docs/api/curl/api/v1/tasks/create.sh +15 -0
- data/examples/test-app/docs/api/curl/api/v1/tasks/destroy.sh +8 -0
- data/examples/test-app/docs/api/curl/api/v1/tasks/list.sh +8 -0
- data/examples/test-app/docs/api/curl/api/v1/tasks/show.sh +8 -0
- data/examples/test-app/docs/api/curl/api/v1/tasks/update.sh +14 -0
- data/examples/test-app/docs/api/curl/api/v1/users/create.sh +17 -0
- data/examples/test-app/docs/api/curl/api/v1/users/list.sh +9 -0
- data/examples/test-app/docs/api/curl/api/v1/users/show.sh +9 -0
- data/examples/test-app/docs/api/dataset.json +2402 -0
- data/examples/test-app/docs/api/postman/collection.json +1290 -0
- data/examples/test-app/generate.rb +14 -0
- data/examples/test-app/reqcord.yml +28 -0
- data/examples/test-app/test/integration/customers_test.rb +72 -0
- data/examples/test-app/test/integration/tasks_test.rb +80 -0
- data/examples/test-app/test/integration/users_test.rb +72 -0
- data/lib/reqcord/capture/collector.rb +31 -0
- data/lib/reqcord/capture/integration_patch.rb +209 -0
- data/lib/reqcord/capture/minitest_context.rb +34 -0
- data/lib/reqcord/capture/rspec_context.rb +42 -0
- data/lib/reqcord/capture/test_context.rb +25 -0
- data/lib/reqcord/capture.rb +19 -0
- data/lib/reqcord/configuration.rb +198 -0
- data/lib/reqcord/dataset.rb +176 -0
- data/lib/reqcord/endpoint.rb +263 -0
- data/lib/reqcord/errors.rb +9 -0
- data/lib/reqcord/exporters/curl.rb +68 -0
- data/lib/reqcord/exporters/markdown.rb +295 -0
- data/lib/reqcord/exporters/postman.rb +206 -0
- data/lib/reqcord/exporters.rb +32 -0
- data/lib/reqcord/generator.rb +364 -0
- data/lib/reqcord/railtie.rb +51 -0
- data/lib/reqcord/renderers/curl.rb +56 -0
- data/lib/reqcord/renderers/payload.rb +69 -0
- data/lib/reqcord/request_example.rb +104 -0
- data/lib/reqcord/response_example.rb +72 -0
- data/lib/reqcord/route_collector.rb +242 -0
- data/lib/reqcord/sanitizers/sanitizer.rb +140 -0
- data/lib/reqcord/schema.rb +187 -0
- data/lib/reqcord/support.rb +58 -0
- data/lib/reqcord/version.rb +5 -0
- data/lib/reqcord.rb +78 -0
- data/lib/tasks/reqcord.rake +99 -0
- data/reqcord.gemspec +46 -0
- metadata +317 -3
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Stands in for `bin/rails reqcord:generate`, which this single file example
|
|
4
|
+
# has no `bin/rails` to run.
|
|
5
|
+
require_relative "app"
|
|
6
|
+
|
|
7
|
+
dataset = Reqcord::Generator.call(
|
|
8
|
+
resources: ENV.fetch("RESOURCE", "").split(",").map(&:strip).reject(&:empty?),
|
|
9
|
+
version: ENV["VERSION"]
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
puts
|
|
13
|
+
puts "Endpoints: #{dataset.endpoints.size} (#{dataset.documented_endpoints.size} covered by tests)"
|
|
14
|
+
puts "Output: #{Reqcord.configuration.output_directory}"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
|
|
3
|
+
test:
|
|
4
|
+
framework: minitest
|
|
5
|
+
paths:
|
|
6
|
+
- test/integration
|
|
7
|
+
|
|
8
|
+
routes:
|
|
9
|
+
prefix: /api
|
|
10
|
+
|
|
11
|
+
output:
|
|
12
|
+
directory: docs/api
|
|
13
|
+
|
|
14
|
+
exporters:
|
|
15
|
+
- curl
|
|
16
|
+
- markdown
|
|
17
|
+
- postman
|
|
18
|
+
|
|
19
|
+
variables:
|
|
20
|
+
base_url: http://localhost:3000
|
|
21
|
+
|
|
22
|
+
sanitize:
|
|
23
|
+
headers:
|
|
24
|
+
Authorization: "Bearer {{token}}"
|
|
25
|
+
X-Api-Key: "{{api_key}}"
|
|
26
|
+
body:
|
|
27
|
+
password: "{{password}}"
|
|
28
|
+
token: "{{token}}"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../app"
|
|
4
|
+
require "minitest/autorun"
|
|
5
|
+
|
|
6
|
+
class AdminTest < ActionDispatch::IntegrationTest
|
|
7
|
+
def api_key
|
|
8
|
+
{ "X-Api-Key" => "sk_live_super-secret-key" }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
test "admin lists products with costs" do
|
|
12
|
+
get "/api/v1/admin/products", headers: api_key, as: :json
|
|
13
|
+
|
|
14
|
+
assert_response :ok
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
test "admin requires an api key" do
|
|
18
|
+
get "/api/v1/admin/products", as: :json
|
|
19
|
+
|
|
20
|
+
assert_response :unauthorized
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
test "admin creates a product" do
|
|
24
|
+
post "/api/v1/admin/products",
|
|
25
|
+
params: { product: { sku: "TEA-003", name: "Jasmine", category: "tea", price_cents: 1400 } },
|
|
26
|
+
headers: api_key,
|
|
27
|
+
as: :json
|
|
28
|
+
|
|
29
|
+
assert_response :created
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
test "admin rejects a product without a sku" do
|
|
33
|
+
post "/api/v1/admin/products", params: { product: { sku: "", name: "Nameless" } }, headers: api_key, as: :json
|
|
34
|
+
|
|
35
|
+
assert_response :unprocessable_entity
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
test "admin rejects a duplicate sku" do
|
|
39
|
+
post "/api/v1/admin/products",
|
|
40
|
+
params: { product: { sku: "TEA-001", name: "Earl Grey again", category: "tea", price_cents: 1200 } },
|
|
41
|
+
headers: api_key,
|
|
42
|
+
as: :json
|
|
43
|
+
|
|
44
|
+
assert_response :conflict
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
test "admin deletes a product" do
|
|
48
|
+
delete "/api/v1/admin/products/4", headers: api_key, as: :json
|
|
49
|
+
|
|
50
|
+
assert_response :no_content
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
test "admin cannot delete an unknown product" do
|
|
54
|
+
delete "/api/v1/admin/products/999", headers: api_key, as: :json
|
|
55
|
+
|
|
56
|
+
assert_response :not_found
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
test "v2 lists products" do
|
|
60
|
+
get "/api/v2/products", as: :json
|
|
61
|
+
|
|
62
|
+
assert_response :ok
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
test "v2 follows a cursor" do
|
|
66
|
+
get "/api/v2/products", params: { cursor: "eyJpZCI6Mn0" }, as: :json
|
|
67
|
+
|
|
68
|
+
assert_response :ok
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../app"
|
|
4
|
+
require "minitest/autorun"
|
|
5
|
+
|
|
6
|
+
class CartTest < ActionDispatch::IntegrationTest
|
|
7
|
+
def auth
|
|
8
|
+
{ "Authorization" => "Bearer eyJhbGciOiJIUzI1NiJ9.super-secret" }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
test "shows the cart" do
|
|
12
|
+
get "/api/v1/cart", headers: auth, as: :json
|
|
13
|
+
|
|
14
|
+
assert_response :ok
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
test "adds an item to the cart" do
|
|
18
|
+
post "/api/v1/cart/items", params: { item: { sku: "TEA-002", quantity: 3 } }, headers: auth, as: :json
|
|
19
|
+
|
|
20
|
+
assert_response :created
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
test "rejects an unknown sku" do
|
|
24
|
+
post "/api/v1/cart/items", params: { item: { sku: "TEA-999", quantity: 1 } }, headers: auth, as: :json
|
|
25
|
+
|
|
26
|
+
assert_response :unprocessable_entity
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
test "removes an item from the cart" do
|
|
30
|
+
delete "/api/v1/cart/items/TEA-001", headers: auth, as: :json
|
|
31
|
+
|
|
32
|
+
assert_response :no_content
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
test "cannot remove an item that is not in the cart" do
|
|
36
|
+
delete "/api/v1/cart/items/MUG-002", headers: auth, as: :json
|
|
37
|
+
|
|
38
|
+
assert_response :not_found
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
test "checks out with a card" do
|
|
42
|
+
post "/api/v1/cart/checkout", params: { payment_method: "card" }, headers: auth, as: :json
|
|
43
|
+
|
|
44
|
+
assert_response :created
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
test "checks out with a bank transfer" do
|
|
48
|
+
post "/api/v1/cart/checkout", params: { payment_method: "bank_transfer" }, headers: auth, as: :json
|
|
49
|
+
|
|
50
|
+
assert_response :created
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
test "rejects an unknown payment method" do
|
|
54
|
+
post "/api/v1/cart/checkout", params: { payment_method: "cash" }, headers: auth, as: :json
|
|
55
|
+
|
|
56
|
+
assert_response :unprocessable_entity
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
test "cart requires authentication" do
|
|
60
|
+
get "/api/v1/cart", as: :json
|
|
61
|
+
|
|
62
|
+
assert_response :unauthorized
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../app"
|
|
4
|
+
require "minitest/autorun"
|
|
5
|
+
|
|
6
|
+
class HomeAndAuthTest < ActionDispatch::IntegrationTest
|
|
7
|
+
def auth
|
|
8
|
+
{ "Authorization" => "Bearer eyJhbGciOiJIUzI1NiJ9.super-secret" }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
test "root describes the api" do
|
|
12
|
+
get "/api/v1", as: :json
|
|
13
|
+
|
|
14
|
+
assert_response :ok
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# A form post, not JSON: the documentation must keep it a form.
|
|
18
|
+
test "logs in with a form" do
|
|
19
|
+
post "/api/v1/auth/login", params: { email: "ada@example.com", password: "correct-horse-battery" }
|
|
20
|
+
|
|
21
|
+
assert_response :ok
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
test "rejects a wrong password" do
|
|
25
|
+
post "/api/v1/auth/login", params: { email: "ada@example.com", password: "wrong" }
|
|
26
|
+
|
|
27
|
+
assert_response :unauthorized
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
test "shows the profile" do
|
|
31
|
+
get "/api/v1/profile", headers: auth, as: :json
|
|
32
|
+
|
|
33
|
+
assert_response :ok
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
test "updates the profile" do
|
|
37
|
+
patch "/api/v1/profile", params: { profile: { name: "Ada L.", locale: "tr" } }, headers: auth, as: :json
|
|
38
|
+
|
|
39
|
+
assert_response :ok
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
test "rejects an unknown locale" do
|
|
43
|
+
patch "/api/v1/profile", params: { profile: { locale: "xx" } }, headers: auth, as: :json
|
|
44
|
+
|
|
45
|
+
assert_response :unprocessable_entity
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
test "profile requires authentication" do
|
|
49
|
+
get "/api/v1/profile", as: :json
|
|
50
|
+
|
|
51
|
+
assert_response :unauthorized
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../app"
|
|
4
|
+
require "minitest/autorun"
|
|
5
|
+
|
|
6
|
+
class OrdersTest < ActionDispatch::IntegrationTest
|
|
7
|
+
def auth
|
|
8
|
+
{ "Authorization" => "Bearer eyJhbGciOiJIUzI1NiJ9.super-secret" }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def order_payload
|
|
12
|
+
{
|
|
13
|
+
order: {
|
|
14
|
+
line_items: [
|
|
15
|
+
{ sku: "TEA-001", quantity: 2 },
|
|
16
|
+
{ sku: "MUG-001", quantity: 1 }
|
|
17
|
+
],
|
|
18
|
+
shipping_address: { line1: "1 Analytical Engine Way", city: "London", country: "GB" }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
test "lists orders" do
|
|
24
|
+
get "/api/v1/orders", headers: auth, as: :json
|
|
25
|
+
|
|
26
|
+
assert_response :ok
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
test "lists pending orders" do
|
|
30
|
+
get "/api/v1/orders", params: { status: "pending" }, headers: auth, as: :json
|
|
31
|
+
|
|
32
|
+
assert_response :ok
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
test "lists shipped orders" do
|
|
36
|
+
get "/api/v1/orders", params: { status: "shipped" }, headers: auth, as: :json
|
|
37
|
+
|
|
38
|
+
assert_response :ok
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
test "shows an order" do
|
|
42
|
+
get "/api/v1/orders/1", headers: auth, as: :json
|
|
43
|
+
|
|
44
|
+
assert_response :ok
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
test "hides another customer's order" do
|
|
48
|
+
get "/api/v1/orders/3", headers: auth, as: :json
|
|
49
|
+
|
|
50
|
+
assert_response :forbidden
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
test "returns not found for an unknown order" do
|
|
54
|
+
get "/api/v1/orders/999", headers: auth, as: :json
|
|
55
|
+
|
|
56
|
+
assert_response :not_found
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
test "creates an order" do
|
|
60
|
+
post "/api/v1/orders", params: order_payload, headers: auth, as: :json
|
|
61
|
+
|
|
62
|
+
assert_response :created
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
test "creates a single item order" do
|
|
66
|
+
post "/api/v1/orders",
|
|
67
|
+
params: { order: { line_items: [{ sku: "MUG-002", quantity: 1 }], shipping_address: { line1: "Piazza", city: "Rome", country: "IT" } } },
|
|
68
|
+
headers: auth,
|
|
69
|
+
as: :json
|
|
70
|
+
|
|
71
|
+
assert_response :created
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
test "rejects an order without line items" do
|
|
75
|
+
post "/api/v1/orders", params: { order: { line_items: [] } }, headers: auth, as: :json
|
|
76
|
+
|
|
77
|
+
assert_response :unprocessable_entity
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
test "rejects an unknown sku" do
|
|
81
|
+
post "/api/v1/orders", params: { order: { line_items: [{ sku: "TEA-999", quantity: 1 }] } }, headers: auth, as: :json
|
|
82
|
+
|
|
83
|
+
assert_response :unprocessable_entity
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
test "cancels a pending order" do
|
|
87
|
+
post "/api/v1/orders/1/cancel", headers: auth, as: :json
|
|
88
|
+
|
|
89
|
+
assert_response :ok
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
test "cannot cancel a shipped order" do
|
|
93
|
+
post "/api/v1/orders/2/cancel", headers: auth, as: :json
|
|
94
|
+
|
|
95
|
+
assert_response :conflict
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
test "deletes an order" do
|
|
99
|
+
delete "/api/v1/orders/1", headers: auth, as: :json
|
|
100
|
+
|
|
101
|
+
assert_response :no_content
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
test "orders require authentication" do
|
|
105
|
+
get "/api/v1/orders", as: :json
|
|
106
|
+
|
|
107
|
+
assert_response :unauthorized
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
test "lists the notes of an order" do
|
|
111
|
+
get "/api/v1/orders/1/notes", headers: auth, as: :json
|
|
112
|
+
|
|
113
|
+
assert_response :ok
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
test "adds a note to an order" do
|
|
117
|
+
post "/api/v1/orders/1/notes", params: { note: { body: "Ring the bell twice" } }, headers: auth, as: :json
|
|
118
|
+
|
|
119
|
+
assert_response :created
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
test "rejects an empty note" do
|
|
123
|
+
post "/api/v1/orders/1/notes", params: { note: { body: "" } }, headers: auth, as: :json
|
|
124
|
+
|
|
125
|
+
assert_response :unprocessable_entity
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../app"
|
|
4
|
+
require "minitest/autorun"
|
|
5
|
+
|
|
6
|
+
class ProductsTest < ActionDispatch::IntegrationTest
|
|
7
|
+
test "lists products" do
|
|
8
|
+
get "/api/v1/products", as: :json
|
|
9
|
+
|
|
10
|
+
assert_response :ok
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
test "filters products by category" do
|
|
14
|
+
get "/api/v1/products", params: { filter: { category: "tea" } }, as: :json
|
|
15
|
+
|
|
16
|
+
assert_response :ok
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
test "filters mugs" do
|
|
20
|
+
get "/api/v1/products", params: { filter: { category: "mugs" } }, as: :json
|
|
21
|
+
|
|
22
|
+
assert_response :ok
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
test "sorts by price ascending" do
|
|
26
|
+
get "/api/v1/products", params: { sort: "price_asc" }, as: :json
|
|
27
|
+
|
|
28
|
+
assert_response :ok
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
test "sorts by price descending" do
|
|
32
|
+
get "/api/v1/products", params: { sort: "price_desc" }, as: :json
|
|
33
|
+
|
|
34
|
+
assert_response :ok
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
test "paginates" do
|
|
38
|
+
get "/api/v1/products", params: { page: 2, per_page: 2 }, as: :json
|
|
39
|
+
|
|
40
|
+
assert_response :ok
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
test "shows a product" do
|
|
44
|
+
get "/api/v1/products/3", as: :json
|
|
45
|
+
|
|
46
|
+
assert_response :ok
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
test "returns not found for an unknown product" do
|
|
50
|
+
get "/api/v1/products/999", as: :json
|
|
51
|
+
|
|
52
|
+
assert_response :not_found
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
test "searches products" do
|
|
56
|
+
get "/api/v1/products/search", params: { q: "mug" }, as: :json
|
|
57
|
+
|
|
58
|
+
assert_response :ok
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
test "search needs a query" do
|
|
62
|
+
get "/api/v1/products/search", as: :json
|
|
63
|
+
|
|
64
|
+
assert_response :bad_request
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Reqcord configuration. Copy this file to your application root as
|
|
2
|
+
# `reqcord.yml`, or generate it with `bin/rails reqcord:init`.
|
|
3
|
+
#
|
|
4
|
+
# Precedence: environment variables > reqcord.yml > Reqcord defaults.
|
|
5
|
+
# Every key is documented in docs/configuration.md.
|
|
6
|
+
|
|
7
|
+
version: 1
|
|
8
|
+
|
|
9
|
+
test:
|
|
10
|
+
# minitest or rspec.
|
|
11
|
+
framework: minitest
|
|
12
|
+
|
|
13
|
+
# Where the tests that exercise your API live. Reqcord picks the runner:
|
|
14
|
+
# `bin/rails test <paths>` in a Rails app, `rspec <paths>` for request
|
|
15
|
+
# specs, a plain Ruby runner when there is no bin/rails.
|
|
16
|
+
paths:
|
|
17
|
+
- test/integration
|
|
18
|
+
|
|
19
|
+
# Or spell the command out yourself; it wins over `paths`. Globs expand.
|
|
20
|
+
# command: bin/rails test test/integration test/api
|
|
21
|
+
|
|
22
|
+
routes:
|
|
23
|
+
# Only routes under this prefix are documented. Filter a single run with
|
|
24
|
+
# RESOURCE=customers,cart or VERSION=v2 instead of editing this file.
|
|
25
|
+
prefix: /api
|
|
26
|
+
|
|
27
|
+
output:
|
|
28
|
+
# Relative to the application root. Override per run with REQCORD_OUTPUT.
|
|
29
|
+
directory: docs/api
|
|
30
|
+
|
|
31
|
+
# Routes no test reached with a 2xx are listed in the index either way;
|
|
32
|
+
# `true` also writes a page for each of them.
|
|
33
|
+
include_uncovered: false
|
|
34
|
+
|
|
35
|
+
# markdown: pages under docs/api, curl: one runnable .sh per endpoint,
|
|
36
|
+
# postman: postman/collection.json (import into Postman or Hoppscotch).
|
|
37
|
+
exporters:
|
|
38
|
+
- curl
|
|
39
|
+
- markdown
|
|
40
|
+
- postman
|
|
41
|
+
|
|
42
|
+
variables:
|
|
43
|
+
# Used as the host in every generated cURL and as the Postman `base_url`
|
|
44
|
+
# variable. Override with REQCORD_BASE_URL.
|
|
45
|
+
base_url: http://localhost:3000
|
|
46
|
+
|
|
47
|
+
sanitize:
|
|
48
|
+
# Captured header values are replaced with these, verbatim. Authorization,
|
|
49
|
+
# Cookie and X-Api-Key are always redacted, configured here or not.
|
|
50
|
+
headers:
|
|
51
|
+
Authorization: "Bearer {{token}}"
|
|
52
|
+
X-Api-Key: "{{api_key}}"
|
|
53
|
+
X-Account-Id: "{{account_id}}"
|
|
54
|
+
|
|
55
|
+
# Body keys, matched at any depth, in requests and responses alike.
|
|
56
|
+
body:
|
|
57
|
+
password: "{{password}}"
|
|
58
|
+
access_token: "{{token}}"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--require spec_helper
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# spec-app (RSpec)
|
|
2
|
+
|
|
3
|
+
The same API as [test-app](../test-app), documented from RSpec request specs
|
|
4
|
+
instead of Minitest. The generated dataset is identical in shape: the test
|
|
5
|
+
framework only decides how examples are named.
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
app.rb the application (customers, users, tasks)
|
|
9
|
+
spec/requests/*_spec.rb ordinary request specs
|
|
10
|
+
spec/spec_helper.rb request helpers (see the note below)
|
|
11
|
+
reqcord.yml `test.framework: rspec`
|
|
12
|
+
docs/api/ generated Markdown, cURL scripts and Postman
|
|
13
|
+
collection — the same files test-app gets
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Regenerate
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
ruby generate.rb
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Notes
|
|
23
|
+
|
|
24
|
+
This example runs on plain `rspec-core`, so `spec_helper.rb` includes the
|
|
25
|
+
ActionDispatch request helpers itself and the specs assert
|
|
26
|
+
`response.status`. An application using `rspec-rails` gets `type: :request`
|
|
27
|
+
and `have_http_status` for free and needs none of that.
|
|
28
|
+
|
|
29
|
+
The only Reqcord-facing difference from test-app is one line in `reqcord.yml`:
|
|
30
|
+
|
|
31
|
+
```yaml
|
|
32
|
+
test:
|
|
33
|
+
framework: rspec
|
|
34
|
+
paths:
|
|
35
|
+
- spec/requests
|
|
36
|
+
```
|