Merge branch 'master' into include-apis-preset-by-default

This commit is contained in:
shockey
2017-07-15 09:27:27 -07:00
committed by GitHub
29 changed files with 342 additions and 76 deletions

View File

@@ -22,7 +22,7 @@ The OpenAPI Specification has undergone 4 revisions since initial creation in 20
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes | Status Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes | Status
------------------ | ------------ | -------------------------- | ----- | ------ ------------------ | ------------ | -------------------------- | ----- | ------
3.0.18 | 2017-07-07 | 2.0 | [tag v3.0.18](https://github.com/swagger-api/swagger-ui/tree/v3.0.18) | 3.0.19 | 2017-07-14 | 2.0 | [tag v3.0.19](https://github.com/swagger-api/swagger-ui/tree/v3.0.19) |
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10) | 2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10) |
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5) | 2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5) |
2.0.24 | 2014-09-12 | 1.1, 1.2 | [tag v2.0.24](https://github.com/swagger-api/swagger-ui/tree/v2.0.24) | 2.0.24 | 2014-09-12 | 1.1, 1.2 | [tag v2.0.24](https://github.com/swagger-api/swagger-ui/tree/v2.0.24) |
@@ -67,7 +67,6 @@ To help with the migration, here are the currently known issues with 3.X. This l
- Only part of the [parameters](#parameters) previously supported are available. - Only part of the [parameters](#parameters) previously supported are available.
- The JSON Form Editor is not implemented. - The JSON Form Editor is not implemented.
- Shebang URL support for operations is missing.
- Support for `collectionFormat` is partial. - Support for `collectionFormat` is partial.
- l10n (translations) is not implemented. - l10n (translations) is not implemented.
- Relative path support for external files is not implemented. - Relative path support for external files is not implemented.

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AAsyKA;;;;;;AA8qEA;;;;;;;;;;;;;;;;;;;;;;;;;;AA6nTA;;;;;;;;;;;;;;AAu8JA;;;;;;;;;AAkgnBA;;;;;AAigQA;;;;;;AAqpVA","sourceRoot":""} {"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AAsyKA;;;;;;AAktEA;;;;;;;;;;;;;;;;;;;;;;;;;;AAkqTA;;;;;;;;;;;;;;AAs8JA;;;;;;;;;AA4tnBA;;;;;AAmpQA;;;;;;AA+mXA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA40CA;;;;;;AA4kFA","sourceRoot":""} {"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA40CA;;;;;;AAqlFA","sourceRoot":""}

2
dist/swagger-ui.css vendored

File diff suppressed because one or more lines are too long

4
dist/swagger-ui.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAopaA","sourceRoot":""} {"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAk/aA","sourceRoot":""}

36
docs/deep-linking.md Normal file
View File

@@ -0,0 +1,36 @@
# Deep linking
Swagger-UI allows you to deeply link into tags and operations within a spec. When Swagger-UI is provided a URL fragment at runtime, it will automatically expand and scroll to a specified tag or operation.
## Usage
👉🏼 Add `deepLinking: true` to your Swagger-UI configuration to enable this functionality.
When you expand a tag or operation, Swagger-UI will automatically update its URL fragment with a deep link to the item.
Conversely, when you collapse a tag or operation, Swagger-UI will clear the URL fragment.
You can also right-click a tag name or operation path in order to copy a link to that tag or operation.
#### Fragment format
The fragment is formatted in one of two ways:
- `#/{tagName}`, to trigger the focus of a specific tag
- `#/{tagName}/{operationId}`, to trigger the focus of a specific operation within a tag
`operationId` is the explicit operationId provided in the spec, if one exists.
Otherwise, Swagger-UI generates an implicit operationId by combining the operation's path and method, and escaping non-alphanumeric characters.
## FAQ
> I'm using Swagger-UI in an application that needs control of the URL fragment. How do I disable deep-linking?
This functionality is disabled by default, but you can pass `deepLinking: false` into Swagger-UI as a configuration item to be sure.
> Can I link to multiple tags or operations?
No, this is not supported.
> Can I collapse everything except the operation or tag I'm linking to?
Sure - use `docExpansion: none` to collapse all tags and operations. Your deep link will take precedence over the setting, so only the tag or operation you've specified will be expanded.

View File

@@ -1,6 +1,6 @@
{ {
"name": "swagger-ui", "name": "swagger-ui",
"version": "3.0.18", "version": "3.0.19",
"main": "dist/swagger-ui.js", "main": "dist/swagger-ui.js",
"repository": "git@github.com:swagger-api/swagger-ui.git", "repository": "git@github.com:swagger-api/swagger-ui.git",
"contributors": [ "contributors": [
@@ -68,9 +68,10 @@
"redux-logger": "*", "redux-logger": "*",
"reselect": "2.5.3", "reselect": "2.5.3",
"sanitize-html": "^1.14.1", "sanitize-html": "^1.14.1",
"scroll-to-element": "^2.0.0",
"serialize-error": "2.0.0", "serialize-error": "2.0.0",
"shallowequal": "0.2.2", "shallowequal": "0.2.2",
"swagger-client": "3.0.17", "swagger-client": "3.0.18",
"url-parse": "^1.1.8", "url-parse": "^1.1.8",
"whatwg-fetch": "0.11.1", "whatwg-fetch": "0.11.1",
"worker-loader": "^0.7.1", "worker-loader": "^0.7.1",

View File

@@ -17,16 +17,19 @@ export default class ArrayModel extends Component {
render(){ render(){
let { getComponent, required, schema, depth, expandDepth } = this.props let { getComponent, required, schema, depth, expandDepth } = this.props
let items = schema.get("items") let items = schema.get("items")
let title = schema.get("title") || name
let properties = schema.filter( ( v, key) => ["type", "items", "$$ref"].indexOf(key) === -1 ) let properties = schema.filter( ( v, key) => ["type", "items", "$$ref"].indexOf(key) === -1 )
const ModelCollapse = getComponent("ModelCollapse") const ModelCollapse = getComponent("ModelCollapse")
const Model = getComponent("Model") const Model = getComponent("Model")
return <span className="model"> const titleEl = title &&
<span className="model-title"> <span className="model-title">
<span className="model-title__text">{ schema.get("title") }</span> <span className="model-title__text">{ title }</span>
</span> </span>
<ModelCollapse collapsed={ depth > expandDepth } collapsedContent="[...]">
return <span className="model">
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent="[...]">
[ [
<span><Model { ...this.props } schema={ items } required={ false }/></span> <span><Model { ...this.props } schema={ items } required={ false }/></span>
] ]

View File

@@ -5,12 +5,14 @@ export default class ModelCollapse extends Component {
static propTypes = { static propTypes = {
collapsedContent: PropTypes.any, collapsedContent: PropTypes.any,
collapsed: PropTypes.bool, collapsed: PropTypes.bool,
children: PropTypes.any children: PropTypes.any,
title: PropTypes.element
} }
static defaultProps = { static defaultProps = {
collapsedContent: "{...}", collapsedContent: "{...}",
collapsed: true, collapsed: true,
title: null
} }
constructor(props, context) { constructor(props, context) {
@@ -31,11 +33,15 @@ export default class ModelCollapse extends Component {
} }
render () { render () {
return (<span> const {title} = this.props
return (
<span>
{ title && <span onClick={this.toggleCollapsed} style={{ "cursor": "pointer" }}>{title}</span> }
<span onClick={ this.toggleCollapsed } style={{ "cursor": "pointer" }}> <span onClick={ this.toggleCollapsed } style={{ "cursor": "pointer" }}>
<span className={ "model-toggle" + ( this.state.collapsed ? " collapsed" : "" ) }></span> <span className={ "model-toggle" + ( this.state.collapsed ? " collapsed" : "" ) }></span>
</span> </span>
{ this.state.collapsed ? this.state.collapsedContent : this.props.children } { this.state.collapsed ? this.state.collapsedContent : this.props.children }
</span>) </span>
)
} }
} }

View File

@@ -28,7 +28,7 @@ export default class Models extends Component {
<use xlinkHref="#large-arrow" /> <use xlinkHref="#large-arrow" />
</svg> </svg>
</h4> </h4>
<Collapse isOpened={showModels} animated> <Collapse isOpened={showModels}>
{ {
definitions.entrySeq().map( ( [ name, model ])=>{ definitions.entrySeq().map( ( [ name, model ])=>{
return <div className="model-container" key={ `models-section-${name}` }> return <div className="model-container" key={ `models-section-${name}` }>

View File

@@ -38,15 +38,13 @@ export default class ObjectModel extends Component {
} }
</span>) </span>)
const titleEl = title && <span className="model-title">
return <span className="model">
{
title && <span className="model-title">
{ isRef && schema.get("$$ref") && <span className="model-hint">{ schema.get("$$ref") }</span> } { isRef && schema.get("$$ref") && <span className="model-hint">{ schema.get("$$ref") }</span> }
<span className="model-title__text">{ title }</span> <span className="model-title__text">{ title }</span>
</span> </span>
}
<ModelCollapse collapsed={ depth > expandDepth } collapsedContent={ collapsedContent }> return <span className="model">
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent={ collapsedContent }>
<span className="brace-open object">{ braceOpen }</span> <span className="brace-open object">{ braceOpen }</span>
{ {
!isRef ? null : <JumpToPathSection name={ name }/> !isRef ? null : <JumpToPathSection name={ name }/>

View File

@@ -116,7 +116,8 @@ export default class Operation extends PureComponent {
specActions, specActions,
specSelectors, specSelectors,
authActions, authActions,
authSelectors authSelectors,
getConfigs
} = this.props } = this.props
let summary = operation.get("summary") let summary = operation.get("summary")
@@ -141,6 +142,10 @@ export default class Operation extends PureComponent {
const Markdown = getComponent( "Markdown" ) const Markdown = getComponent( "Markdown" )
const Schemes = getComponent( "schemes" ) const Schemes = getComponent( "schemes" )
const { deepLinking } = getConfigs()
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
// Merge in Live Response // Merge in Live Response
if(response && response.size > 0) { if(response && response.size > 0) {
let notDocumented = !responses.get(String(response.get("status"))) let notDocumented = !responses.get(String(response.get("status")))
@@ -152,11 +157,16 @@ export default class Operation extends PureComponent {
let onChangeKey = [ path, method ] // Used to add values to _this_ operation ( indexed by path and method ) let onChangeKey = [ path, method ] // Used to add values to _this_ operation ( indexed by path and method )
return ( return (
<div className={deprecated ? "opblock opblock-deprecated" : shown ? `opblock opblock-${method} is-open` : `opblock opblock-${method}`} id={isShownKey} > <div className={deprecated ? "opblock opblock-deprecated" : shown ? `opblock opblock-${method} is-open` : `opblock opblock-${method}`} id={isShownKey.join("-")} >
<div className={`opblock-summary opblock-summary-${method}`} onClick={this.toggleShown} > <div className={`opblock-summary opblock-summary-${method}`} onClick={this.toggleShown} >
<span className="opblock-summary-method">{method.toUpperCase()}</span> <span className="opblock-summary-method">{method.toUpperCase()}</span>
<span className={ deprecated ? "opblock-summary-path__deprecated" : "opblock-summary-path" } > <span className={ deprecated ? "opblock-summary-path__deprecated" : "opblock-summary-path" } >
<a
className="nostyle"
onClick={(e) => e.preventDefault()}
href={ isDeepLinkingEnabled ? `#/${isShownKey[1]}/${isShownKey[2]}` : ""} >
<span>{path}</span> <span>{path}</span>
</a>
<JumpToPath path={jumpToKey} /> <JumpToPath path={jumpToKey} />
</span> </span>
@@ -191,7 +201,9 @@ export default class Operation extends PureComponent {
<div className="opblock-external-docs-wrapper"> <div className="opblock-external-docs-wrapper">
<h4 className="opblock-title_normal">Find more details</h4> <h4 className="opblock-title_normal">Find more details</h4>
<div className="opblock-external-docs"> <div className="opblock-external-docs">
<span className="opblock-external-docs__description">{ externalDocs.get("description") }</span> <span className="opblock-external-docs__description">
<Markdown source={ externalDocs.get("description") } />
</span>
<a className="opblock-external-docs__link" href={ externalDocs.get("url") }>{ externalDocs.get("url") }</a> <a className="opblock-external-docs__link" href={ externalDocs.get("url") }>{ externalDocs.get("url") }</a>
</div> </div>
</div> : null </div> : null

View File

@@ -1,5 +1,8 @@
import React from "react" import React from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import { helpers } from "swagger-client"
const { opId } = helpers
export default class Operations extends React.Component { export default class Operations extends React.Component {
@@ -33,7 +36,15 @@ export default class Operations extends React.Component {
const Collapse = getComponent("Collapse") const Collapse = getComponent("Collapse")
let showSummary = layoutSelectors.showSummary() let showSummary = layoutSelectors.showSummary()
let { docExpansion, displayOperationId, displayRequestDuration, maxDisplayedTags } = getConfigs() let {
docExpansion,
displayOperationId,
displayRequestDuration,
maxDisplayedTags,
deepLinking
} = getConfigs()
const isDeepLinkingEnabled = deepLinking && deepLinking !== "false"
let filter = layoutSelectors.currentFilter() let filter = layoutSelectors.currentFilter()
@@ -62,8 +73,16 @@ export default class Operations extends React.Component {
return ( return (
<div className={showTag ? "opblock-tag-section is-open" : "opblock-tag-section"} key={"operation-" + tag}> <div className={showTag ? "opblock-tag-section is-open" : "opblock-tag-section"} key={"operation-" + tag}>
<h4 onClick={() => layoutActions.show(isShownKey, !showTag)} className={!tagDescription ? "opblock-tag no-desc" : "opblock-tag" }> <h4
onClick={() => layoutActions.show(isShownKey, !showTag)}
className={!tagDescription ? "opblock-tag no-desc" : "opblock-tag" }
id={isShownKey.join("-")}>
<a
className="nostyle"
onClick={(e) => e.preventDefault()}
href={ isDeepLinkingEnabled ? `#/${tag}` : ""}>
<span>{tag}</span> <span>{tag}</span>
</a>
{ !tagDescription ? null : { !tagDescription ? null :
<small> <small>
{ tagDescription } { tagDescription }
@@ -81,11 +100,14 @@ export default class Operations extends React.Component {
{ {
operations.map( op => { operations.map( op => {
const isShownKey = ["operations", op.get("id"), tag]
const path = op.get("path", "") const path = op.get("path", "")
const method = op.get("method", "") const method = op.get("method", "")
const jumpToKey = `paths.${path}.${method}` const jumpToKey = `paths.${path}.${method}`
const operationId =
op.getIn(["operation", "operationId"]) || op.getIn(["operation", "__originalOperationId"]) || opId(op.get("operation"), path, method) || op.get("id")
const isShownKey = ["operations", tag, operationId]
const allowTryItOut = specSelectors.allowTryItOutFor(op.get("path"), op.get("method")) const allowTryItOut = specSelectors.allowTryItOutFor(op.get("path"), op.get("method"))
const response = specSelectors.responseFor(op.get("path"), op.get("method")) const response = specSelectors.responseFor(op.get("path"), op.get("method"))
const request = specSelectors.requestFor(op.get("path"), op.get("method")) const request = specSelectors.requestFor(op.get("path"), op.get("method"))

View File

@@ -18,10 +18,12 @@ function Markdown({ source }) {
return null return null
} }
return <Remarkable return <div className="markdown">
options={{html: true, typographer: true, linkify: true, linkTarget: "_blank"}} <Remarkable
options={{html: true, typographer: true, breaks: true, linkify: true, linkTarget: "_blank"}}
source={sanitized} source={sanitized}
></Remarkable> ></Remarkable>
</div>
} }
Markdown.propTypes = { Markdown.propTypes = {

View File

@@ -30,6 +30,7 @@ const CONFIGS = [
"parameterMacro", "parameterMacro",
"displayOperationId", "displayOperationId",
"displayRequestDuration", "displayRequestDuration",
"deepLinking",
] ]
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
@@ -61,6 +62,7 @@ module.exports = function SwaggerUI(opts) {
custom: {}, custom: {},
displayOperationId: false, displayOperationId: false,
displayRequestDuration: false, displayRequestDuration: false,
deepLinking: false,
// Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance. // Initial set of plugins ( TODO rename this, or refactor - we don't need presets _and_ plugins. Its just there for performance.
// Instead, we can compile the first plugin ( it can be a collection of plugins ), then batch the rest. // Instead, we can compile the first plugin ( it can be a collection of plugins ), then batch the rest.

View File

@@ -0,0 +1 @@
See `docs/deep-linking.md`.

View File

@@ -0,0 +1,7 @@
export const setHash = (value) => {
if(value) {
return history.pushState(null, null, `#${value}`)
} else {
return window.location.hash = ""
}
}

View File

@@ -0,0 +1,18 @@
// import reducers from "./reducers"
// import * as actions from "./actions"
// import * as selectors from "./selectors"
import * as specWrapActions from "./spec-wrap-actions"
import * as layoutWrapActions from "./layout-wrap-actions"
export default function() {
return {
statePlugins: {
spec: {
wrapActions: specWrapActions
},
layout: {
wrapActions: layoutWrapActions
}
}
}
}

View File

@@ -0,0 +1,36 @@
import { setHash } from "./helpers"
export const show = (ori, { getConfigs }) => (...args) => {
ori(...args)
const isDeepLinkingEnabled = getConfigs().deepLinking
if(!isDeepLinkingEnabled || isDeepLinkingEnabled === "false") {
return
}
try {
let [thing, shown] = args
let [type] = thing
if(type === "operations-tag" || type === "operations") {
if(!shown) {
return setHash("/")
}
if(type === "operations") {
let [, tag, operationId] = thing
setHash(`/${tag}/${operationId}`)
}
if(type === "operations-tag") {
let [, tag] = thing
setHash(`/${tag}`)
}
}
} catch(e) {
// This functionality is not mission critical, so if something goes wrong
// we'll just move on
console.error(e)
}
}

View File

@@ -0,0 +1,51 @@
import scrollTo from "scroll-to-element"
const SCROLL_OFFSET = -5
let hasHashBeenParsed = false
export const updateResolved = (ori, { layoutActions, getConfigs }) => (...args) => {
ori(...args)
const isDeepLinkingEnabled = getConfigs().deepLinking
if(!isDeepLinkingEnabled || isDeepLinkingEnabled === "false") {
return
}
if(window.location.hash && !hasHashBeenParsed ) {
let hash = window.location.hash.slice(1) // # is first character
if(hash[0] === "!") {
// Parse UI 2.x shebangs
hash = hash.slice(1)
}
if(hash[0] === "/") {
// "/pet/addPet" => "pet/addPet"
// makes the split result cleaner
// also handles forgotten leading slash
hash = hash.slice(1)
}
let [tag, operationId] = hash.split("/")
if(tag && operationId) {
// Pre-expand and scroll to the operation
layoutActions.show(["operations-tag", tag], true)
layoutActions.show(["operations", tag, operationId], true)
scrollTo(`#operations-${tag}-${operationId}`, {
offset: SCROLL_OFFSET
})
} else if(tag) {
// Pre-expand and scroll to the tag
layoutActions.show(["operations-tag", tag], true)
scrollTo(`#operations-tag-${tag}`, {
offset: SCROLL_OFFSET
})
}
}
hasHashBeenParsed = true
}

View File

@@ -10,6 +10,7 @@ import auth from "core/plugins/auth"
import util from "core/plugins/util" import util from "core/plugins/util"
import SplitPaneModePlugin from "core/plugins/split-pane-mode" import SplitPaneModePlugin from "core/plugins/split-pane-mode"
import downloadUrlPlugin from "core/plugins/download-url" import downloadUrlPlugin from "core/plugins/download-url"
import deepLinkingPlugin from "core/plugins/deep-linking"
import App from "core/components/app" import App from "core/components/app"
import AuthorizationPopup from "core/components/auth/authorization-popup" import AuthorizationPopup from "core/components/auth/authorization-popup"
@@ -131,6 +132,7 @@ export default function() {
auth, auth,
ast, ast,
SplitPaneModePlugin, SplitPaneModePlugin,
downloadUrlPlugin downloadUrlPlugin,
deepLinkingPlugin
] ]
} }

View File

@@ -451,13 +451,13 @@ export const propChecker = (props, nextProps, objectList=[], ignoreList=[]) => {
} }
export const validateNumber = ( val ) => { export const validateNumber = ( val ) => {
if ( !/^-?\d+(\.?\d+)?$/.test(val)) { if (!/^-?\d+(\.?\d+)?$/.test(val)) {
return "Value must be a number" return "Value must be a number"
} }
} }
export const validateInteger = ( val ) => { export const validateInteger = ( val ) => {
if ( !/^-?\d+$/.test(val)) { if (!/^-?\d+$/.test(val)) {
return "Value must be an integer" return "Value must be an integer"
} }
} }
@@ -485,6 +485,10 @@ export const validateParam = (param, isXml) => {
return errors return errors
} }
if ( value === null || value === undefined ) {
return errors
}
if ( type === "number" ) { if ( type === "number" ) {
let err = validateNumber(value) let err = validateNumber(value)
if (!err) return errors if (!err) return errors

View File

@@ -390,6 +390,7 @@ body
} }
.opblock-description-wrapper, .opblock-description-wrapper,
.opblock-external-docs-wrapper,
.opblock-title_normal .opblock-title_normal
{ {
font-size: 12px; font-size: 12px;
@@ -418,6 +419,12 @@ body
} }
} }
.opblock-external-docs-wrapper {
h4 {
padding-left: 0px;
}
}
.execute-wrapper .execute-wrapper
{ {
padding: 20px; padding: 20px;
@@ -644,3 +651,16 @@ section
@include text_headline(); @include text_headline();
} }
} }
a.nostyle {
text-decoration: inherit;
color: inherit;
cursor: auto;
display: inline;
&:visited {
text-decoration: inherit;
color: inherit;
cursor: auto;
}
}

View File

@@ -79,6 +79,10 @@
border-radius: 4px; border-radius: 4px;
background: rgba(#000,.7); background: rgba(#000,.7);
} }
p {
margin: 0 0 1em 0;
}
} }

View File

@@ -10,4 +10,8 @@ try {
// for more information. // for more information.
} }
// `absolutePath` and `getAbsoluteFSPath` are both here because at one point,
// we documented having one and actually implemented the other.
// They were both retained so we don't break anyone's code.
module.exports.absolutePath = require("./absolute-path.js") module.exports.absolutePath = require("./absolute-path.js")
module.exports.getAbsoluteFSPath = require("./absolute-path.js")

View File

@@ -214,6 +214,7 @@ describe("utils", function(){
}) })
it("validates numbers", function() { it("validates numbers", function() {
// string instead of a number
param = fromJS({ param = fromJS({
required: false, required: false,
type: "number", type: "number",
@@ -221,9 +222,28 @@ describe("utils", function(){
}) })
result = validateParam( param, false ) result = validateParam( param, false )
expect( result ).toEqual( ["Value must be a number"] ) expect( result ).toEqual( ["Value must be a number"] )
// undefined value
param = fromJS({
required: false,
type: "number",
value: undefined
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
// null value
param = fromJS({
required: false,
type: "number",
value: null
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
}) })
it("validates integers", function() { it("validates integers", function() {
// string instead of integer
param = fromJS({ param = fromJS({
required: false, required: false,
type: "integer", type: "integer",
@@ -231,6 +251,24 @@ describe("utils", function(){
}) })
result = validateParam( param, false ) result = validateParam( param, false )
expect( result ).toEqual( ["Value must be an integer"] ) 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() { it("validates arrays", function() {