Add rswag and coverage for orders endpoint

Add coverage for core orders endpoint queries (WIP)
This commit is contained in:
Steve Roberts
2020-06-05 10:15:35 +10:00
parent 9e19d79337
commit e619ae621c
8 changed files with 384 additions and 2 deletions

View File

@@ -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'

View File

@@ -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

View 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

View 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

View File

@@ -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

View 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
View 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
View 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