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.
Files changed (249) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -0
  3. data/CHANGELOG.md +77 -0
  4. data/Gemfile +5 -0
  5. data/Gemfile.lock +171 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +239 -95
  8. data/Rakefile +13 -0
  9. data/docs/configuration.md +319 -0
  10. data/examples/complex-spec-app/.rspec +1 -0
  11. data/examples/complex-spec-app/README.md +21 -0
  12. data/examples/complex-spec-app/app.rb +363 -0
  13. data/examples/complex-spec-app/docs/api/README.md +104 -0
  14. data/examples/complex-spec-app/docs/api/api/v1/admin/products/create.md +117 -0
  15. data/examples/complex-spec-app/docs/api/api/v1/admin/products/destroy.md +51 -0
  16. data/examples/complex-spec-app/docs/api/api/v1/admin/products/index.md +11 -0
  17. data/examples/complex-spec-app/docs/api/api/v1/admin/products/list.md +106 -0
  18. data/examples/complex-spec-app/docs/api/api/v1/auth/index.md +9 -0
  19. data/examples/complex-spec-app/docs/api/api/v1/auth/login.md +76 -0
  20. data/examples/complex-spec-app/docs/api/api/v1/cart-items/create.md +91 -0
  21. data/examples/complex-spec-app/docs/api/api/v1/cart-items/destroy.md +51 -0
  22. data/examples/complex-spec-app/docs/api/api/v1/cart-items/index.md +10 -0
  23. data/examples/complex-spec-app/docs/api/api/v1/carts/checkout.md +102 -0
  24. data/examples/complex-spec-app/docs/api/api/v1/carts/index.md +10 -0
  25. data/examples/complex-spec-app/docs/api/api/v1/carts/show.md +73 -0
  26. data/examples/complex-spec-app/docs/api/api/v1/home/index.md +9 -0
  27. data/examples/complex-spec-app/docs/api/api/v1/home/list.md +47 -0
  28. data/examples/complex-spec-app/docs/api/api/v1/notes/create.md +94 -0
  29. data/examples/complex-spec-app/docs/api/api/v1/notes/index.md +10 -0
  30. data/examples/complex-spec-app/docs/api/api/v1/notes/list.md +61 -0
  31. data/examples/complex-spec-app/docs/api/api/v1/orders/cancel.md +69 -0
  32. data/examples/complex-spec-app/docs/api/api/v1/orders/create.md +150 -0
  33. data/examples/complex-spec-app/docs/api/api/v1/orders/destroy.md +37 -0
  34. data/examples/complex-spec-app/docs/api/api/v1/orders/index.md +13 -0
  35. data/examples/complex-spec-app/docs/api/api/v1/orders/list.md +78 -0
  36. data/examples/complex-spec-app/docs/api/api/v1/orders/show.md +83 -0
  37. data/examples/complex-spec-app/docs/api/api/v1/products/index.md +11 -0
  38. data/examples/complex-spec-app/docs/api/api/v1/products/list.md +83 -0
  39. data/examples/complex-spec-app/docs/api/api/v1/products/search.md +88 -0
  40. data/examples/complex-spec-app/docs/api/api/v1/products/show.md +71 -0
  41. data/examples/complex-spec-app/docs/api/api/v1/profiles/index.md +10 -0
  42. data/examples/complex-spec-app/docs/api/api/v1/profiles/show.md +61 -0
  43. data/examples/complex-spec-app/docs/api/api/v1/profiles/update.md +91 -0
  44. data/examples/complex-spec-app/docs/api/api/v2/products/index.md +9 -0
  45. data/examples/complex-spec-app/docs/api/api/v2/products/list.md +77 -0
  46. data/examples/complex-spec-app/docs/api/curl/api/v1/admin/products/create.sh +18 -0
  47. data/examples/complex-spec-app/docs/api/curl/api/v1/admin/products/destroy.sh +9 -0
  48. data/examples/complex-spec-app/docs/api/curl/api/v1/admin/products/list.sh +9 -0
  49. data/examples/complex-spec-app/docs/api/curl/api/v1/auth/login.sh +9 -0
  50. data/examples/complex-spec-app/docs/api/curl/api/v1/cart-items/create.sh +16 -0
  51. data/examples/complex-spec-app/docs/api/curl/api/v1/cart-items/destroy.sh +9 -0
  52. data/examples/complex-spec-app/docs/api/curl/api/v1/carts/checkout.sh +13 -0
  53. data/examples/complex-spec-app/docs/api/curl/api/v1/carts/show.sh +9 -0
  54. data/examples/complex-spec-app/docs/api/curl/api/v1/home/list.sh +8 -0
  55. data/examples/complex-spec-app/docs/api/curl/api/v1/notes/create.sh +15 -0
  56. data/examples/complex-spec-app/docs/api/curl/api/v1/notes/list.sh +9 -0
  57. data/examples/complex-spec-app/docs/api/curl/api/v1/orders/cancel.sh +9 -0
  58. data/examples/complex-spec-app/docs/api/curl/api/v1/orders/create.sh +29 -0
  59. data/examples/complex-spec-app/docs/api/curl/api/v1/orders/destroy.sh +9 -0
  60. data/examples/complex-spec-app/docs/api/curl/api/v1/orders/list.sh +9 -0
  61. data/examples/complex-spec-app/docs/api/curl/api/v1/orders/show.sh +9 -0
  62. data/examples/complex-spec-app/docs/api/curl/api/v1/products/list.sh +8 -0
  63. data/examples/complex-spec-app/docs/api/curl/api/v1/products/search.sh +8 -0
  64. data/examples/complex-spec-app/docs/api/curl/api/v1/products/show.sh +8 -0
  65. data/examples/complex-spec-app/docs/api/curl/api/v1/profiles/show.sh +9 -0
  66. data/examples/complex-spec-app/docs/api/curl/api/v1/profiles/update.sh +16 -0
  67. data/examples/complex-spec-app/docs/api/curl/api/v2/products/list.sh +8 -0
  68. data/examples/complex-spec-app/docs/api/dataset.json +5116 -0
  69. data/examples/complex-spec-app/docs/api/postman/collection.json +2519 -0
  70. data/examples/complex-spec-app/generate.rb +14 -0
  71. data/examples/complex-spec-app/reqcord.yml +28 -0
  72. data/examples/complex-spec-app/spec/requests/admin_spec.rb +67 -0
  73. data/examples/complex-spec-app/spec/requests/cart_spec.rb +61 -0
  74. data/examples/complex-spec-app/spec/requests/home_and_auth_spec.rb +49 -0
  75. data/examples/complex-spec-app/spec/requests/orders_spec.rb +124 -0
  76. data/examples/complex-spec-app/spec/requests/products_spec.rb +65 -0
  77. data/examples/complex-spec-app/spec/spec_helper.rb +17 -0
  78. data/examples/complex-test-app/README.md +40 -0
  79. data/examples/complex-test-app/app.rb +384 -0
  80. data/examples/complex-test-app/docs/api/README.md +104 -0
  81. data/examples/complex-test-app/docs/api/api/v1/admin/products/create.md +117 -0
  82. data/examples/complex-test-app/docs/api/api/v1/admin/products/destroy.md +51 -0
  83. data/examples/complex-test-app/docs/api/api/v1/admin/products/index.md +11 -0
  84. data/examples/complex-test-app/docs/api/api/v1/admin/products/list.md +106 -0
  85. data/examples/complex-test-app/docs/api/api/v1/auth/index.md +9 -0
  86. data/examples/complex-test-app/docs/api/api/v1/auth/login.md +76 -0
  87. data/examples/complex-test-app/docs/api/api/v1/cart-items/create.md +91 -0
  88. data/examples/complex-test-app/docs/api/api/v1/cart-items/destroy.md +51 -0
  89. data/examples/complex-test-app/docs/api/api/v1/cart-items/index.md +10 -0
  90. data/examples/complex-test-app/docs/api/api/v1/carts/checkout.md +102 -0
  91. data/examples/complex-test-app/docs/api/api/v1/carts/index.md +10 -0
  92. data/examples/complex-test-app/docs/api/api/v1/carts/show.md +73 -0
  93. data/examples/complex-test-app/docs/api/api/v1/home/index.md +9 -0
  94. data/examples/complex-test-app/docs/api/api/v1/home/list.md +47 -0
  95. data/examples/complex-test-app/docs/api/api/v1/notes/create.md +94 -0
  96. data/examples/complex-test-app/docs/api/api/v1/notes/index.md +10 -0
  97. data/examples/complex-test-app/docs/api/api/v1/notes/list.md +61 -0
  98. data/examples/complex-test-app/docs/api/api/v1/orders/cancel.md +69 -0
  99. data/examples/complex-test-app/docs/api/api/v1/orders/create.md +150 -0
  100. data/examples/complex-test-app/docs/api/api/v1/orders/destroy.md +37 -0
  101. data/examples/complex-test-app/docs/api/api/v1/orders/index.md +13 -0
  102. data/examples/complex-test-app/docs/api/api/v1/orders/list.md +71 -0
  103. data/examples/complex-test-app/docs/api/api/v1/orders/show.md +83 -0
  104. data/examples/complex-test-app/docs/api/api/v1/products/index.md +11 -0
  105. data/examples/complex-test-app/docs/api/api/v1/products/list.md +83 -0
  106. data/examples/complex-test-app/docs/api/api/v1/products/search.md +88 -0
  107. data/examples/complex-test-app/docs/api/api/v1/products/show.md +71 -0
  108. data/examples/complex-test-app/docs/api/api/v1/profiles/index.md +10 -0
  109. data/examples/complex-test-app/docs/api/api/v1/profiles/show.md +61 -0
  110. data/examples/complex-test-app/docs/api/api/v1/profiles/update.md +91 -0
  111. data/examples/complex-test-app/docs/api/api/v2/products/index.md +9 -0
  112. data/examples/complex-test-app/docs/api/api/v2/products/list.md +77 -0
  113. data/examples/complex-test-app/docs/api/curl/api/v1/admin/products/create.sh +18 -0
  114. data/examples/complex-test-app/docs/api/curl/api/v1/admin/products/destroy.sh +9 -0
  115. data/examples/complex-test-app/docs/api/curl/api/v1/admin/products/list.sh +9 -0
  116. data/examples/complex-test-app/docs/api/curl/api/v1/auth/login.sh +9 -0
  117. data/examples/complex-test-app/docs/api/curl/api/v1/cart-items/create.sh +16 -0
  118. data/examples/complex-test-app/docs/api/curl/api/v1/cart-items/destroy.sh +9 -0
  119. data/examples/complex-test-app/docs/api/curl/api/v1/carts/checkout.sh +13 -0
  120. data/examples/complex-test-app/docs/api/curl/api/v1/carts/show.sh +9 -0
  121. data/examples/complex-test-app/docs/api/curl/api/v1/home/list.sh +8 -0
  122. data/examples/complex-test-app/docs/api/curl/api/v1/notes/create.sh +15 -0
  123. data/examples/complex-test-app/docs/api/curl/api/v1/notes/list.sh +9 -0
  124. data/examples/complex-test-app/docs/api/curl/api/v1/orders/cancel.sh +9 -0
  125. data/examples/complex-test-app/docs/api/curl/api/v1/orders/create.sh +29 -0
  126. data/examples/complex-test-app/docs/api/curl/api/v1/orders/destroy.sh +9 -0
  127. data/examples/complex-test-app/docs/api/curl/api/v1/orders/list.sh +9 -0
  128. data/examples/complex-test-app/docs/api/curl/api/v1/orders/show.sh +9 -0
  129. data/examples/complex-test-app/docs/api/curl/api/v1/products/list.sh +8 -0
  130. data/examples/complex-test-app/docs/api/curl/api/v1/products/search.sh +8 -0
  131. data/examples/complex-test-app/docs/api/curl/api/v1/products/show.sh +8 -0
  132. data/examples/complex-test-app/docs/api/curl/api/v1/profiles/show.sh +9 -0
  133. data/examples/complex-test-app/docs/api/curl/api/v1/profiles/update.sh +16 -0
  134. data/examples/complex-test-app/docs/api/curl/api/v2/products/list.sh +8 -0
  135. data/examples/complex-test-app/docs/api/dataset.json +5109 -0
  136. data/examples/complex-test-app/docs/api/postman/collection.json +2568 -0
  137. data/examples/complex-test-app/generate.rb +14 -0
  138. data/examples/complex-test-app/reqcord.yml +28 -0
  139. data/examples/complex-test-app/test/integration/admin_test.rb +70 -0
  140. data/examples/complex-test-app/test/integration/cart_test.rb +64 -0
  141. data/examples/complex-test-app/test/integration/home_and_auth_test.rb +53 -0
  142. data/examples/complex-test-app/test/integration/orders_test.rb +127 -0
  143. data/examples/complex-test-app/test/integration/products_test.rb +66 -0
  144. data/examples/reqcord.yml +58 -0
  145. data/examples/spec-app/.rspec +1 -0
  146. data/examples/spec-app/README.md +36 -0
  147. data/examples/spec-app/app.rb +209 -0
  148. data/examples/spec-app/docs/api/README.md +45 -0
  149. data/examples/spec-app/docs/api/api/v1/customers/create.md +95 -0
  150. data/examples/spec-app/docs/api/api/v1/customers/index.md +11 -0
  151. data/examples/spec-app/docs/api/api/v1/customers/list.md +67 -0
  152. data/examples/spec-app/docs/api/api/v1/customers/show.md +65 -0
  153. data/examples/spec-app/docs/api/api/v1/tasks/complete.md +51 -0
  154. data/examples/spec-app/docs/api/api/v1/tasks/create.md +90 -0
  155. data/examples/spec-app/docs/api/api/v1/tasks/destroy.md +35 -0
  156. data/examples/spec-app/docs/api/api/v1/tasks/index.md +14 -0
  157. data/examples/spec-app/docs/api/api/v1/tasks/list.md +65 -0
  158. data/examples/spec-app/docs/api/api/v1/tasks/show.md +65 -0
  159. data/examples/spec-app/docs/api/api/v1/tasks/update.md +74 -0
  160. data/examples/spec-app/docs/api/api/v1/users/create.md +95 -0
  161. data/examples/spec-app/docs/api/api/v1/users/index.md +11 -0
  162. data/examples/spec-app/docs/api/api/v1/users/list.md +67 -0
  163. data/examples/spec-app/docs/api/api/v1/users/show.md +65 -0
  164. data/examples/spec-app/docs/api/curl/api/v1/customers/create.sh +17 -0
  165. data/examples/spec-app/docs/api/curl/api/v1/customers/list.sh +9 -0
  166. data/examples/spec-app/docs/api/curl/api/v1/customers/show.sh +9 -0
  167. data/examples/spec-app/docs/api/curl/api/v1/tasks/complete.sh +8 -0
  168. data/examples/spec-app/docs/api/curl/api/v1/tasks/create.sh +15 -0
  169. data/examples/spec-app/docs/api/curl/api/v1/tasks/destroy.sh +8 -0
  170. data/examples/spec-app/docs/api/curl/api/v1/tasks/list.sh +8 -0
  171. data/examples/spec-app/docs/api/curl/api/v1/tasks/show.sh +8 -0
  172. data/examples/spec-app/docs/api/curl/api/v1/tasks/update.sh +14 -0
  173. data/examples/spec-app/docs/api/curl/api/v1/users/create.sh +17 -0
  174. data/examples/spec-app/docs/api/curl/api/v1/users/list.sh +9 -0
  175. data/examples/spec-app/docs/api/curl/api/v1/users/show.sh +9 -0
  176. data/examples/spec-app/docs/api/dataset.json +2402 -0
  177. data/examples/spec-app/docs/api/postman/collection.json +1290 -0
  178. data/examples/spec-app/generate.rb +14 -0
  179. data/examples/spec-app/reqcord.yml +27 -0
  180. data/examples/spec-app/spec/requests/customers_spec.rb +71 -0
  181. data/examples/spec-app/spec/requests/tasks_spec.rb +78 -0
  182. data/examples/spec-app/spec/requests/users_spec.rb +68 -0
  183. data/examples/spec-app/spec/spec_helper.rb +17 -0
  184. data/examples/test-app/README.md +57 -0
  185. data/examples/test-app/app.rb +212 -0
  186. data/examples/test-app/docs/api/README.md +45 -0
  187. data/examples/test-app/docs/api/api/v1/customers/create.md +95 -0
  188. data/examples/test-app/docs/api/api/v1/customers/index.md +11 -0
  189. data/examples/test-app/docs/api/api/v1/customers/list.md +67 -0
  190. data/examples/test-app/docs/api/api/v1/customers/show.md +65 -0
  191. data/examples/test-app/docs/api/api/v1/tasks/complete.md +51 -0
  192. data/examples/test-app/docs/api/api/v1/tasks/create.md +90 -0
  193. data/examples/test-app/docs/api/api/v1/tasks/destroy.md +35 -0
  194. data/examples/test-app/docs/api/api/v1/tasks/index.md +14 -0
  195. data/examples/test-app/docs/api/api/v1/tasks/list.md +65 -0
  196. data/examples/test-app/docs/api/api/v1/tasks/show.md +65 -0
  197. data/examples/test-app/docs/api/api/v1/tasks/update.md +74 -0
  198. data/examples/test-app/docs/api/api/v1/users/create.md +95 -0
  199. data/examples/test-app/docs/api/api/v1/users/index.md +11 -0
  200. data/examples/test-app/docs/api/api/v1/users/list.md +67 -0
  201. data/examples/test-app/docs/api/api/v1/users/show.md +65 -0
  202. data/examples/test-app/docs/api/curl/api/v1/customers/create.sh +17 -0
  203. data/examples/test-app/docs/api/curl/api/v1/customers/list.sh +9 -0
  204. data/examples/test-app/docs/api/curl/api/v1/customers/show.sh +9 -0
  205. data/examples/test-app/docs/api/curl/api/v1/tasks/complete.sh +8 -0
  206. data/examples/test-app/docs/api/curl/api/v1/tasks/create.sh +15 -0
  207. data/examples/test-app/docs/api/curl/api/v1/tasks/destroy.sh +8 -0
  208. data/examples/test-app/docs/api/curl/api/v1/tasks/list.sh +8 -0
  209. data/examples/test-app/docs/api/curl/api/v1/tasks/show.sh +8 -0
  210. data/examples/test-app/docs/api/curl/api/v1/tasks/update.sh +14 -0
  211. data/examples/test-app/docs/api/curl/api/v1/users/create.sh +17 -0
  212. data/examples/test-app/docs/api/curl/api/v1/users/list.sh +9 -0
  213. data/examples/test-app/docs/api/curl/api/v1/users/show.sh +9 -0
  214. data/examples/test-app/docs/api/dataset.json +2402 -0
  215. data/examples/test-app/docs/api/postman/collection.json +1290 -0
  216. data/examples/test-app/generate.rb +14 -0
  217. data/examples/test-app/reqcord.yml +28 -0
  218. data/examples/test-app/test/integration/customers_test.rb +72 -0
  219. data/examples/test-app/test/integration/tasks_test.rb +80 -0
  220. data/examples/test-app/test/integration/users_test.rb +72 -0
  221. data/lib/reqcord/capture/collector.rb +31 -0
  222. data/lib/reqcord/capture/integration_patch.rb +209 -0
  223. data/lib/reqcord/capture/minitest_context.rb +34 -0
  224. data/lib/reqcord/capture/rspec_context.rb +42 -0
  225. data/lib/reqcord/capture/test_context.rb +25 -0
  226. data/lib/reqcord/capture.rb +19 -0
  227. data/lib/reqcord/configuration.rb +198 -0
  228. data/lib/reqcord/dataset.rb +176 -0
  229. data/lib/reqcord/endpoint.rb +263 -0
  230. data/lib/reqcord/errors.rb +9 -0
  231. data/lib/reqcord/exporters/curl.rb +68 -0
  232. data/lib/reqcord/exporters/markdown.rb +295 -0
  233. data/lib/reqcord/exporters/postman.rb +206 -0
  234. data/lib/reqcord/exporters.rb +32 -0
  235. data/lib/reqcord/generator.rb +364 -0
  236. data/lib/reqcord/railtie.rb +51 -0
  237. data/lib/reqcord/renderers/curl.rb +56 -0
  238. data/lib/reqcord/renderers/payload.rb +69 -0
  239. data/lib/reqcord/request_example.rb +104 -0
  240. data/lib/reqcord/response_example.rb +72 -0
  241. data/lib/reqcord/route_collector.rb +242 -0
  242. data/lib/reqcord/sanitizers/sanitizer.rb +140 -0
  243. data/lib/reqcord/schema.rb +187 -0
  244. data/lib/reqcord/support.rb +58 -0
  245. data/lib/reqcord/version.rb +5 -0
  246. data/lib/reqcord.rb +78 -0
  247. data/lib/tasks/reqcord.rake +99 -0
  248. data/reqcord.gemspec +46 -0
  249. 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
+ ```