- | { key }: |
+
+ { key }{ isRequired && * }
+ |
)
@@ -121,6 +122,7 @@ export class JsonSchema_array extends PureComponent {
render() {
let { getComponent, required, schema, fn } = this.props
+ let errors = schema.errors || []
let itemSchema = fn.inferSchema(schema.items)
const JsonSchemaForm = getComponent("JsonSchemaForm")
@@ -131,19 +133,17 @@ export class JsonSchema_array extends PureComponent {
if ( enumValue ) {
const Select = getComponent("Select")
- return ()
}
- let errors = schema.errors || []
-
return (
- { !value || value.count() < 1 ?
- (errors.length ? { errors[0] } : null) :
+ { !value || value.count() < 1 ? null :
value.map( (item,i) => {
let schema = Object.assign({}, itemSchema)
if ( errors.length ) {
@@ -153,12 +153,12 @@ export class JsonSchema_array extends PureComponent {
return (
this.onItemChange(val, i)} schema={schema} />
-
+
)
}).toArray()
}
-
+
)
}
@@ -170,12 +170,14 @@ export class JsonSchema_boolean extends Component {
onEnumChange = (val) => this.props.onChange(val)
render() {
- let { getComponent, required, value } = this.props
+ let { getComponent, value, schema } = this.props
+ let errors = schema.errors || []
const Select = getComponent("Select")
- return ()
}
}
diff --git a/src/core/utils.js b/src/core/utils.js
index 95771fb4..7cc5beda 100644
--- a/src/core/utils.js
+++ b/src/core/utils.js
@@ -41,7 +41,7 @@ export function fromJSOrdered (js) {
return !isObject(js) ? js :
Array.isArray(js) ?
Im.Seq(js).map(fromJSOrdered).toList() :
- Im.Seq(js).map(fromJSOrdered).toOrderedMap()
+ Im.OrderedMap(js).map(fromJSOrdered)
}
export function bindToState(obj, state) {
@@ -468,6 +468,18 @@ export const validateFile = ( val ) => {
}
}
+export const validateBoolean = ( val ) => {
+ if ( !(val === "true" || val === "false" || val === true || val === false) ) {
+ return "Value must be a boolean"
+ }
+}
+
+export const validateString = ( val ) => {
+ if ( val && typeof val !== "string" ) {
+ return "Value must be a string"
+ }
+}
+
// validation of parameters before execute
export const validateParam = (param, isXml) => {
let errors = []
@@ -475,52 +487,66 @@ export const validateParam = (param, isXml) => {
let required = param.get("required")
let type = param.get("type")
- let stringCheck = type === "string" && !value
- let arrayCheck = type === "array" && Array.isArray(value) && !value.length
- let listCheck = type === "array" && Im.List.isList(value) && !value.count()
- let fileCheck = type === "file" && !(value instanceof win.File)
+ // If the parameter is required OR the parameter has a value (meaning optional, but filled in)
+ // then we should do our validation routine
+ if ( required || value ) {
+ // These checks should evaluate to true if the parameter's value is valid
+ let stringCheck = type === "string" && value && !validateString(value)
+ let arrayCheck = type === "array" && Array.isArray(value) && value.length
+ let listCheck = type === "array" && Im.List.isList(value) && value.count()
+ let fileCheck = type === "file" && value instanceof win.File
+ let booleanCheck = type === "boolean" && !validateBoolean(value)
+ let numberCheck = type === "number" && !validateNumber(value) // validateNumber returns undefined if the value is a number
+ let integerCheck = type === "integer" && !validateInteger(value) // validateInteger returns undefined if the value is an integer
- if ( required && (stringCheck || arrayCheck || listCheck || fileCheck) ) {
- errors.push("Required field is not provided")
- return errors
- }
+ if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) {
+ errors.push("Required field is not provided")
+ return errors
+ }
- if ( value === null || value === undefined ) {
- return errors
- }
+ if ( type === "string" ) {
+ let err = validateString(value)
+ if (!err) return errors
+ errors.push(err)
+ } else if ( type === "boolean" ) {
+ let err = validateBoolean(value)
+ if (!err) return errors
+ errors.push(err)
+ } else if ( type === "number" ) {
+ let err = validateNumber(value)
+ if (!err) return errors
+ errors.push(err)
+ } else if ( type === "integer" ) {
+ let err = validateInteger(value)
+ if (!err) return errors
+ errors.push(err)
+ } else if ( type === "array" ) {
+ let itemType
- if ( type === "number" ) {
- let err = validateNumber(value)
- if (!err) return errors
- errors.push(err)
- } else if ( type === "integer" ) {
- let err = validateInteger(value)
- if (!err) return errors
- errors.push(err)
- } else if ( type === "array" ) {
- let itemType
+ if ( !value.count() ) { return errors }
- if ( !value.count() ) { return errors }
+ itemType = param.getIn(["items", "type"])
- itemType = param.getIn(["items", "type"])
+ value.forEach((item, index) => {
+ let err
- value.forEach((item, index) => {
- let err
+ if (itemType === "number") {
+ err = validateNumber(item)
+ } else if (itemType === "integer") {
+ err = validateInteger(item)
+ } else if (itemType === "string") {
+ err = validateString(item)
+ }
- if (itemType === "number") {
- err = validateNumber(item)
- } else if (itemType === "integer") {
- err = validateInteger(item)
- }
-
- if ( err ) {
- errors.push({ index: index, error: err})
- }
- })
- } else if ( type === "file" ) {
- let err = validateFile(value)
- if (!err) return errors
- errors.push(err)
+ if ( err ) {
+ errors.push({ index: index, error: err})
+ }
+ })
+ } else if ( type === "file" ) {
+ let err = validateFile(value)
+ if (!err) return errors
+ errors.push(err)
+ }
}
return errors
diff --git a/src/style/_buttons.scss b/src/style/_buttons.scss
index 2470f8b0..bfb85023 100644
--- a/src/style/_buttons.scss
+++ b/src/style/_buttons.scss
@@ -14,6 +14,11 @@
@include text_headline();
+ &.btn-sm {
+ font-size: 12px;
+ padding: 4px 23px;
+ }
+
&[disabled]
{
cursor: not-allowed;
@@ -165,6 +170,9 @@
button
{
cursor: pointer;
-
outline: none;
+
+ &.invalid {
+ @include invalidFormElement();
+ }
}
diff --git a/src/style/_form.scss b/src/style/_form.scss
index 185b836e..e54d5438 100644
--- a/src/style/_form.scss
+++ b/src/style/_form.scss
@@ -21,6 +21,10 @@ select
background: #f7f7f7;
}
+
+ &.invalid {
+ @include invalidFormElement();
+ }
}
.opblock-body select
@@ -53,12 +57,8 @@ input[type=file]
border-radius: 4px;
background: #fff;
- &.invalid
- {
- animation: shake .4s 1;
-
- border-color: $_color-delete;
- background: lighten($_color-delete, 35%);
+ &.invalid {
+ @include invalidFormElement();
}
}
diff --git a/src/style/_mixins.scss b/src/style/_mixins.scss
index a2a27d48..8fd01720 100644
--- a/src/style/_mixins.scss
+++ b/src/style/_mixins.scss
@@ -166,3 +166,9 @@ $browser-context: 16;
@warn 'Breakpoint mixin supports: tablet, mobile, desktop';
}
}
+
+@mixin invalidFormElement() {
+ animation: shake .4s 1;
+ border-color: $_color-delete;
+ background: lighten($_color-delete, 35%);
+}
diff --git a/src/style/_table.scss b/src/style/_table.scss
index 3d58f3d8..d1481709 100644
--- a/src/style/_table.scss
+++ b/src/style/_table.scss
@@ -97,6 +97,10 @@ table
width: 100%;
max-width: 340px;
}
+
+ select {
+ border-width: 1px;
+ }
}
.parameter__name
diff --git a/test/components/schemes.js b/test/components/schemes.js
new file mode 100644
index 00000000..a21c0628
--- /dev/null
+++ b/test/components/schemes.js
@@ -0,0 +1,41 @@
+
+/* eslint-env mocha */
+import React from "react"
+import expect, { createSpy } from "expect"
+import { shallow } from "enzyme"
+import { fromJS } from "immutable"
+import Schemes from "components/schemes"
+
+describe("", function(){
+ it("calls props.specActions.setScheme() when no operationScheme is selected", function(){
+
+ // Given
+ let props = {
+ specActions: {
+ setScheme: createSpy()
+ },
+ schemes: fromJS([
+ "http",
+ "https"
+ ]),
+ operationScheme: undefined,
+ path: "/test",
+ method: "get"
+ }
+
+ // When
+ let wrapper = shallow()
+
+ // Then operationScheme should default to first scheme in options list
+ expect(props.specActions.setScheme).toHaveBeenCalledWith("http", "/test" , "get")
+
+ // When the operationScheme is no longer in the list of options
+ props.schemes = fromJS([
+ "https"
+ ])
+ wrapper.setProps(props)
+
+ // Then operationScheme should default to first scheme in options list
+ expect(props.specActions.setScheme).toHaveBeenCalledWith("https", "/test", "get")
+ })
+})
diff --git a/test/core/utils.js b/test/core/utils.js
index a63da13d..acc5a14e 100644
--- a/test/core/utils.js
+++ b/test/core/utils.js
@@ -1,10 +1,10 @@
/* eslint-env mocha */
import expect from "expect"
import { fromJS } from "immutable"
-import { mapToList, validateNumber, validateInteger, validateParam, validateFile } from "core/utils"
+import { mapToList, validateNumber, validateInteger, validateParam, validateFile, fromJSOrdered } from "core/utils"
import win from "core/window"
-describe("utils", function(){
+describe("utils", function() {
describe("mapToList", function(){
@@ -176,6 +176,7 @@ describe("utils", function(){
let result = null
it("validates required strings", function() {
+ // invalid string
param = fromJS({
required: true,
type: "string",
@@ -183,9 +184,39 @@ describe("utils", function(){
})
result = validateParam( param, false )
expect( result ).toEqual( ["Required field is not provided"] )
+
+ // valid string
+ param = fromJS({
+ required: true,
+ type: "string",
+ value: "test string"
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+ })
+
+ it("validates optional strings", function() {
+ // valid (empty) string
+ param = fromJS({
+ required: false,
+ type: "string",
+ value: ""
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+
+ // valid string
+ param = fromJS({
+ required: false,
+ type: "string",
+ value: "test"
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
})
it("validates required files", function() {
+ // invalid file
param = fromJS({
required: true,
type: "file",
@@ -193,9 +224,48 @@ describe("utils", function(){
})
result = validateParam( param, false )
expect( result ).toEqual( ["Required field is not provided"] )
+
+ // valid file
+ param = fromJS({
+ required: true,
+ type: "file",
+ value: new win.File()
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+ })
+
+ it("validates optional files", function() {
+ // invalid file
+ param = fromJS({
+ required: false,
+ type: "file",
+ value: "not a file"
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( ["Value must be a file"] )
+
+ // valid (empty) file
+ param = fromJS({
+ required: false,
+ type: "file",
+ value: undefined
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+
+ // valid file
+ param = fromJS({
+ required: false,
+ type: "file",
+ value: new win.File()
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
})
it("validates required arrays", function() {
+ // invalid (empty) array
param = fromJS({
required: true,
type: "array",
@@ -204,75 +274,51 @@ describe("utils", function(){
result = validateParam( param, false )
expect( result ).toEqual( ["Required field is not provided"] )
+ // invalid (not an array)
param = fromJS({
required: true,
type: "array",
- value: []
+ value: undefined
})
result = validateParam( param, false )
expect( result ).toEqual( ["Required field is not provided"] )
- })
- it("validates numbers", function() {
- // string instead of a number
+ // invalid array, items do not match correct type
param = fromJS({
- required: false,
- type: "number",
- value: "test"
+ required: true,
+ type: "array",
+ value: [1],
+ items: {
+ type: "string"
+ }
})
result = validateParam( param, false )
- expect( result ).toEqual( ["Value must be a number"] )
+ expect( result ).toEqual( [{index: 0, error: "Value must be a string"}] )
- // undefined value
+ // valid array, with no 'type' for items
param = fromJS({
- required: false,
- type: "number",
- value: undefined
+ required: true,
+ type: "array",
+ value: ["1"]
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
- // null value
+ // valid array, items match type
param = fromJS({
- required: false,
- type: "number",
- value: null
+ required: true,
+ type: "array",
+ value: ["1"],
+ items: {
+ type: "string"
+ }
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
})
- it("validates integers", function() {
- // string instead of integer
- param = fromJS({
- required: false,
- type: "integer",
- value: "test"
- })
- result = validateParam( param, false )
- expect( result ).toEqual( ["Value must be an integer"] )
-
- // undefined value
- param = fromJS({
- required: false,
- type: "integer",
- value: undefined
- })
- result = validateParam( param, false )
- expect( result ).toEqual( [] )
-
- // null value
- param = fromJS({
- required: false,
- type: "integer",
- value: null
- })
- result = validateParam( param, false )
- expect( result ).toEqual( [] )
- })
-
- it("validates arrays", function() {
- // empty array
+ it("validates optional arrays", function() {
+ // valid, empty array
param = fromJS({
required: false,
type: "array",
@@ -281,7 +327,7 @@ describe("utils", function(){
result = validateParam( param, false )
expect( result ).toEqual( [] )
- // numbers
+ // invalid, items do not match correct type
param = fromJS({
required: false,
type: "array",
@@ -293,17 +339,236 @@ describe("utils", function(){
result = validateParam( param, false )
expect( result ).toEqual( [{index: 0, error: "Value must be a number"}] )
- // integers
+ // valid
param = fromJS({
required: false,
type: "array",
- value: ["not", "numbers"],
+ value: ["test"],
items: {
- type: "integer"
+ type: "string"
}
})
result = validateParam( param, false )
- expect( result ).toEqual( [{index: 0, error: "Value must be an integer"}, {index: 1, error: "Value must be an integer"}] )
+ expect( result ).toEqual( [] )
+ })
+
+ it("validates required booleans", function() {
+ // invalid boolean value
+ param = fromJS({
+ required: true,
+ type: "boolean",
+ value: undefined
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( ["Required field is not provided"] )
+
+ // invalid boolean value (not a boolean)
+ param = fromJS({
+ required: true,
+ type: "boolean",
+ value: "test string"
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( ["Required field is not provided"] )
+
+ // valid boolean value
+ param = fromJS({
+ required: true,
+ type: "boolean",
+ value: "true"
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+
+ // valid boolean value
+ param = fromJS({
+ required: true,
+ type: "boolean",
+ value: false
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+ })
+
+ it("validates optional booleans", function() {
+ // valid (empty) boolean value
+ param = fromJS({
+ required: false,
+ type: "boolean",
+ value: undefined
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+
+ // invalid boolean value (not a boolean)
+ param = fromJS({
+ required: false,
+ type: "boolean",
+ value: "test string"
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( ["Value must be a boolean"] )
+
+ // valid boolean value
+ param = fromJS({
+ required: false,
+ type: "boolean",
+ value: "true"
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+
+ // valid boolean value
+ param = fromJS({
+ required: false,
+ type: "boolean",
+ value: false
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+ })
+
+ it("validates required numbers", function() {
+ // invalid number, string instead of a number
+ param = fromJS({
+ required: true,
+ type: "number",
+ value: "test"
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( ["Required field is not provided"] )
+
+ // invalid number, undefined value
+ param = fromJS({
+ required: true,
+ type: "number",
+ value: undefined
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( ["Required field is not provided"] )
+
+ // valid number
+ param = fromJS({
+ required: true,
+ type: "number",
+ value: 10
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+ })
+
+ it("validates optional numbers", function() {
+ // invalid number, string instead of a number
+ param = fromJS({
+ required: false,
+ type: "number",
+ value: "test"
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( ["Value must be a number"] )
+
+ // valid (empty) number
+ param = fromJS({
+ required: false,
+ type: "number",
+ value: undefined
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+
+ // valid number
+ param = fromJS({
+ required: false,
+ type: "number",
+ value: 10
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+ })
+
+ it("validates required integers", function() {
+ // invalid integer, string instead of an integer
+ param = fromJS({
+ required: true,
+ type: "integer",
+ value: "test"
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( ["Required field is not provided"] )
+
+ // invalid integer, undefined value
+ param = fromJS({
+ required: true,
+ type: "integer",
+ value: undefined
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( ["Required field is not provided"] )
+
+ // valid integer
+ param = fromJS({
+ required: true,
+ type: "integer",
+ value: 10
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+ })
+
+ it("validates optional integers", function() {
+ // invalid integer, string instead of an integer
+ param = fromJS({
+ required: false,
+ type: "integer",
+ value: "test"
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( ["Value must be an integer"] )
+
+ // valid (empty) integer
+ param = fromJS({
+ required: false,
+ type: "integer",
+ value: undefined
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
+
+ // valid number
+ param = fromJS({
+ required: false,
+ type: "integer",
+ value: 10
+ })
+ result = validateParam( param, false )
+ expect( result ).toEqual( [] )
})
})
+
+ describe("fromJSOrdered", () => {
+ it("should create an OrderedMap from an object", () => {
+ const param = {
+ value: "test"
+ }
+
+ const result = fromJSOrdered(param).toJS()
+ expect( result ).toEqual( { value: "test" } )
+ })
+
+ it("should not use an object's length property for Map size", () => {
+ const param = {
+ length: 5
+ }
+
+ const result = fromJSOrdered(param).toJS()
+ expect( result ).toEqual( { length: 5 } )
+ })
+
+ it("should create an OrderedMap from an array", () => {
+ const param = [1, 1, 2, 3, 5, 8]
+
+ const result = fromJSOrdered(param).toJS()
+ expect( result ).toEqual( [1, 1, 2, 3, 5, 8] )
+ })
+ })
})
|