mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-10 03:30:22 +00:00
Add rswag and coverage for orders endpoint
Add coverage for core orders endpoint queries (WIP)
This commit is contained in:
3
Gemfile
3
Gemfile
@@ -145,6 +145,7 @@ group :test, :development do
|
||||
gem 'letter_opener', '>= 1.4.1'
|
||||
gem 'rspec-rails', ">= 3.5.2"
|
||||
gem 'rspec-retry'
|
||||
gem 'rswag', "2.2.0"
|
||||
gem 'selenium-webdriver'
|
||||
gem 'shoulda-matchers'
|
||||
gem 'timecop'
|
||||
@@ -165,7 +166,7 @@ group :development do
|
||||
gem "newrelic_rpm", "~> 3.0"
|
||||
gem "pry", "~> 0.12.0" # pry 0.13 is not compatible with pry-byebug 3.7
|
||||
gem 'pry-byebug', '~> 3.7.0' # 3.8 requires ruby 2.4
|
||||
gem 'rubocop'
|
||||
gem 'rubocop', '0.81'
|
||||
gem 'rubocop-rails'
|
||||
gem 'spring'
|
||||
gem 'spring-commands-rspec'
|
||||
|
||||
18
Gemfile.lock
18
Gemfile.lock
@@ -434,6 +434,8 @@ GEM
|
||||
jquery-ui-rails (4.2.1)
|
||||
railties (>= 3.2.16)
|
||||
json (1.8.6)
|
||||
json-schema (2.8.1)
|
||||
addressable (>= 2.4)
|
||||
json_spec (1.1.5)
|
||||
multi_json (~> 1.0)
|
||||
rspec (>= 2.0, < 4.0)
|
||||
@@ -590,6 +592,19 @@ GEM
|
||||
rspec-retry (0.6.2)
|
||||
rspec-core (> 3.3)
|
||||
rspec-support (3.9.2)
|
||||
rswag (2.2.0)
|
||||
rswag-api (= 2.2.0)
|
||||
rswag-specs (= 2.2.0)
|
||||
rswag-ui (= 2.2.0)
|
||||
rswag-api (2.2.0)
|
||||
railties (>= 3.1, < 6.1)
|
||||
rswag-specs (2.2.0)
|
||||
activesupport (>= 3.1, < 6.1)
|
||||
json-schema (~> 2.2)
|
||||
railties (>= 3.1, < 6.1)
|
||||
rswag-ui (2.2.0)
|
||||
actionpack (>= 3.1, < 6.1)
|
||||
railties (>= 3.1, < 6.1)
|
||||
rubocop (0.81.0)
|
||||
jaro_winkler (~> 1.5.1)
|
||||
parallel (~> 1.10)
|
||||
@@ -780,7 +795,8 @@ DEPENDENCIES
|
||||
roo (~> 2.8.3)
|
||||
rspec-rails (>= 3.5.2)
|
||||
rspec-retry
|
||||
rubocop
|
||||
rswag (= 2.2.0)
|
||||
rubocop (= 0.81)
|
||||
rubocop-rails
|
||||
sass
|
||||
sass-rails
|
||||
|
||||
14
config/initializers/rswag-ui.rb
Normal file
14
config/initializers/rswag-ui.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
Rswag::Ui.configure do |c|
|
||||
|
||||
# List the Swagger endpoints that you want to be documented through the swagger-ui
|
||||
# The first parameter is the path (absolute or relative to the UI host) to the corresponding
|
||||
# endpoint and the second is a title that will be displayed in the document selector
|
||||
# NOTE: If you're using rspec-api to expose Swagger files (under swagger_root) as JSON or YAML endpoints,
|
||||
# then the list below should correspond to the relative paths for those endpoints
|
||||
|
||||
c.swagger_endpoint '/api-docs/v1/swagger.yaml', 'API V1 Docs'
|
||||
|
||||
# Add Basic Auth in case your API is private
|
||||
# c.basic_auth_enabled = true
|
||||
# c.basic_auth_credentials 'username', 'password'
|
||||
end
|
||||
14
config/initializers/rswag_api.rb
Normal file
14
config/initializers/rswag_api.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
Rswag::Api.configure do |c|
|
||||
|
||||
# Specify a root folder where Swagger JSON files are located
|
||||
# This is used by the Swagger middleware to serve requests for API descriptions
|
||||
# NOTE: If you're using rswag-specs to generate Swagger, you'll need to ensure
|
||||
# that it's configured to generate files in the same folder
|
||||
c.swagger_root = Rails.root.to_s + '/swagger'
|
||||
|
||||
# Inject a lamda function to alter the returned Swagger prior to serialization
|
||||
# The function will have access to the rack env for the current request
|
||||
# For example, you could leverage this to dynamically assign the "host" property
|
||||
#
|
||||
#c.swagger_filter = lambda { |swagger, env| swagger['host'] = env['HTTP_HOST'] }
|
||||
end
|
||||
@@ -1,4 +1,8 @@
|
||||
Openfoodnetwork::Application.routes.draw do
|
||||
mount Rswag::Ui::Engine => '/api-docs'
|
||||
|
||||
mount Rswag::Api::Engine => '/api-docs'
|
||||
|
||||
root :to => 'home#index'
|
||||
|
||||
# Redirects from old URLs avoid server errors and helps search engines
|
||||
|
||||
130
spec/requests/api/orders_spec.rb
Normal file
130
spec/requests/api/orders_spec.rb
Normal file
@@ -0,0 +1,130 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'swagger_helper'
|
||||
|
||||
describe 'api/orders', type: :request do
|
||||
path '/api/orders' do
|
||||
get('list orders') do
|
||||
tags 'Orders'
|
||||
# type should be replaced with swagger 3.01 valid schema: {type: string} when rswag #317 is resoved:
|
||||
# https://github.com/rswag/rswag/pull/319
|
||||
parameter name: 'X-Spree-Token', in: :header, type: :string
|
||||
parameter name: 'q[distributor_id_eq]', in: :query, type: :string, required: false, description: "Query orders for a specific distributor id."
|
||||
parameter name: 'q[completed_at_gt]', in: :query, type: :string, required: false, description: "Query orders completed after a date."
|
||||
parameter name: 'q[completed_at_lt]', in: :query, type: :string, required: false, description: "Query orders completed before a date."
|
||||
parameter name: 'q[state_eq]', in: :query, type: :string, required: false, description: "Query orders by order state, eg 'cart', 'complete'."
|
||||
parameter name: 'q[payment_state_eq]', in: :query, type: :string, required: false, description: "Query orders by order payment_state, eg 'balance_due', 'paid', 'failed'."
|
||||
parameter name: 'q[email_cont]', in: :query, type: :string, required: false, description: "Query orders where the order email contains a string."
|
||||
parameter name: 'q[order_cycle_id_eq]', in: :query, type: :string, required: false, description: "Query orders for a specific order_cycle id."
|
||||
|
||||
response(200, 'get orders') do
|
||||
# Adds model metadata for Swagger UI. Ideally we'd be able to just add:
|
||||
# schema '$ref' => '#/components/schemas/Order_Concise'
|
||||
# Which would also validate the response in the test, this is an open
|
||||
# issue with rswag: https://github.com/rswag/rswag/issues/268
|
||||
metadata[:response][:content] = { "application/json": {
|
||||
schema: {'$ref' => '#/components/schemas/Order_Concise'}
|
||||
}
|
||||
}
|
||||
context "when there are four orders with different properties set" do
|
||||
let(:order_dist_1) { create(:order_with_distributor, email: "specific_name@example.com") }
|
||||
let(:order_dist_2) { create(:order_with_distributor) }
|
||||
let(:order_dist_1_complete) { create(:order, distributor: order_dist_1.distributor, state: 'complete', completed_at: Time.zone.today - 7.days) }
|
||||
let(:order_dist_1_credit_owed) { create(:order, distributor: order_dist_1.distributor, state: 'complete', payment_state: 'credit_owed', completed_at: Time.zone.today) }
|
||||
|
||||
let(:user) { order_dist_1.distributor.owner }
|
||||
let(:'X-Spree-Token') do
|
||||
user.generate_spree_api_key!
|
||||
user.spree_api_key
|
||||
end
|
||||
|
||||
context "and there are no query parameters" do
|
||||
|
||||
run_test! do |response|
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
data = JSON.parse(response.body)
|
||||
orders = data["orders"]
|
||||
expect(orders.size).to eq 4
|
||||
end
|
||||
end
|
||||
|
||||
context "and queried by distributor id" do
|
||||
let(:'q[distributor_id_eq]') { order_dist_2.distributor.id }
|
||||
|
||||
run_test! do |response|
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
data = JSON.parse(response.body)
|
||||
orders = data["orders"]
|
||||
expect(orders.size).to eq 1
|
||||
expect(orders.first["id"]).to eq order_dist_2.id
|
||||
end
|
||||
end
|
||||
|
||||
context "and queried within a date range" do
|
||||
let(:'q[completed_at_gt]') { Time.zone.today - 7.days - 1.second }
|
||||
let(:'q[completed_at_lt]') { Time.zone.today - 6.days }
|
||||
|
||||
run_test! do |response|
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
data = JSON.parse(response.body)
|
||||
orders = data["orders"]
|
||||
expect(orders.size).to eq 1
|
||||
expect(orders.first["id"]).to eq order_dist_1_complete.id
|
||||
end
|
||||
end
|
||||
|
||||
context "and queried by complete state" do
|
||||
let(:'q[state_eq]') { "complete" }
|
||||
run_test! do |response|
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
data = JSON.parse(response.body)
|
||||
orders = data["orders"]
|
||||
expect(orders.size).to eq 1
|
||||
expect(orders.first["id"]).to eq order_dist_1_complete.id
|
||||
end
|
||||
end
|
||||
|
||||
context "and queried by credit_owed payment_state" do
|
||||
let(:'q[payment_state_eq]') { "credit_owed" }
|
||||
run_test! do |response|
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
data = JSON.parse(response.body)
|
||||
orders = data["orders"]
|
||||
expect(orders.size).to eq 1
|
||||
expect(orders.first["id"]).to eq order_dist_1_credit_owed.id
|
||||
end
|
||||
end
|
||||
|
||||
context "and queried by buyer email contains a specific string" do
|
||||
let(:'q[email_cont]') { order_dist_1.email.split("@").first }
|
||||
run_test! do |response|
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
data = JSON.parse(response.body)
|
||||
orders = data["orders"]
|
||||
expect(orders.size).to eq 1
|
||||
expect(orders.first["id"]).to eq order_dist_1_credit_owed.id
|
||||
end
|
||||
end
|
||||
|
||||
context "and queried by a specific order_cycle" do
|
||||
let(:'q[order_cycle_id_eq]') { order_dist_2.order_cycle.id }
|
||||
run_test! do |response|
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
data = JSON.parse(response.body)
|
||||
orders = data["orders"]
|
||||
expect(orders.size).to eq 1
|
||||
expect(orders.first["id"]).to eq order_dist_2.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
72
spec/swagger_helper.rb
Normal file
72
spec/swagger_helper.rb
Normal file
@@ -0,0 +1,72 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.swagger_root = Rails.root.join('swagger').to_s
|
||||
config.swagger_docs = {
|
||||
'v1/swagger.yaml' => {
|
||||
openapi: '3.0.1',
|
||||
info: {
|
||||
title: 'The Open Food Network',
|
||||
description: 'Some endpoints are public and require no authorization; others require authorization. Talk to us to get your credentials set up. Check out our repo! https://github.com/openfoodfoundation/openfoodnetwork',
|
||||
version: '0.1',
|
||||
},
|
||||
components: {
|
||||
securitySchemes: {
|
||||
api_key: {
|
||||
type: :apiKey,
|
||||
name: 'X-Spree-Token',
|
||||
in: :header
|
||||
}
|
||||
},
|
||||
schemas: {
|
||||
Order_Concise: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'integer' },
|
||||
number: { type: 'string' },
|
||||
full_name: { type: 'string' },
|
||||
email: { type: 'string' },
|
||||
phone: { type: 'string' },
|
||||
completed_at: { type: 'string' },
|
||||
display_total: { type: 'string' },
|
||||
show_path: { type: 'string' },
|
||||
edit_path: { type: 'string' },
|
||||
state: { type: 'string' },
|
||||
payment_state: { type: 'string' },
|
||||
shipment_state: { type: 'string' },
|
||||
payments_path: { type: 'string' },
|
||||
shipments_path: { type: 'string' },
|
||||
ship_path: { type: 'string' },
|
||||
ready_to_ship: { type: 'string' },
|
||||
created_at: { type: 'string' },
|
||||
distributor_name: { type: 'string' },
|
||||
special_instructions: { type: 'string' },
|
||||
payment_capture_path: { type: 'string' },
|
||||
distributor: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'integer' }
|
||||
}
|
||||
},
|
||||
order_cycle: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'integer' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
paths: {},
|
||||
servers: [
|
||||
{
|
||||
url: 'https://staging.katuma.org/api'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
config.swagger_format = :yaml
|
||||
end
|
||||
131
swagger/v1/swagger.yaml
Normal file
131
swagger/v1/swagger.yaml
Normal file
@@ -0,0 +1,131 @@
|
||||
---
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: The Open Food Network
|
||||
description: Some endpoints are public and require no authorization; others require
|
||||
authorization. Talk to us to get your credentials set up. Check out our repo!
|
||||
https://github.com/openfoodfoundation/openfoodnetwork
|
||||
version: '0.1'
|
||||
components:
|
||||
securitySchemes:
|
||||
api_key:
|
||||
type: apiKey
|
||||
name: X-Spree-Token
|
||||
in: header
|
||||
schemas:
|
||||
Order_Concise:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
number:
|
||||
type: string
|
||||
full_name:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
phone:
|
||||
type: string
|
||||
completed_at:
|
||||
type: string
|
||||
display_total:
|
||||
type: string
|
||||
show_path:
|
||||
type: string
|
||||
edit_path:
|
||||
type: string
|
||||
state:
|
||||
type: string
|
||||
payment_state:
|
||||
type: string
|
||||
shipment_state:
|
||||
type: string
|
||||
payments_path:
|
||||
type: string
|
||||
shipments_path:
|
||||
type: string
|
||||
ship_path:
|
||||
type: string
|
||||
ready_to_ship:
|
||||
type: string
|
||||
created_at:
|
||||
type: string
|
||||
distributor_name:
|
||||
type: string
|
||||
special_instructions:
|
||||
type: string
|
||||
payment_capture_path:
|
||||
type: string
|
||||
distributor:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
order_cycle:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
paths:
|
||||
"/api/orders":
|
||||
get:
|
||||
summary: list orders
|
||||
tags:
|
||||
- Orders
|
||||
parameters:
|
||||
- name: X-Spree-Token
|
||||
in: header
|
||||
schema:
|
||||
type: string
|
||||
- name: q[distributor_id_eq]
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
style: deepObject
|
||||
description: Query orders for a specific distributor id.
|
||||
- name: q[completed_at_gt]
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
style: deepObject
|
||||
description: Query orders completed after a date.
|
||||
- name: q[completed_at_lt]
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
style: deepObject
|
||||
description: Query orders completed before a date.
|
||||
- name: q[state_eq]
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
style: deepObject
|
||||
description: Query orders by order state, eg 'cart', 'complete'.
|
||||
- name: q[payment_state_eq]
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
style: deepObject
|
||||
description: Query orders by order payment_state, eg 'balance_due', 'paid',
|
||||
'failed'.
|
||||
- name: q[email_cont]
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
style: deepObject
|
||||
description: Query orders where the order email contains a string.
|
||||
- name: q[order_cycle_id_eq]
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
style: deepObject
|
||||
description: Query orders for a specific order_cycle id.
|
||||
responses:
|
||||
'200':
|
||||
description: get orders
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
"$ref": "#/components/schemas/Order_Concise"
|
||||
servers:
|
||||
- url: https://staging.katuma.org/api
|
||||
Reference in New Issue
Block a user