bug: parameter allowEmptyValue + required interactions (via #5142)
* add failing tests
* standardize parameter keying
* validateParam test migrations
* migrate test cases to new pattern
* disambiguate name/in ordering in `body.body` test cases
* `name+in`=> `{in}.{name}`
* consider allowEmptyValue parameter inclusion in runtime validation
* use config object for all validateParam options
* drop isXml flag from validateParams
This commit is contained in:
@@ -5,7 +5,7 @@ import serializeError from "serialize-error"
|
|||||||
import isString from "lodash/isString"
|
import isString from "lodash/isString"
|
||||||
import debounce from "lodash/debounce"
|
import debounce from "lodash/debounce"
|
||||||
import set from "lodash/set"
|
import set from "lodash/set"
|
||||||
import { isJSONObject } from "core/utils"
|
import { isJSONObject, paramToValue } from "core/utils"
|
||||||
|
|
||||||
// Actions conform to FSA (flux-standard-actions)
|
// Actions conform to FSA (flux-standard-actions)
|
||||||
// {type: string,payload: Any|Error, meta: obj, error: bool}
|
// {type: string,payload: Any|Error, meta: obj, error: bool}
|
||||||
@@ -345,19 +345,19 @@ export const executeRequest = (req) =>
|
|||||||
|
|
||||||
// ensure that explicitly-included params are in the request
|
// ensure that explicitly-included params are in the request
|
||||||
|
|
||||||
if(op && op.parameters && op.parameters.length) {
|
if (operation && operation.get("parameters")) {
|
||||||
op.parameters
|
operation.get("parameters")
|
||||||
.filter(param => param && param.allowEmptyValue === true)
|
.filter(param => param && param.get("allowEmptyValue") === true)
|
||||||
.forEach(param => {
|
.forEach(param => {
|
||||||
if (specSelectors.parameterInclusionSettingFor([pathName, method], param.name, param.in)) {
|
if (specSelectors.parameterInclusionSettingFor([pathName, method], param.get("name"), param.get("in"))) {
|
||||||
req.parameters = req.parameters || {}
|
req.parameters = req.parameters || {}
|
||||||
const paramValue = req.parameters[param.name]
|
const paramValue = paramToValue(param, req.parameters)
|
||||||
|
|
||||||
// if the value is falsy or an empty Immutable iterable...
|
// if the value is falsy or an empty Immutable iterable...
|
||||||
if(!paramValue || (paramValue && paramValue.size === 0)) {
|
if(!paramValue || (paramValue && paramValue.size === 0)) {
|
||||||
// set it to empty string, so Swagger Client will treat it as
|
// set it to empty string, so Swagger Client will treat it as
|
||||||
// present but empty.
|
// present but empty.
|
||||||
req.parameters[param.name] = ""
|
req.parameters[param.get("name")] = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { fromJS, List } from "immutable"
|
import { fromJS, List } from "immutable"
|
||||||
import { fromJSOrdered, validateParam } from "core/utils"
|
import { fromJSOrdered, validateParam, paramToValue } from "core/utils"
|
||||||
import win from "../../window"
|
import win from "../../window"
|
||||||
|
|
||||||
// selector-in-reducer is suboptimal, but `operationWithMeta` is more of a helper
|
// selector-in-reducer is suboptimal, but `operationWithMeta` is more of a helper
|
||||||
import {
|
import {
|
||||||
operationWithMeta
|
specJsonWithResolvedSubtrees,
|
||||||
|
parameterValues,
|
||||||
|
parameterInclusionSettingFor,
|
||||||
} from "./selectors"
|
} from "./selectors"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -25,6 +27,7 @@ import {
|
|||||||
CLEAR_VALIDATE_PARAMS,
|
CLEAR_VALIDATE_PARAMS,
|
||||||
SET_SCHEME
|
SET_SCHEME
|
||||||
} from "./actions"
|
} from "./actions"
|
||||||
|
import { paramToIdentifier } from "../../utils"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
@@ -54,14 +57,7 @@ export default {
|
|||||||
[UPDATE_PARAM]: ( state, {payload} ) => {
|
[UPDATE_PARAM]: ( state, {payload} ) => {
|
||||||
let { path: pathMethod, paramName, paramIn, param, value, isXml } = payload
|
let { path: pathMethod, paramName, paramIn, param, value, isXml } = payload
|
||||||
|
|
||||||
let paramKey
|
let paramKey = param ? paramToIdentifier(param) : `${paramIn}.${paramName}`
|
||||||
|
|
||||||
// `hashCode` is an Immutable.js Map method
|
|
||||||
if(param && param.hashCode && !paramIn && !paramName) {
|
|
||||||
paramKey = `${param.get("name")}.${param.get("in")}.hash-${param.hashCode()}`
|
|
||||||
} else {
|
|
||||||
paramKey = `${paramName}.${paramIn}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const valueKey = isXml ? "value_xml" : "value"
|
const valueKey = isXml ? "value_xml" : "value"
|
||||||
|
|
||||||
@@ -79,7 +75,7 @@ export default {
|
|||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
const paramKey = `${paramName}.${paramIn}`
|
const paramKey = `${paramIn}.${paramName}`
|
||||||
|
|
||||||
return state.setIn(
|
return state.setIn(
|
||||||
["meta", "paths", ...pathMethod, "parameter_inclusions", paramKey],
|
["meta", "paths", ...pathMethod, "parameter_inclusions", paramKey],
|
||||||
@@ -88,15 +84,18 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
[VALIDATE_PARAMS]: ( state, { payload: { pathMethod, isOAS3 } } ) => {
|
[VALIDATE_PARAMS]: ( state, { payload: { pathMethod, isOAS3 } } ) => {
|
||||||
let meta = state.getIn( [ "meta", "paths", ...pathMethod ], fromJS({}) )
|
const op = specJsonWithResolvedSubtrees(state).getIn(["paths", ...pathMethod])
|
||||||
let isXml = /xml/i.test(meta.get("consumes_value"))
|
const paramValues = parameterValues(state, pathMethod).toJS()
|
||||||
|
|
||||||
const op = operationWithMeta(state, ...pathMethod)
|
|
||||||
|
|
||||||
return state.updateIn(["meta", "paths", ...pathMethod, "parameters"], fromJS({}), paramMeta => {
|
return state.updateIn(["meta", "paths", ...pathMethod, "parameters"], fromJS({}), paramMeta => {
|
||||||
return op.get("parameters", List()).reduce((res, param) => {
|
return op.get("parameters", List()).reduce((res, param) => {
|
||||||
const errors = validateParam(param, isXml, isOAS3)
|
const value = paramToValue(param, paramValues)
|
||||||
return res.setIn([`${param.get("name")}.${param.get("in")}`, "errors"], fromJS(errors))
|
const isEmptyValueIncluded = parameterInclusionSettingFor(state, pathMethod, param.get("name"), param.get("in"))
|
||||||
|
const errors = validateParam(param, value, {
|
||||||
|
bypassRequiredCheck: isEmptyValueIncluded,
|
||||||
|
isOAS3,
|
||||||
|
})
|
||||||
|
return res.setIn([paramToIdentifier(param), "errors"], fromJS(errors))
|
||||||
}, paramMeta)
|
}, paramMeta)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { createSelector } from "reselect"
|
import { createSelector } from "reselect"
|
||||||
import { sorters } from "core/utils"
|
import { sorters } from "core/utils"
|
||||||
import { fromJS, Set, Map, OrderedMap, List } from "immutable"
|
import { fromJS, Set, Map, OrderedMap, List } from "immutable"
|
||||||
|
import { paramToIdentifier } from "../../utils"
|
||||||
|
|
||||||
const DEFAULT_TAG = "default"
|
const DEFAULT_TAG = "default"
|
||||||
|
|
||||||
@@ -302,11 +303,11 @@ export const parameterWithMetaByIdentity = (state, pathMethod, param) => {
|
|||||||
const metaParams = state.getIn(["meta", "paths", ...pathMethod, "parameters"], OrderedMap())
|
const metaParams = state.getIn(["meta", "paths", ...pathMethod, "parameters"], OrderedMap())
|
||||||
|
|
||||||
const mergedParams = opParams.map((currentParam) => {
|
const mergedParams = opParams.map((currentParam) => {
|
||||||
const nameInKeyedMeta = metaParams.get(`${param.get("name")}.${param.get("in")}`)
|
const inNameKeyedMeta = metaParams.get(`${param.get("in")}.${param.get("name")}`)
|
||||||
const hashKeyedMeta = metaParams.get(`${param.get("name")}.${param.get("in")}.hash-${param.hashCode()}`)
|
const hashKeyedMeta = metaParams.get(`${param.get("in")}.${param.get("name")}.hash-${param.hashCode()}`)
|
||||||
return OrderedMap().merge(
|
return OrderedMap().merge(
|
||||||
currentParam,
|
currentParam,
|
||||||
nameInKeyedMeta,
|
inNameKeyedMeta,
|
||||||
hashKeyedMeta
|
hashKeyedMeta
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -315,7 +316,7 @@ export const parameterWithMetaByIdentity = (state, pathMethod, param) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const parameterInclusionSettingFor = (state, pathMethod, paramName, paramIn) => {
|
export const parameterInclusionSettingFor = (state, pathMethod, paramName, paramIn) => {
|
||||||
const paramKey = `${paramName}.${paramIn}`
|
const paramKey = `${paramIn}.${paramName}`
|
||||||
return state.getIn(["meta", "paths", ...pathMethod, "parameter_inclusions", paramKey], false)
|
return state.getIn(["meta", "paths", ...pathMethod, "parameter_inclusions", paramKey], false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,7 +365,7 @@ export function parameterValues(state, pathMethod, isXml) {
|
|||||||
let paramValues = operationWithMeta(state, ...pathMethod).get("parameters", List())
|
let paramValues = operationWithMeta(state, ...pathMethod).get("parameters", List())
|
||||||
return paramValues.reduce( (hash, p) => {
|
return paramValues.reduce( (hash, p) => {
|
||||||
let value = isXml && p.get("in") === "body" ? p.get("value_xml") : p.get("value")
|
let value = isXml && p.get("in") === "body" ? p.get("value_xml") : p.get("value")
|
||||||
return hash.set(`${p.get("in")}.${p.get("name")}`, value)
|
return hash.set(paramToIdentifier(p, { allowHashes: false }), value)
|
||||||
}, fromJS({}))
|
}, fromJS({}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -484,9 +484,8 @@ export const validatePattern = (val, rxPattern) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// validation of parameters before execute
|
// validation of parameters before execute
|
||||||
export const validateParam = (param, isXml, isOAS3 = false) => {
|
export const validateParam = (param, value, { isOAS3 = false, bypassRequiredCheck = false } = {}) => {
|
||||||
let errors = []
|
let errors = []
|
||||||
let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value")
|
|
||||||
let required = param.get("required")
|
let required = param.get("required")
|
||||||
|
|
||||||
let paramDetails = isOAS3 ? param.get("schema") : param
|
let paramDetails = isOAS3 ? param.get("schema") : param
|
||||||
@@ -501,7 +500,6 @@ export const validateParam = (param, isXml, isOAS3 = false) => {
|
|||||||
let minLength = paramDetails.get("minLength")
|
let minLength = paramDetails.get("minLength")
|
||||||
let pattern = paramDetails.get("pattern")
|
let pattern = paramDetails.get("pattern")
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If the parameter is required OR the parameter has a value (meaning optional, but filled in)
|
If the parameter is required OR the parameter has a value (meaning optional, but filled in)
|
||||||
then we should do our validation routine.
|
then we should do our validation routine.
|
||||||
@@ -540,7 +538,7 @@ export const validateParam = (param, isXml, isOAS3 = false) => {
|
|||||||
|
|
||||||
const passedAnyCheck = allChecks.some(v => !!v)
|
const passedAnyCheck = allChecks.some(v => !!v)
|
||||||
|
|
||||||
if ( required && !passedAnyCheck ) {
|
if (required && !passedAnyCheck && !bypassRequiredCheck ) {
|
||||||
errors.push("Required field is not provided")
|
errors.push("Required field is not provided")
|
||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
@@ -805,3 +803,43 @@ export function numberToString(thing) {
|
|||||||
|
|
||||||
return thing
|
return thing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function paramToIdentifier(param, { returnAll = false, allowHashes = true } = {}) {
|
||||||
|
if(!Im.Map.isMap(param)) {
|
||||||
|
throw new Error("paramToIdentifier: received a non-Im.Map parameter as input")
|
||||||
|
}
|
||||||
|
const paramName = param.get("name")
|
||||||
|
const paramIn = param.get("in")
|
||||||
|
|
||||||
|
let generatedIdentifiers = []
|
||||||
|
|
||||||
|
// Generate identifiers in order of most to least specificity
|
||||||
|
|
||||||
|
if (param && param.hashCode && paramIn && paramName && allowHashes) {
|
||||||
|
generatedIdentifiers.push(`${paramIn}.${paramName}.hash-${param.hashCode()}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(paramIn && paramName) {
|
||||||
|
generatedIdentifiers.push(`${paramIn}.${paramName}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
generatedIdentifiers.push(paramName)
|
||||||
|
|
||||||
|
// Return the most preferred identifier, or all if requested
|
||||||
|
|
||||||
|
return returnAll ? generatedIdentifiers : (generatedIdentifiers[0] || "")
|
||||||
|
}
|
||||||
|
|
||||||
|
export function paramToValue(param, paramValues) {
|
||||||
|
const allIdentifiers = paramToIdentifier(param, { returnAll: true })
|
||||||
|
|
||||||
|
// Map identifiers to values in the provided value hash, filter undefined values,
|
||||||
|
// and return the first value found
|
||||||
|
const values = allIdentifiers
|
||||||
|
.map(id => {
|
||||||
|
return paramValues[id]
|
||||||
|
})
|
||||||
|
.filter(value => value !== undefined)
|
||||||
|
|
||||||
|
return values[0]
|
||||||
|
}
|
||||||
@@ -130,7 +130,7 @@ describe("spec plugin - reducer", function(){
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe("SPEC_UPDATE_PARAM", function() {
|
describe("SPEC_UPDATE_PARAM", function() {
|
||||||
it("should store parameter values by name+in", () => {
|
it("should store parameter values by {in}.{name}", () => {
|
||||||
const updateParam = reducer["spec_update_param"]
|
const updateParam = reducer["spec_update_param"]
|
||||||
|
|
||||||
const path = "/pet/post"
|
const path = "/pet/post"
|
||||||
@@ -140,14 +140,14 @@ describe("spec plugin - reducer", function(){
|
|||||||
const result = updateParam(state, {
|
const result = updateParam(state, {
|
||||||
payload: {
|
payload: {
|
||||||
path: [path, method],
|
path: [path, method],
|
||||||
paramName: "body",
|
paramName: "myBody",
|
||||||
paramIn: "body",
|
paramIn: "body",
|
||||||
value: `{ "a": 123 }`,
|
value: `{ "a": 123 }`,
|
||||||
isXml: false
|
isXml: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const response = result.getIn(["meta", "paths", path, method, "parameters", "body.body", "value"])
|
const response = result.getIn(["meta", "paths", path, method, "parameters", "body.myBody", "value"])
|
||||||
expect(response).toEqual(`{ "a": 123 }`)
|
expect(response).toEqual(`{ "a": 123 }`)
|
||||||
})
|
})
|
||||||
it("should store parameter values by identity", () => {
|
it("should store parameter values by identity", () => {
|
||||||
@@ -157,7 +157,7 @@ describe("spec plugin - reducer", function(){
|
|||||||
const method = "POST"
|
const method = "POST"
|
||||||
|
|
||||||
const param = fromJS({
|
const param = fromJS({
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body",
|
in: "body",
|
||||||
schema: {
|
schema: {
|
||||||
type: "string"
|
type: "string"
|
||||||
@@ -174,12 +174,12 @@ describe("spec plugin - reducer", function(){
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const value = result.getIn(["meta", "paths", path, method, "parameters", `body.body.hash-${param.hashCode()}`, "value"])
|
const value = result.getIn(["meta", "paths", path, method, "parameters", `body.myBody.hash-${param.hashCode()}`, "value"])
|
||||||
expect(value).toEqual(`{ "a": 123 }`)
|
expect(value).toEqual(`{ "a": 123 }`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe("SPEC_UPDATE_EMPTY_PARAM_INCLUSION", function() {
|
describe("SPEC_UPDATE_EMPTY_PARAM_INCLUSION", function() {
|
||||||
it("should store parameter values by name+in", () => {
|
it("should store parameter values by {in}.{name}", () => {
|
||||||
const updateParam = reducer["spec_update_empty_param_inclusion"]
|
const updateParam = reducer["spec_update_empty_param_inclusion"]
|
||||||
|
|
||||||
const path = "/pet/post"
|
const path = "/pet/post"
|
||||||
@@ -196,7 +196,7 @@ describe("spec plugin - reducer", function(){
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const response = result.getIn(["meta", "paths", path, method, "parameter_inclusions", "param.query"])
|
const response = result.getIn(["meta", "paths", path, method, "parameter_inclusions", "query.param"])
|
||||||
expect(response).toEqual(true)
|
expect(response).toEqual(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -497,7 +497,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("operationWithMeta", function() {
|
describe("operationWithMeta", function() {
|
||||||
it("should support merging in name+in keyed param metadata", function () {
|
it("should support merging in {in}.{name} keyed param metadata", function () {
|
||||||
const state = fromJS({
|
const state = fromJS({
|
||||||
json: {
|
json: {
|
||||||
paths: {
|
paths: {
|
||||||
@@ -505,7 +505,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
"get": {
|
"get": {
|
||||||
parameters: [
|
parameters: [
|
||||||
{
|
{
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body"
|
in: "body"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -518,7 +518,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
parameters: {
|
parameters: {
|
||||||
"body.body": {
|
"body.myBody": {
|
||||||
value: "abc123"
|
value: "abc123"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -533,7 +533,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
expect(result.toJS()).toEqual({
|
expect(result.toJS()).toEqual({
|
||||||
parameters: [
|
parameters: [
|
||||||
{
|
{
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body",
|
in: "body",
|
||||||
value: "abc123"
|
value: "abc123"
|
||||||
}
|
}
|
||||||
@@ -542,7 +542,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
})
|
})
|
||||||
it("should support merging in hash-keyed param metadata", function () {
|
it("should support merging in hash-keyed param metadata", function () {
|
||||||
const bodyParam = fromJS({
|
const bodyParam = fromJS({
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body"
|
in: "body"
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -563,7 +563,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
parameters: {
|
parameters: {
|
||||||
[`body.body.hash-${bodyParam.hashCode()}`]: {
|
[`body.myBody.hash-${bodyParam.hashCode()}`]: {
|
||||||
value: "abc123"
|
value: "abc123"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -578,7 +578,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
expect(result.toJS()).toEqual({
|
expect(result.toJS()).toEqual({
|
||||||
parameters: [
|
parameters: [
|
||||||
{
|
{
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body",
|
in: "body",
|
||||||
value: "abc123"
|
value: "abc123"
|
||||||
}
|
}
|
||||||
@@ -587,7 +587,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe("parameterWithMeta", function() {
|
describe("parameterWithMeta", function() {
|
||||||
it("should support merging in name+in keyed param metadata", function () {
|
it("should support merging in {in}.{name} keyed param metadata", function () {
|
||||||
const state = fromJS({
|
const state = fromJS({
|
||||||
json: {
|
json: {
|
||||||
paths: {
|
paths: {
|
||||||
@@ -595,7 +595,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
"get": {
|
"get": {
|
||||||
parameters: [
|
parameters: [
|
||||||
{
|
{
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body"
|
in: "body"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -608,7 +608,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
parameters: {
|
parameters: {
|
||||||
"body.body": {
|
"body.myBody": {
|
||||||
value: "abc123"
|
value: "abc123"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -618,17 +618,17 @@ describe("spec plugin - selectors", function(){
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = parameterWithMeta(state, ["/", "get"], "body", "body")
|
const result = parameterWithMeta(state, ["/", "get"], "myBody", "body")
|
||||||
|
|
||||||
expect(result.toJS()).toEqual({
|
expect(result.toJS()).toEqual({
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body",
|
in: "body",
|
||||||
value: "abc123"
|
value: "abc123"
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
it("should give best-effort when encountering hash-keyed param metadata", function () {
|
it("should give best-effort when encountering hash-keyed param metadata", function () {
|
||||||
const bodyParam = fromJS({
|
const bodyParam = fromJS({
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body"
|
in: "body"
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -649,7 +649,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
parameters: {
|
parameters: {
|
||||||
[`body.body.hash-${bodyParam.hashCode()}`]: {
|
[`body.myBody.hash-${bodyParam.hashCode()}`]: {
|
||||||
value: "abc123"
|
value: "abc123"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -659,10 +659,10 @@ describe("spec plugin - selectors", function(){
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = parameterWithMeta(state, ["/", "get"], "body", "body")
|
const result = parameterWithMeta(state, ["/", "get"], "myBody", "body")
|
||||||
|
|
||||||
expect(result.toJS()).toEqual({
|
expect(result.toJS()).toEqual({
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body",
|
in: "body",
|
||||||
value: "abc123"
|
value: "abc123"
|
||||||
})
|
})
|
||||||
@@ -670,9 +670,9 @@ describe("spec plugin - selectors", function(){
|
|||||||
|
|
||||||
})
|
})
|
||||||
describe("parameterWithMetaByIdentity", function() {
|
describe("parameterWithMetaByIdentity", function() {
|
||||||
it("should support merging in name+in keyed param metadata", function () {
|
it("should support merging in {in}.{name} keyed param metadata", function () {
|
||||||
const bodyParam = fromJS({
|
const bodyParam = fromJS({
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body"
|
in: "body"
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -691,7 +691,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
parameters: {
|
parameters: {
|
||||||
"body.body": {
|
"body.myBody": {
|
||||||
value: "abc123"
|
value: "abc123"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -704,14 +704,14 @@ describe("spec plugin - selectors", function(){
|
|||||||
const result = parameterWithMetaByIdentity(state, ["/", "get"], bodyParam)
|
const result = parameterWithMetaByIdentity(state, ["/", "get"], bodyParam)
|
||||||
|
|
||||||
expect(result.toJS()).toEqual({
|
expect(result.toJS()).toEqual({
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body",
|
in: "body",
|
||||||
value: "abc123"
|
value: "abc123"
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
it("should support merging in hash-keyed param metadata", function () {
|
it("should support merging in hash-keyed param metadata", function () {
|
||||||
const bodyParam = fromJS({
|
const bodyParam = fromJS({
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body"
|
in: "body"
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -732,7 +732,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
parameters: {
|
parameters: {
|
||||||
[`body.body.hash-${bodyParam.hashCode()}`]: {
|
[`body.myBody.hash-${bodyParam.hashCode()}`]: {
|
||||||
value: "abc123"
|
value: "abc123"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -745,14 +745,14 @@ describe("spec plugin - selectors", function(){
|
|||||||
const result = parameterWithMetaByIdentity(state, ["/", "get"], bodyParam)
|
const result = parameterWithMetaByIdentity(state, ["/", "get"], bodyParam)
|
||||||
|
|
||||||
expect(result.toJS()).toEqual({
|
expect(result.toJS()).toEqual({
|
||||||
name: "body",
|
name: "myBody",
|
||||||
in: "body",
|
in: "body",
|
||||||
value: "abc123"
|
value: "abc123"
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe("parameterInclusionSettingFor", function() {
|
describe("parameterInclusionSettingFor", function() {
|
||||||
it("should support getting name+in param inclusion settings", function () {
|
it("should support getting {in}.{name} param inclusion settings", function () {
|
||||||
const param = fromJS({
|
const param = fromJS({
|
||||||
name: "param",
|
name: "param",
|
||||||
in: "query",
|
in: "query",
|
||||||
@@ -776,7 +776,7 @@ describe("spec plugin - selectors", function(){
|
|||||||
"/": {
|
"/": {
|
||||||
"get": {
|
"get": {
|
||||||
"parameter_inclusions": {
|
"parameter_inclusions": {
|
||||||
[`param.query`]: true
|
[`query.param`]: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ import {
|
|||||||
sanitizeUrl,
|
sanitizeUrl,
|
||||||
extractFileNameFromContentDispositionHeader,
|
extractFileNameFromContentDispositionHeader,
|
||||||
deeplyStripKey,
|
deeplyStripKey,
|
||||||
getSampleSchema
|
getSampleSchema,
|
||||||
|
paramToIdentifier,
|
||||||
|
paramToValue,
|
||||||
} from "core/utils"
|
} from "core/utils"
|
||||||
import win from "core/window"
|
import win from "core/window"
|
||||||
|
|
||||||
@@ -342,30 +344,33 @@ describe("utils", function() {
|
|||||||
|
|
||||||
describe("validateParam", function() {
|
describe("validateParam", function() {
|
||||||
let param = null
|
let param = null
|
||||||
|
let value = null
|
||||||
let result = null
|
let result = null
|
||||||
|
|
||||||
const assertValidateParam = (param, expectedError) => {
|
const assertValidateParam = (param, value, expectedError) => {
|
||||||
// Swagger 2.0 version
|
// Swagger 2.0 version
|
||||||
result = validateParam( fromJS(param), false )
|
result = validateParam( fromJS(param), fromJS(value))
|
||||||
expect( result ).toEqual( expectedError )
|
expect( result ).toEqual( expectedError )
|
||||||
|
|
||||||
// OAS3 version, using `schema` sub-object
|
// OAS3 version, using `schema` sub-object
|
||||||
let oas3Param = {
|
let oas3Param = {
|
||||||
value: param.value,
|
|
||||||
required: param.required,
|
required: param.required,
|
||||||
schema: {
|
schema: {
|
||||||
...param,
|
...param,
|
||||||
value: undefined,
|
|
||||||
required: undefined
|
required: undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = validateParam( fromJS(oas3Param), false, true )
|
result = validateParam( fromJS(oas3Param), fromJS(value), {
|
||||||
|
isOAS3: true
|
||||||
|
})
|
||||||
expect( result ).toEqual( expectedError )
|
expect( result ).toEqual( expectedError )
|
||||||
}
|
}
|
||||||
|
|
||||||
const assertValidateOas3Param = (param, expectedError) => {
|
const assertValidateOas3Param = (param, value, expectedError) => {
|
||||||
// for cases where you _only_ want to try OAS3
|
// for cases where you _only_ want to try OAS3
|
||||||
result = validateParam( fromJS(param), false, true )
|
result = validateParam(fromJS(param), value, {
|
||||||
|
isOAS3: true
|
||||||
|
})
|
||||||
expect( result ).toEqual( expectedError )
|
expect( result ).toEqual( expectedError )
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,10 +378,12 @@ describe("utils", function() {
|
|||||||
// This should "skip" validation because there is no `schema` property
|
// This should "skip" validation because there is no `schema` property
|
||||||
// and we are telling `validateParam` this is an OAS3 spec
|
// and we are telling `validateParam` this is an OAS3 spec
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
value: "",
|
|
||||||
required: true
|
required: true
|
||||||
})
|
})
|
||||||
result = validateParam( param, false, true )
|
value = ""
|
||||||
|
result = validateParam( param, value, {
|
||||||
|
isOAS3: true
|
||||||
|
} )
|
||||||
expect( result ).toEqual( [] )
|
expect( result ).toEqual( [] )
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -386,34 +393,34 @@ describe("utils", function() {
|
|||||||
required: true,
|
required: true,
|
||||||
schema: {
|
schema: {
|
||||||
type: "object"
|
type: "object"
|
||||||
},
|
|
||||||
value: {
|
|
||||||
abc: 123
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertValidateOas3Param(param, [])
|
value = {
|
||||||
|
abc: 123
|
||||||
|
}
|
||||||
|
assertValidateOas3Param(param, value, [])
|
||||||
|
|
||||||
// valid object-as-string
|
// valid object-as-string
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
schema: {
|
schema: {
|
||||||
type: "object"
|
type: "object"
|
||||||
},
|
}
|
||||||
value: JSON.stringify({
|
|
||||||
abc: 123
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
assertValidateOas3Param(param, [])
|
value = JSON.stringify({
|
||||||
|
abc: 123
|
||||||
|
})
|
||||||
|
assertValidateOas3Param(param, value, [])
|
||||||
|
|
||||||
// invalid object-as-string
|
// invalid object-as-string
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
schema: {
|
schema: {
|
||||||
type: "object"
|
type: "object"
|
||||||
},
|
}
|
||||||
value: "{{}"
|
|
||||||
}
|
}
|
||||||
assertValidateOas3Param(param, ["Parameter string value must be valid JSON"])
|
value = "{{}"
|
||||||
|
assertValidateOas3Param(param, value, ["Parameter string value must be valid JSON"])
|
||||||
|
|
||||||
// missing when required
|
// missing when required
|
||||||
param = {
|
param = {
|
||||||
@@ -422,7 +429,8 @@ describe("utils", function() {
|
|||||||
type: "object"
|
type: "object"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
assertValidateOas3Param(param, ["Required field is not provided"])
|
value = undefined
|
||||||
|
assertValidateOas3Param(param, value, ["Required field is not provided"])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional OAS3 objects", function() {
|
it("validates optional OAS3 objects", function() {
|
||||||
@@ -430,32 +438,32 @@ describe("utils", function() {
|
|||||||
param = {
|
param = {
|
||||||
schema: {
|
schema: {
|
||||||
type: "object"
|
type: "object"
|
||||||
},
|
|
||||||
value: {
|
|
||||||
abc: 123
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertValidateOas3Param(param, [])
|
value = {
|
||||||
|
abc: 123
|
||||||
|
}
|
||||||
|
assertValidateOas3Param(param, value, [])
|
||||||
|
|
||||||
// valid object-as-string
|
// valid object-as-string
|
||||||
param = {
|
param = {
|
||||||
schema: {
|
schema: {
|
||||||
type: "object"
|
type: "object"
|
||||||
},
|
}
|
||||||
value: JSON.stringify({
|
|
||||||
abc: 123
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
assertValidateOas3Param(param, [])
|
value = JSON.stringify({
|
||||||
|
abc: 123
|
||||||
|
})
|
||||||
|
assertValidateOas3Param(param, value, [])
|
||||||
|
|
||||||
// invalid object-as-string
|
// invalid object-as-string
|
||||||
param = {
|
param = {
|
||||||
schema: {
|
schema: {
|
||||||
type: "object"
|
type: "object"
|
||||||
},
|
}
|
||||||
value: "{{}"
|
|
||||||
}
|
}
|
||||||
assertValidateOas3Param(param, ["Parameter string value must be valid JSON"])
|
value = "{{}"
|
||||||
|
assertValidateOas3Param(param, value, ["Parameter string value must be valid JSON"])
|
||||||
|
|
||||||
// missing when not required
|
// missing when not required
|
||||||
param = {
|
param = {
|
||||||
@@ -463,35 +471,36 @@ describe("utils", function() {
|
|||||||
type: "object"
|
type: "object"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
assertValidateOas3Param(param, [])
|
value = undefined
|
||||||
|
assertValidateOas3Param(param, value, [])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required strings", function() {
|
it("validates required strings", function() {
|
||||||
// invalid string
|
// invalid string
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "string",
|
type: "string"
|
||||||
value: ""
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Required field is not provided"])
|
value = ""
|
||||||
|
assertValidateParam(param, value, ["Required field is not provided"])
|
||||||
|
|
||||||
// valid string
|
// valid string
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "string",
|
type: "string"
|
||||||
value: "test string"
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = "test string"
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// valid string with min and max length
|
// valid string with min and max length
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "string",
|
type: "string",
|
||||||
value: "test string",
|
|
||||||
maxLength: 50,
|
maxLength: 50,
|
||||||
minLength: 1
|
minLength: 1
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = "test string"
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required strings with min and max length", function() {
|
it("validates required strings with min and max length", function() {
|
||||||
@@ -499,380 +508,381 @@ describe("utils", function() {
|
|||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "string",
|
type: "string",
|
||||||
value: "test string",
|
|
||||||
maxLength: 5
|
maxLength: 5
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Value must be less than MaxLength"])
|
value = "test string"
|
||||||
|
assertValidateParam(param, value, ["Value must be less than MaxLength"])
|
||||||
|
|
||||||
// invalid string with max length 0
|
// invalid string with max length 0
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "string",
|
type: "string",
|
||||||
value: "test string",
|
|
||||||
maxLength: 0
|
maxLength: 0
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Value must be less than MaxLength"])
|
value = "test string"
|
||||||
|
assertValidateParam(param, value, ["Value must be less than MaxLength"])
|
||||||
|
|
||||||
// invalid string with min length
|
// invalid string with min length
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "string",
|
type: "string",
|
||||||
value: "test string",
|
|
||||||
minLength: 50
|
minLength: 50
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Value must be greater than MinLength"])
|
value = "test string"
|
||||||
|
assertValidateParam(param, value, ["Value must be greater than MinLength"])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional strings", function() {
|
it("validates optional strings", function() {
|
||||||
// valid (empty) string
|
// valid (empty) string
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "string",
|
type: "string"
|
||||||
value: ""
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = ""
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// valid string
|
// valid string
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "string",
|
type: "string"
|
||||||
value: "test"
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = "test"
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required files", function() {
|
it("validates required files", function() {
|
||||||
// invalid file
|
// invalid file
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "file",
|
type: "file"
|
||||||
value: undefined
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Required field is not provided"])
|
value = undefined
|
||||||
|
assertValidateParam(param, value, ["Required field is not provided"])
|
||||||
|
|
||||||
// valid file
|
// valid file
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "file",
|
type: "file"
|
||||||
value: new win.File()
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = new win.File()
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional files", function() {
|
it("validates optional files", function() {
|
||||||
// invalid file
|
// invalid file
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "file",
|
type: "file"
|
||||||
value: "not a file"
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Value must be a file"])
|
value = "not a file"
|
||||||
|
assertValidateParam(param, value, ["Value must be a file"])
|
||||||
|
|
||||||
// valid (empty) file
|
// valid (empty) file
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "file",
|
type: "file"
|
||||||
value: undefined
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = undefined
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// valid file
|
// valid file
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "file",
|
type: "file"
|
||||||
value: new win.File()
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = new win.File()
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required arrays", function() {
|
it("validates required arrays", function() {
|
||||||
// invalid (empty) array
|
// invalid (empty) array
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "array",
|
type: "array"
|
||||||
value: []
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Required field is not provided"])
|
value = []
|
||||||
|
assertValidateParam(param, value, ["Required field is not provided"])
|
||||||
|
|
||||||
// invalid (not an array)
|
// invalid (not an array)
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "array",
|
type: "array"
|
||||||
value: undefined
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Required field is not provided"])
|
value = undefined
|
||||||
|
assertValidateParam(param, value, ["Required field is not provided"])
|
||||||
|
|
||||||
// invalid array, items do not match correct type
|
// invalid array, items do not match correct type
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: [1],
|
|
||||||
items: {
|
items: {
|
||||||
type: "string"
|
type: "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [{index: 0, error: "Value must be a string"}])
|
value = [1]
|
||||||
|
assertValidateParam(param, value, [{index: 0, error: "Value must be a string"}])
|
||||||
|
|
||||||
// valid array, with no 'type' for items
|
// valid array, with no 'type' for items
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "array",
|
type: "array"
|
||||||
value: ["1"]
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = [1]
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// valid array, items match type
|
// valid array, items match type
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: ["1"],
|
|
||||||
items: {
|
items: {
|
||||||
type: "string"
|
type: "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = ["1"]
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional arrays", function() {
|
it("validates optional arrays", function() {
|
||||||
// valid, empty array
|
// valid, empty array
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "array",
|
type: "array"
|
||||||
value: []
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = []
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// invalid, items do not match correct type
|
// invalid, items do not match correct type
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: ["number"],
|
|
||||||
items: {
|
items: {
|
||||||
type: "number"
|
type: "number"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [{index: 0, error: "Value must be a number"}])
|
value = ["number"]
|
||||||
|
assertValidateParam(param, value, [{index: 0, error: "Value must be a number"}])
|
||||||
|
|
||||||
// valid
|
// valid
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: ["test"],
|
|
||||||
items: {
|
items: {
|
||||||
type: "string"
|
type: "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = ["test"]
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required booleans", function() {
|
it("validates required booleans", function() {
|
||||||
// invalid boolean value
|
// invalid boolean value
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "boolean",
|
type: "boolean"
|
||||||
value: undefined
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Required field is not provided"])
|
value = undefined
|
||||||
|
assertValidateParam(param, value, ["Required field is not provided"])
|
||||||
|
|
||||||
// invalid boolean value (not a boolean)
|
// invalid boolean value (not a boolean)
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "boolean",
|
type: "boolean"
|
||||||
value: "test string"
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Value must be a boolean"])
|
value = "test string"
|
||||||
|
assertValidateParam(param, value, ["Value must be a boolean"])
|
||||||
|
|
||||||
// valid boolean value
|
// valid boolean value
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "boolean",
|
type: "boolean"
|
||||||
value: "true"
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = "true"
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// valid boolean value
|
// valid boolean value
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "boolean",
|
type: "boolean"
|
||||||
value: false
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = false
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional booleans", function() {
|
it("validates optional booleans", function() {
|
||||||
// valid (empty) boolean value
|
// valid (empty) boolean value
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "boolean",
|
type: "boolean"
|
||||||
value: undefined
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = undefined
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// invalid boolean value (not a boolean)
|
// invalid boolean value (not a boolean)
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "boolean",
|
type: "boolean"
|
||||||
value: "test string"
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Value must be a boolean"])
|
value = "test string"
|
||||||
|
assertValidateParam(param, value, ["Value must be a boolean"])
|
||||||
|
|
||||||
// valid boolean value
|
// valid boolean value
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "boolean",
|
type: "boolean"
|
||||||
value: "true"
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = "true"
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// valid boolean value
|
// valid boolean value
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "boolean",
|
type: "boolean"
|
||||||
value: false
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = false
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required numbers", function() {
|
it("validates required numbers", function() {
|
||||||
// invalid number, string instead of a number
|
// invalid number, string instead of a number
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "number",
|
type: "number"
|
||||||
value: "test"
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Value must be a number"])
|
value = "test"
|
||||||
|
assertValidateParam(param, value, ["Value must be a number"])
|
||||||
|
|
||||||
// invalid number, undefined value
|
// invalid number, undefined value
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "number",
|
type: "number"
|
||||||
value: undefined
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Required field is not provided"])
|
value = undefined
|
||||||
|
assertValidateParam(param, value, ["Required field is not provided"])
|
||||||
|
|
||||||
// valid number with min and max
|
// valid number with min and max
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "number",
|
type: "number",
|
||||||
value: 10,
|
|
||||||
minimum: 5,
|
minimum: 5,
|
||||||
maximum: 99
|
maximum: 99
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = 10
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// valid negative number with min and max
|
// valid negative number with min and max
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "number",
|
type: "number",
|
||||||
value: -10,
|
|
||||||
minimum: -50,
|
minimum: -50,
|
||||||
maximum: -5
|
maximum: -5
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = -10
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// invalid number with maximum:0
|
// invalid number with maximum:0
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "number",
|
type: "number",
|
||||||
value: 1,
|
|
||||||
maximum: 0
|
maximum: 0
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Value must be less than Maximum"])
|
value = 1
|
||||||
|
assertValidateParam(param, value, ["Value must be less than Maximum"])
|
||||||
|
|
||||||
// invalid number with minimum:0
|
// invalid number with minimum:0
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "number",
|
type: "number",
|
||||||
value: -10,
|
|
||||||
minimum: 0
|
minimum: 0
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Value must be greater than Minimum"])
|
value = -10
|
||||||
|
assertValidateParam(param, value, ["Value must be greater than Minimum"])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional numbers", function() {
|
it("validates optional numbers", function() {
|
||||||
// invalid number, string instead of a number
|
// invalid number, string instead of a number
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "number",
|
type: "number"
|
||||||
value: "test"
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Value must be a number"])
|
value = "test"
|
||||||
|
assertValidateParam(param, value, ["Value must be a number"])
|
||||||
|
|
||||||
// valid (empty) number
|
// valid (empty) number
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "number",
|
type: "number"
|
||||||
value: undefined
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = undefined
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// valid number
|
// valid number
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "number",
|
type: "number"
|
||||||
value: 10
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = 10
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required integers", function() {
|
it("validates required integers", function() {
|
||||||
// invalid integer, string instead of an integer
|
// invalid integer, string instead of an integer
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "integer",
|
type: "integer"
|
||||||
value: "test"
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Value must be an integer"])
|
value = "test"
|
||||||
|
assertValidateParam(param, value, ["Value must be an integer"])
|
||||||
|
|
||||||
// invalid integer, undefined value
|
// invalid integer, undefined value
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "integer",
|
type: "integer"
|
||||||
value: undefined
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Required field is not provided"])
|
value = undefined
|
||||||
|
assertValidateParam(param, value, ["Required field is not provided"])
|
||||||
|
|
||||||
// valid integer, but 0 is falsy in JS
|
// valid integer, but 0 is falsy in JS
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "integer",
|
type: "integer"
|
||||||
value: 0
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = 0
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// valid integer
|
// valid integer
|
||||||
param = {
|
param = {
|
||||||
required: true,
|
required: true,
|
||||||
type: "integer",
|
type: "integer"
|
||||||
value: 10
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = 10
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates optional integers", function() {
|
it("validates optional integers", function() {
|
||||||
// invalid integer, string instead of an integer
|
// invalid integer, string instead of an integer
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "integer",
|
type: "integer"
|
||||||
value: "test"
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, ["Value must be an integer"])
|
value = "test"
|
||||||
|
assertValidateParam(param, value, ["Value must be an integer"])
|
||||||
|
|
||||||
// valid (empty) integer
|
// valid (empty) integer
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "integer",
|
type: "integer"
|
||||||
value: undefined
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = undefined
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
|
|
||||||
// integers
|
// integers
|
||||||
param = {
|
param = {
|
||||||
required: false,
|
required: false,
|
||||||
type: "integer",
|
type: "integer"
|
||||||
value: 10
|
|
||||||
}
|
}
|
||||||
assertValidateParam(param, [])
|
value = 10
|
||||||
|
assertValidateParam(param, value, [])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1209,6 +1219,7 @@ describe("utils", function() {
|
|||||||
expect(sanitizeUrl({})).toEqual("")
|
expect(sanitizeUrl({})).toEqual("")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("getSampleSchema", function() {
|
describe("getSampleSchema", function() {
|
||||||
const oriDate = Date
|
const oriDate = Date
|
||||||
|
|
||||||
@@ -1235,4 +1246,144 @@ describe("utils", function() {
|
|||||||
expect(res).toEqual(new Date().toISOString())
|
expect(res).toEqual(new Date().toISOString())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("paramToIdentifier", function() {
|
||||||
|
it("should convert an Immutable parameter map to an identifier", () => {
|
||||||
|
const param = fromJS({
|
||||||
|
name: "id",
|
||||||
|
in: "query"
|
||||||
|
})
|
||||||
|
const res = paramToIdentifier(param)
|
||||||
|
|
||||||
|
expect(res).toEqual("query.id.hash-606199662")
|
||||||
|
})
|
||||||
|
it("should convert an Immutable parameter map to a set of identifiers", () => {
|
||||||
|
const param = fromJS({
|
||||||
|
name: "id",
|
||||||
|
in: "query"
|
||||||
|
})
|
||||||
|
const res = paramToIdentifier(param, { returnAll: true })
|
||||||
|
|
||||||
|
expect(res).toEqual([
|
||||||
|
"query.id.hash-606199662",
|
||||||
|
"query.id",
|
||||||
|
"id"
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should convert an unhashable Immutable parameter map to an identifier", () => {
|
||||||
|
const param = fromJS({
|
||||||
|
name: "id",
|
||||||
|
in: "query"
|
||||||
|
})
|
||||||
|
|
||||||
|
param.hashCode = null
|
||||||
|
|
||||||
|
const res = paramToIdentifier(param)
|
||||||
|
|
||||||
|
expect(res).toEqual("query.id")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should convert an unhashable Immutable parameter map to a set of identifiers", () => {
|
||||||
|
const param = fromJS({
|
||||||
|
name: "id",
|
||||||
|
in: "query"
|
||||||
|
})
|
||||||
|
|
||||||
|
param.hashCode = null
|
||||||
|
|
||||||
|
const res = paramToIdentifier(param, { returnAll: true })
|
||||||
|
|
||||||
|
expect(res).toEqual([
|
||||||
|
"query.id",
|
||||||
|
"id"
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should convert an Immutable parameter map lacking an `in` value to an identifier", () => {
|
||||||
|
const param = fromJS({
|
||||||
|
name: "id"
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = paramToIdentifier(param)
|
||||||
|
|
||||||
|
expect(res).toEqual("id")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should convert an Immutable parameter map lacking an `in` value to an identifier", () => {
|
||||||
|
const param = fromJS({
|
||||||
|
name: "id"
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = paramToIdentifier(param, { returnAll: true })
|
||||||
|
|
||||||
|
expect(res).toEqual(["id"])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw gracefully when given a non-Immutable parameter input", () => {
|
||||||
|
const param = {
|
||||||
|
name: "id"
|
||||||
|
}
|
||||||
|
|
||||||
|
let error = null
|
||||||
|
let res = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = paramToIdentifier(param)
|
||||||
|
} catch(e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).toBeA(Error)
|
||||||
|
expect(error.message).toInclude("received a non-Im.Map parameter as input")
|
||||||
|
expect(res).toEqual(null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("paramToValue", function() {
|
||||||
|
it("should identify a hash-keyed value", () => {
|
||||||
|
const param = fromJS({
|
||||||
|
name: "id",
|
||||||
|
in: "query"
|
||||||
|
})
|
||||||
|
|
||||||
|
const paramValues = {
|
||||||
|
"query.id.hash-606199662": "asdf"
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = paramToValue(param, paramValues)
|
||||||
|
|
||||||
|
expect(res).toEqual("asdf")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should identify a in+name value", () => {
|
||||||
|
const param = fromJS({
|
||||||
|
name: "id",
|
||||||
|
in: "query"
|
||||||
|
})
|
||||||
|
|
||||||
|
const paramValues = {
|
||||||
|
"query.id": "asdf"
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = paramToValue(param, paramValues)
|
||||||
|
|
||||||
|
expect(res).toEqual("asdf")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should identify a name value", () => {
|
||||||
|
const param = fromJS({
|
||||||
|
name: "id",
|
||||||
|
in: "query"
|
||||||
|
})
|
||||||
|
|
||||||
|
const paramValues = {
|
||||||
|
"id": "asdf"
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = paramToValue(param, paramValues)
|
||||||
|
|
||||||
|
expect(res).toEqual("asdf")
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
26
test/e2e-cypress/static/documents/bugs/5129.yaml
Normal file
26
test/e2e-cypress/static/documents/bugs/5129.yaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
openapi: "3.0.0"
|
||||||
|
|
||||||
|
paths:
|
||||||
|
/aev:
|
||||||
|
get:
|
||||||
|
parameters:
|
||||||
|
- name: param
|
||||||
|
in: query
|
||||||
|
allowEmptyValue: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: ok
|
||||||
|
/aev/and/required:
|
||||||
|
get:
|
||||||
|
parameters:
|
||||||
|
- name: param
|
||||||
|
in: query
|
||||||
|
allowEmptyValue: true
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: ok
|
||||||
121
test/e2e-cypress/tests/bugs/5129.js
Normal file
121
test/e2e-cypress/tests/bugs/5129.js
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
describe("#5129: parameter required + allowEmptyValue interactions", () => {
|
||||||
|
describe("allowEmptyValue parameter", () => {
|
||||||
|
const opId = "#operations-default-get_aev"
|
||||||
|
it("should omit the parameter by default", () => {
|
||||||
|
cy
|
||||||
|
.visit("/?url=/documents/bugs/5129.yaml")
|
||||||
|
.get(opId)
|
||||||
|
.click()
|
||||||
|
.get(".btn.try-out__btn")
|
||||||
|
.click()
|
||||||
|
.get(".btn.execute")
|
||||||
|
.click()
|
||||||
|
.get(".request-url pre")
|
||||||
|
.should("have.text", "http://localhost:3230/aev")
|
||||||
|
})
|
||||||
|
it("should include a value", () => {
|
||||||
|
cy
|
||||||
|
.visit("/?url=/documents/bugs/5129.yaml")
|
||||||
|
.get(opId)
|
||||||
|
.click()
|
||||||
|
.get(".btn.try-out__btn")
|
||||||
|
.click()
|
||||||
|
.get(`.parameters-col_description input[type=text]`)
|
||||||
|
.type("asdf")
|
||||||
|
.get(".btn.execute")
|
||||||
|
.click()
|
||||||
|
.get(".request-url pre")
|
||||||
|
.should("have.text", "http://localhost:3230/aev?param=asdf")
|
||||||
|
})
|
||||||
|
it("should include an empty value when empty value box is checked", () => {
|
||||||
|
cy
|
||||||
|
.visit("/?url=/documents/bugs/5129.yaml")
|
||||||
|
.get(opId)
|
||||||
|
.click()
|
||||||
|
.get(".btn.try-out__btn")
|
||||||
|
.click()
|
||||||
|
.get(`.parameters-col_description input[type=checkbox]`)
|
||||||
|
.check()
|
||||||
|
.get(".btn.execute")
|
||||||
|
.click()
|
||||||
|
.get(".request-url pre")
|
||||||
|
.should("have.text", "http://localhost:3230/aev?param=")
|
||||||
|
})
|
||||||
|
it("should include a value when empty value box is checked and then input is provided", () => {
|
||||||
|
cy
|
||||||
|
.visit("/?url=/documents/bugs/5129.yaml")
|
||||||
|
.get(opId)
|
||||||
|
.click()
|
||||||
|
.get(".btn.try-out__btn")
|
||||||
|
.click()
|
||||||
|
.get(`.parameters-col_description input[type=checkbox]`)
|
||||||
|
.check()
|
||||||
|
.get(`.parameters-col_description input[type=text]`)
|
||||||
|
.type("1234")
|
||||||
|
.get(".btn.execute")
|
||||||
|
.click()
|
||||||
|
.get(".request-url pre")
|
||||||
|
.should("have.text", "http://localhost:3230/aev?param=1234")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe("allowEmptyValue + required parameter", () => {
|
||||||
|
const opId = "#operations-default-get_aev_and_required"
|
||||||
|
it("should refuse to execute by default", () => {
|
||||||
|
cy
|
||||||
|
.visit("/?url=/documents/bugs/5129.yaml")
|
||||||
|
.get(opId)
|
||||||
|
.click()
|
||||||
|
.get(".btn.try-out__btn")
|
||||||
|
.click()
|
||||||
|
.get(".btn.execute")
|
||||||
|
.click()
|
||||||
|
.wait(1000)
|
||||||
|
.get(".request-url pre")
|
||||||
|
.should("not.exist")
|
||||||
|
})
|
||||||
|
it("should include a value", () => {
|
||||||
|
cy
|
||||||
|
.visit("/?url=/documents/bugs/5129.yaml")
|
||||||
|
.get(opId)
|
||||||
|
.click()
|
||||||
|
.get(".btn.try-out__btn")
|
||||||
|
.click()
|
||||||
|
.get(`.parameters-col_description input[type=text]`)
|
||||||
|
.type("asdf")
|
||||||
|
.get(".btn.execute")
|
||||||
|
.click()
|
||||||
|
.get(".request-url pre")
|
||||||
|
.should("have.text", "http://localhost:3230/aev/and/required?param=asdf")
|
||||||
|
})
|
||||||
|
it("should include an empty value when empty value box is checked", () => {
|
||||||
|
cy
|
||||||
|
.visit("/?url=/documents/bugs/5129.yaml")
|
||||||
|
.get(opId)
|
||||||
|
.click()
|
||||||
|
.get(".btn.try-out__btn")
|
||||||
|
.click()
|
||||||
|
.get(`.parameters-col_description input[type=checkbox]`)
|
||||||
|
.check()
|
||||||
|
.get(".btn.execute")
|
||||||
|
.click()
|
||||||
|
.get(".request-url pre")
|
||||||
|
.should("have.text", "http://localhost:3230/aev/and/required?param=")
|
||||||
|
})
|
||||||
|
it("should include a value when empty value box is checked and then input is provided", () => {
|
||||||
|
cy
|
||||||
|
.visit("/?url=/documents/bugs/5129.yaml")
|
||||||
|
.get(opId)
|
||||||
|
.click()
|
||||||
|
.get(".btn.try-out__btn")
|
||||||
|
.click()
|
||||||
|
.get(`.parameters-col_description input[type=checkbox]`)
|
||||||
|
.check()
|
||||||
|
.get(`.parameters-col_description input[type=text]`)
|
||||||
|
.type("1234")
|
||||||
|
.get(".btn.execute")
|
||||||
|
.click()
|
||||||
|
.get(".request-url pre")
|
||||||
|
.should("have.text", "http://localhost:3230/aev/and/required?param=1234")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user