Example (#4730)
* add tests for example feature * refactor ParameterRow value setter logic * aside: fix property access in sampleFromSchema * prioritize media type examples for OAS3 responses * use `example` in schema level example * refactor: move stringify to utils * prioritize media type examples in OAS3 request bodies * modify nightwatch config * fix parameter/response regressions * reorder and broaden default value sources * update lockfile
This commit is contained in:
43
package-lock.json
generated
43
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "swagger-ui",
|
"name": "swagger-ui",
|
||||||
"version": "3.17.2",
|
"version": "3.17.3",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -3755,6 +3755,12 @@
|
|||||||
"mimic-response": "^1.0.0"
|
"mimic-response": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dedent": {
|
||||||
|
"version": "0.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
|
||||||
|
"integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"deep-eql": {
|
"deep-eql": {
|
||||||
"version": "0.1.3",
|
"version": "0.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz",
|
||||||
@@ -4543,6 +4549,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"eslint-plugin-import": {
|
||||||
|
"version": "2.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz",
|
||||||
|
"integrity": "sha512-t6hGKQDMIt9N8R7vLepsYXgDfeuhp6ZJSgtrLEDxonpSubyxUZHjhm6LsAaZX8q6GYVxkbT3kTsV9G5mBCFR6A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"contains-path": "^0.1.0",
|
||||||
|
"debug": "^2.6.8",
|
||||||
|
"doctrine": "1.5.0",
|
||||||
|
"eslint-import-resolver-node": "^0.3.1",
|
||||||
|
"eslint-module-utils": "^2.2.0",
|
||||||
|
"has": "^1.0.1",
|
||||||
|
"lodash": "^4.17.4",
|
||||||
|
"minimatch": "^3.0.3",
|
||||||
|
"read-pkg-up": "^2.0.0",
|
||||||
|
"resolve": "^1.6.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"doctrine": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
|
||||||
|
"integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"esutils": "^2.0.2",
|
||||||
|
"isarray": "^1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"eslint-plugin-mocha": {
|
"eslint-plugin-mocha": {
|
||||||
"version": "4.12.1",
|
"version": "4.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-4.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-4.12.1.tgz",
|
||||||
@@ -16494,6 +16530,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||||
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
|
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
|
||||||
},
|
},
|
||||||
|
"reselect": {
|
||||||
|
"version": "2.5.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/reselect/-/reselect-2.5.4.tgz",
|
||||||
|
"integrity": "sha1-t9I/3wC4P6etAnlUb427vXZccEc="
|
||||||
|
},
|
||||||
"resolve": {
|
"resolve": {
|
||||||
"version": "1.7.1",
|
"version": "1.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
|
||||||
|
|||||||
@@ -98,6 +98,7 @@
|
|||||||
"chromedriver": "^2.38.3",
|
"chromedriver": "^2.38.3",
|
||||||
"copy-webpack-plugin": "^4.0.1",
|
"copy-webpack-plugin": "^4.0.1",
|
||||||
"css-loader": "^0.28.11",
|
"css-loader": "^0.28.11",
|
||||||
|
"dedent": "^0.7.0",
|
||||||
"deepmerge": "^2.1.0",
|
"deepmerge": "^2.1.0",
|
||||||
"enzyme": "^2.7.1",
|
"enzyme": "^2.7.1",
|
||||||
"eslint": "^4.1.1",
|
"eslint": "^4.1.1",
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export default class ParamBody extends PureComponent {
|
|||||||
let { value, isEditBox } = this.state
|
let { value, isEditBox } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="body-param">
|
<div className="body-param" data-param-name={param.get("name")} data-param-in={param.get("in")}>
|
||||||
{
|
{
|
||||||
isEditBox && isExecute
|
isEditBox && isExecute
|
||||||
? <TextArea className={ "body-param__text" + ( errors.count() ? " invalid" : "")} value={value} onChange={ this.handleOnChange }/>
|
? <TextArea className={ "body-param__text" + ( errors.count() ? " invalid" : "")} value={value} onChange={ this.handleOnChange }/>
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ export default class ParameterRow extends Component {
|
|||||||
let { specSelectors, pathMethod, rawParam } = props
|
let { specSelectors, pathMethod, rawParam } = props
|
||||||
let { isOAS3 } = specSelectors
|
let { isOAS3 } = specSelectors
|
||||||
|
|
||||||
let example = rawParam.get("example")
|
|
||||||
|
|
||||||
let parameterWithMeta = specSelectors.parameterWithMetaByIdentity(pathMethod, rawParam)
|
let parameterWithMeta = specSelectors.parameterWithMetaByIdentity(pathMethod, rawParam)
|
||||||
// fallback, if the meta lookup fails
|
// fallback, if the meta lookup fails
|
||||||
parameterWithMeta = parameterWithMeta.isEmpty() ? rawParam : parameterWithMeta
|
parameterWithMeta = parameterWithMeta.isEmpty() ? rawParam : parameterWithMeta
|
||||||
@@ -39,7 +37,7 @@ export default class ParameterRow extends Component {
|
|||||||
let enumValue
|
let enumValue
|
||||||
|
|
||||||
if(isOAS3()) {
|
if(isOAS3()) {
|
||||||
let schema = rawParam.get("schema") || Map()
|
let schema = parameterWithMeta.get("schema") || Map()
|
||||||
enumValue = schema.get("enum")
|
enumValue = schema.get("enum")
|
||||||
} else {
|
} else {
|
||||||
enumValue = parameterWithMeta ? parameterWithMeta.get("enum") : undefined
|
enumValue = parameterWithMeta ? parameterWithMeta.get("enum") : undefined
|
||||||
@@ -50,15 +48,15 @@ export default class ParameterRow extends Component {
|
|||||||
|
|
||||||
if ( paramValue !== undefined ) {
|
if ( paramValue !== undefined ) {
|
||||||
value = paramValue
|
value = paramValue
|
||||||
} else if ( example !== undefined ) {
|
|
||||||
value = example
|
|
||||||
} else if ( rawParam.get("required") && enumValue && enumValue.size ) {
|
} else if ( rawParam.get("required") && enumValue && enumValue.size ) {
|
||||||
value = enumValue.first()
|
value = enumValue.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( value !== undefined ) {
|
if ( value !== undefined && value !== paramValue ) {
|
||||||
this.onChangeWrapper(value)
|
this.onChangeWrapper(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setDefaultValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeWrapper = (value, isXml = false) => {
|
onChangeWrapper = (value, isXml = false) => {
|
||||||
@@ -69,22 +67,28 @@ export default class ParameterRow extends Component {
|
|||||||
setDefaultValue = () => {
|
setDefaultValue = () => {
|
||||||
let { specSelectors, pathMethod, rawParam } = this.props
|
let { specSelectors, pathMethod, rawParam } = this.props
|
||||||
|
|
||||||
if (rawParam.get("value") !== undefined) {
|
let paramWithMeta = specSelectors.parameterWithMetaByIdentity(pathMethod, rawParam)
|
||||||
|
|
||||||
|
|
||||||
|
if (paramWithMeta.get("value") !== undefined) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let schema = specSelectors.isOAS3() ? rawParam.get("schema", Map({})) : rawParam
|
if( paramWithMeta.get("in") !== "body" ) {
|
||||||
|
let newValue
|
||||||
|
|
||||||
let defaultValue = schema.get("default")
|
if (specSelectors.isSwagger2()) {
|
||||||
let xExampleValue = rawParam.get("x-example") // Swagger 2 only
|
newValue = paramWithMeta.get("x-example")
|
||||||
let parameter = specSelectors.parameterWithMetaByIdentity(pathMethod, rawParam)
|
|| paramWithMeta.getIn(["default"])
|
||||||
let value = parameter ? parameter.get("value") : ""
|
|| paramWithMeta.getIn(["schema", "example"])
|
||||||
|
|| paramWithMeta.getIn(["schema", "default"])
|
||||||
if( rawParam.get("in") !== "body" ) {
|
} else if (specSelectors.isOAS3()) {
|
||||||
if ( xExampleValue !== undefined && value === undefined && specSelectors.isSwagger2() ) {
|
newValue = paramWithMeta.get("example")
|
||||||
this.onChangeWrapper(xExampleValue)
|
|| paramWithMeta.getIn(["schema", "example"])
|
||||||
} else if ( defaultValue !== undefined && value === undefined ) {
|
|| paramWithMeta.getIn(["schema", "default"])
|
||||||
this.onChangeWrapper(defaultValue)
|
}
|
||||||
|
if(newValue !== undefined) {
|
||||||
|
this.onChangeWrapper(newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,7 +165,7 @@ export default class ParameterRow extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr className="parameters">
|
<tr data-param-name={param.get("name")} data-param-in={param.get("in")}>
|
||||||
<td className="col parameters-col_name">
|
<td className="col parameters-col_name">
|
||||||
<div className={required ? "parameter__name required" : "parameter__name"}>
|
<div className={required ? "parameter__name required" : "parameter__name"}>
|
||||||
{ param.get("name") }
|
{ param.get("name") }
|
||||||
|
|||||||
@@ -2,21 +2,13 @@ import React from "react"
|
|||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import ImPropTypes from "react-immutable-proptypes"
|
import ImPropTypes from "react-immutable-proptypes"
|
||||||
import cx from "classnames"
|
import cx from "classnames"
|
||||||
import { fromJS, Seq, Iterable, List } from "immutable"
|
import { fromJS, Seq, Iterable, List, Map } from "immutable"
|
||||||
import { getSampleSchema, fromJSOrdered } from "core/utils"
|
import { getSampleSchema, fromJSOrdered, stringify } from "core/utils"
|
||||||
|
|
||||||
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
|
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
|
||||||
if ( examples && examples.size ) {
|
if ( examples && examples.size ) {
|
||||||
return examples.entrySeq().map( ([ key, example ]) => {
|
return examples.entrySeq().map( ([ key, example ]) => {
|
||||||
let exampleValue = example
|
let exampleValue = stringify(example)
|
||||||
if ( example.toJS ) {
|
|
||||||
try {
|
|
||||||
exampleValue = JSON.stringify(example.toJS(), null, 2)
|
|
||||||
}
|
|
||||||
catch(e) {
|
|
||||||
exampleValue = String(example)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (<div key={ key }>
|
return (<div key={ key }>
|
||||||
<h5>{ key }</h5>
|
<h5>{ key }</h5>
|
||||||
@@ -97,20 +89,29 @@ export default class Response extends React.Component {
|
|||||||
const ContentType = getComponent("contentType")
|
const ContentType = getComponent("contentType")
|
||||||
|
|
||||||
var sampleResponse
|
var sampleResponse
|
||||||
|
var sampleSchema
|
||||||
var schema, specPathWithPossibleSchema
|
var schema, specPathWithPossibleSchema
|
||||||
|
|
||||||
|
const activeContentType = this.state.responseContentType || contentType
|
||||||
|
|
||||||
if(isOAS3()) {
|
if(isOAS3()) {
|
||||||
const schemaPath = List(["content", this.state.responseContentType, "schema"])
|
const mediaType = response.getIn(["content", activeContentType], Map({}))
|
||||||
const oas3SchemaForContentType = response.getIn(schemaPath)
|
const oas3SchemaForContentType = mediaType.get("schema", Map({}))
|
||||||
sampleResponse = oas3SchemaForContentType ? getSampleSchema(oas3SchemaForContentType.toJS(), this.state.responseContentType, {
|
|
||||||
includeReadOnly: true
|
if(mediaType.get("example") !== undefined) {
|
||||||
}) : null
|
sampleSchema = stringify(mediaType.get("example"))
|
||||||
|
} else {
|
||||||
|
sampleSchema = getSampleSchema(oas3SchemaForContentType.toJS(), this.state.responseContentType, {
|
||||||
|
includeReadOnly: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
sampleResponse = oas3SchemaForContentType ? sampleSchema : null
|
||||||
schema = oas3SchemaForContentType ? inferSchema(oas3SchemaForContentType.toJS()) : null
|
schema = oas3SchemaForContentType ? inferSchema(oas3SchemaForContentType.toJS()) : null
|
||||||
specPathWithPossibleSchema = oas3SchemaForContentType ? schemaPath : specPath
|
specPathWithPossibleSchema = oas3SchemaForContentType ? List(["content", this.state.responseContentType, "schema"]) : specPath
|
||||||
} else {
|
} else {
|
||||||
schema = inferSchema(response.toJS()) // TODO: don't convert back and forth. Lets just stick with immutable for inferSchema
|
schema = inferSchema(response.toJS()) // TODO: don't convert back and forth. Lets just stick with immutable for inferSchema
|
||||||
specPathWithPossibleSchema = response.has("schema") ? specPath.push("schema") : specPath
|
specPathWithPossibleSchema = response.has("schema") ? specPath.push("schema") : specPath
|
||||||
sampleResponse = schema ? getSampleSchema(schema, contentType, {
|
sampleResponse = schema ? getSampleSchema(schema, activeContentType, {
|
||||||
includeReadOnly: true,
|
includeReadOnly: true,
|
||||||
includeWriteOnly: true // writeOnly has no filtering effect in swagger 2.0
|
includeWriteOnly: true // writeOnly has no filtering effect in swagger 2.0
|
||||||
}) : null
|
}) : null
|
||||||
@@ -126,7 +127,7 @@ export default class Response extends React.Component {
|
|||||||
let example = getExampleComponent( sampleResponse, examples, HighlightCode )
|
let example = getExampleComponent( sampleResponse, examples, HighlightCode )
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr className={ "response " + ( className || "") }>
|
<tr className={ "response " + ( className || "") } data-code={code}>
|
||||||
<td className="col response-col_status">
|
<td className="col response-col_status">
|
||||||
{ code }
|
{ code }
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { PureComponent } from "react"
|
import React, { PureComponent } from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import { fromJS } from "immutable"
|
import { fromJS } from "immutable"
|
||||||
import { getSampleSchema } from "core/utils"
|
import { getSampleSchema, stringify } from "core/utils"
|
||||||
|
|
||||||
const NOOP = Function.prototype
|
const NOOP = Function.prototype
|
||||||
|
|
||||||
@@ -67,9 +67,11 @@ export default class RequestBodyEditor extends PureComponent {
|
|||||||
|
|
||||||
sample = (explicitMediaType) => {
|
sample = (explicitMediaType) => {
|
||||||
let { requestBody, mediaType } = this.props
|
let { requestBody, mediaType } = this.props
|
||||||
let schema = requestBody.getIn(["content", explicitMediaType || mediaType, "schema"]).toJS()
|
let mediaTypeValue = requestBody.getIn(["content", explicitMediaType || mediaType])
|
||||||
|
let schema = mediaTypeValue.get("schema").toJS()
|
||||||
|
let mediaTypeExample = mediaTypeValue.get("example") !== undefined ? stringify(mediaTypeValue.get("example")) : null
|
||||||
|
|
||||||
return getSampleSchema(schema, explicitMediaType || mediaType, {
|
return mediaTypeExample || getSampleSchema(schema, explicitMediaType || mediaType, {
|
||||||
includeWriteOnly: true
|
includeWriteOnly: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,10 +52,10 @@ export const sampleFromSchema = (schema, config={}) => {
|
|||||||
let props = objectify(properties)
|
let props = objectify(properties)
|
||||||
let obj = {}
|
let obj = {}
|
||||||
for (var name in props) {
|
for (var name in props) {
|
||||||
if ( props[name].readOnly && !includeReadOnly ) {
|
if ( props[name] && props[name].readOnly && !includeReadOnly ) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ( props[name].writeOnly && !includeWriteOnly ) {
|
if ( props[name] && props[name].writeOnly && !includeWriteOnly ) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
obj[name] = sampleFromSchema(props[name], config)
|
obj[name] = sampleFromSchema(props[name], config)
|
||||||
|
|||||||
@@ -760,3 +760,24 @@ export function deeplyStripKey(input, keyToStrip, predicate = () => true) {
|
|||||||
|
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function stringify(thing) {
|
||||||
|
if (typeof thing === "string") {
|
||||||
|
return thing
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thing.toJS) {
|
||||||
|
thing = thing.toJS()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof thing === "object" && thing !== null) {
|
||||||
|
try {
|
||||||
|
return JSON.stringify(thing, null, 2)
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return String(thing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return thing.toString()
|
||||||
|
}
|
||||||
@@ -19,7 +19,8 @@ describe("bug #4557: default parameter values", function(){
|
|||||||
specSelectors: {
|
specSelectors: {
|
||||||
security(){},
|
security(){},
|
||||||
parameterWithMetaByIdentity(){ return paramValue },
|
parameterWithMetaByIdentity(){ return paramValue },
|
||||||
isOAS3(){ return false }
|
isOAS3(){ return false },
|
||||||
|
isSwagger2(){ return true }
|
||||||
},
|
},
|
||||||
fn: {},
|
fn: {},
|
||||||
operation: {get: ()=>{}},
|
operation: {get: ()=>{}},
|
||||||
@@ -52,7 +53,8 @@ describe("bug #4557: default parameter values", function(){
|
|||||||
specSelectors: {
|
specSelectors: {
|
||||||
security(){},
|
security(){},
|
||||||
parameterWithMetaByIdentity(){ return paramValue },
|
parameterWithMetaByIdentity(){ return paramValue },
|
||||||
isOAS3(){ return true }
|
isOAS3(){ return true },
|
||||||
|
isSwagger2() { return false }
|
||||||
},
|
},
|
||||||
fn: {},
|
fn: {},
|
||||||
operation: {get: ()=>{}},
|
operation: {get: ()=>{}},
|
||||||
|
|||||||
@@ -6,10 +6,6 @@
|
|||||||
"custom_assertions_path" : "",
|
"custom_assertions_path" : "",
|
||||||
"page_objects_path" : "test/e2e/pages",
|
"page_objects_path" : "test/e2e/pages",
|
||||||
"globals_path" : "",
|
"globals_path" : "",
|
||||||
"test_workers" : {
|
|
||||||
"enabled" : true,
|
|
||||||
"workers" : "auto"
|
|
||||||
},
|
|
||||||
|
|
||||||
"test_runner" : {
|
"test_runner" : {
|
||||||
"type" : "mocha",
|
"type" : "mocha",
|
||||||
|
|||||||
240
test/e2e/scenarios/features/example.js
Normal file
240
test/e2e/scenarios/features/example.js
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
const dedent = require("dedent")
|
||||||
|
|
||||||
|
describe("feature: `example` field support", function () {
|
||||||
|
|
||||||
|
describe("Swagger 2", function() {
|
||||||
|
|
||||||
|
beforeEach(function (client, done) {
|
||||||
|
client
|
||||||
|
.url("localhost:3230")
|
||||||
|
.page.main()
|
||||||
|
|
||||||
|
client.waitForElementVisible(".download-url-input:not([disabled])", 5000)
|
||||||
|
.clearValue(".download-url-input")
|
||||||
|
.setValue(".download-url-input", "/test-specs/features/example.swagger.yaml")
|
||||||
|
.click("button.download-url-button")
|
||||||
|
.waitForElementVisible(".opblock", 10000)
|
||||||
|
.click("#operations-default-put_one")
|
||||||
|
.waitForElementVisible("#operations-default-put_one.is-open", 5000)
|
||||||
|
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(function (client, done) {
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
// Supports complex root `example` values in Schema objects for bodies
|
||||||
|
// Supports nested `example` values in Schema objects for bodies
|
||||||
|
|
||||||
|
describe("primitive parameters", function() {
|
||||||
|
it("should respect a primitive x-example value", function (client) {
|
||||||
|
client
|
||||||
|
.click("button.try-out__btn")
|
||||||
|
.assert.value(
|
||||||
|
`tr[data-param-name="ValidParam"] input[type="text"]`,
|
||||||
|
`12345`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it("should ignore a primitive example value", function (client) {
|
||||||
|
client
|
||||||
|
.click("button.try-out__btn")
|
||||||
|
.assert.value(
|
||||||
|
`tr[data-param-name="NotValidParam"] input[type="text"]`,
|
||||||
|
``
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("object parameters", function() {
|
||||||
|
it("should correctly consider property-level schema examples", function(client) {
|
||||||
|
client.assert.containsText(`div[data-param-name="body"] pre`,
|
||||||
|
dedent(`
|
||||||
|
{
|
||||||
|
"one": "hello!",
|
||||||
|
"two": {
|
||||||
|
"uno": "wow!",
|
||||||
|
"dos": "hey there!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it("should correctly consider root schema-level schema examples", function(client) {
|
||||||
|
client.assert.containsText(`div[data-param-name="body2"] pre`,
|
||||||
|
dedent(`
|
||||||
|
{
|
||||||
|
"foo": "hey",
|
||||||
|
"bar": 123
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it("should correctly consider nested schema-level schema examples", function(client) {
|
||||||
|
client.assert.containsText(`div[data-param-name="body3"] pre`,
|
||||||
|
dedent(`
|
||||||
|
{
|
||||||
|
"one": {
|
||||||
|
"uno": "woohoo!",
|
||||||
|
"dos": "amazing!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("responses", function() {
|
||||||
|
it("should correctly consider schema-level examples", function (client) {
|
||||||
|
client.assert.containsText(`tr.response[data-code="201"] pre`,
|
||||||
|
dedent(`
|
||||||
|
{
|
||||||
|
"code": 201,
|
||||||
|
"payload": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"code": "AE2",
|
||||||
|
"name": "Yono"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it("should correctly consider property-level examples", function (client) {
|
||||||
|
client.assert.containsText(`tr.response[data-code="202"] pre`,
|
||||||
|
dedent(`
|
||||||
|
{
|
||||||
|
"code": 202,
|
||||||
|
"payload": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"code": "AE2",
|
||||||
|
"name": "Yono"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe("OpenAPI 3.0", function() {
|
||||||
|
beforeEach(function (client, done) {
|
||||||
|
client
|
||||||
|
.url("localhost:3230")
|
||||||
|
.page.main()
|
||||||
|
|
||||||
|
client.waitForElementVisible(".download-url-input:not([disabled])", 5000)
|
||||||
|
.clearValue(".download-url-input")
|
||||||
|
.setValue(".download-url-input", "/test-specs/features/example.openapi.yaml")
|
||||||
|
.click("button.download-url-button")
|
||||||
|
.waitForElementVisible(".opblock-summary-description", 10000)
|
||||||
|
.click("#operations-agent-editAgent")
|
||||||
|
.waitForElementVisible("#operations-agent-editAgent.is-open", 5000)
|
||||||
|
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("parameters", function() {
|
||||||
|
it("should respect a primitive example value", function(client) {
|
||||||
|
client
|
||||||
|
.click("button.try-out__btn")
|
||||||
|
.assert.value(
|
||||||
|
`div.parameters-container > div > table > tbody > tr > td.col.parameters-col_description > input[type="text"]`,
|
||||||
|
`12345`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("request bodies", function() {
|
||||||
|
it("should correctly consider media type-level examples", function (client) {
|
||||||
|
client
|
||||||
|
.click(`select.content-type option[value="application/json_media-type-level"]`)
|
||||||
|
.assert.containsText(`pre.body-param__example`,
|
||||||
|
dedent(`
|
||||||
|
{
|
||||||
|
"code": "AE1",
|
||||||
|
"name": "Andrew"
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it("should correctly consider schema-level examples", function (client) {
|
||||||
|
client
|
||||||
|
.click(`select.content-type option[value="application/json_schema-level"]`)
|
||||||
|
.assert.containsText(`pre.body-param__example`,
|
||||||
|
dedent(`
|
||||||
|
{
|
||||||
|
"code": "AE1",
|
||||||
|
"name": "Andrew"
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it("should correctly consider property-level examples", function (client) {
|
||||||
|
client
|
||||||
|
.click(`select.content-type option[value="application/json_property-level"]`)
|
||||||
|
.assert.containsText(`pre.body-param__example`,
|
||||||
|
dedent(`
|
||||||
|
{
|
||||||
|
"code": "AE1",
|
||||||
|
"name": "Andrew"
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe("responses", function() {
|
||||||
|
it("should correctly consider media type-level examples", function (client) {
|
||||||
|
client.assert.containsText(`tr.response[data-code="200"] pre`,
|
||||||
|
dedent(`
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"payload": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"code": "AE2",
|
||||||
|
"name": "Yono"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it("should correctly consider schema-level examples", function (client) {
|
||||||
|
client.assert.containsText(`tr.response[data-code="201"] pre`,
|
||||||
|
dedent(`
|
||||||
|
{
|
||||||
|
"code": 201,
|
||||||
|
"payload": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"code": "AE2",
|
||||||
|
"name": "Yono"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
it("should correctly consider property-level examples", function (client) {
|
||||||
|
client.assert.containsText(`tr.response[data-code="202"] pre`,
|
||||||
|
dedent(`
|
||||||
|
{
|
||||||
|
"code": 202,
|
||||||
|
"payload": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"code": "AE2",
|
||||||
|
"name": "Yono"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
156
test/e2e/specs/features/example.openapi.yaml
Normal file
156
test/e2e/specs/features/example.openapi.yaml
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
openapi: 3.0.0
|
||||||
|
servers:
|
||||||
|
- url: http://example.com/v1
|
||||||
|
description: Production server version 1
|
||||||
|
- url: http://staging-api.example.com
|
||||||
|
description: Staging server
|
||||||
|
info:
|
||||||
|
description: |
|
||||||
|
This is an API documentation of example.
|
||||||
|
version: "0.1.0"
|
||||||
|
title: Example
|
||||||
|
termsOfService: 'http://www.example.com/terms/'
|
||||||
|
contact:
|
||||||
|
email: developer@example.com
|
||||||
|
license:
|
||||||
|
name: Proprietary license
|
||||||
|
url: 'http://www.example.com/license/'
|
||||||
|
tags:
|
||||||
|
- name: agent
|
||||||
|
description: Access to example
|
||||||
|
paths:
|
||||||
|
/agents/{agentId}:
|
||||||
|
put:
|
||||||
|
tags:
|
||||||
|
- agent
|
||||||
|
summary: Edit agent
|
||||||
|
operationId: editAgent
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: agentId
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
example: 12345
|
||||||
|
required: true
|
||||||
|
description: Numeric ID of the paper agent to edit
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json_media-type-level:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
code: AE1
|
||||||
|
name: Andrew
|
||||||
|
application/json_schema-level:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
code: AE1
|
||||||
|
name: Andrew
|
||||||
|
application/json_property-level:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
example: AE1
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example: Andrew
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: media type-level example
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
payload:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
readOnly: true
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
code: 200
|
||||||
|
payload:
|
||||||
|
- id: 1
|
||||||
|
code: AE2
|
||||||
|
name: Yono
|
||||||
|
'201':
|
||||||
|
description: schema-level example
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
payload:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
readOnly: true
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
code: 201
|
||||||
|
payload:
|
||||||
|
- id: 1
|
||||||
|
code: AE2
|
||||||
|
name: Yono
|
||||||
|
'202':
|
||||||
|
description: property-level example
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
example: 202
|
||||||
|
payload:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
readOnly: true
|
||||||
|
example: 1
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
example: AE2
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example: Yono
|
||||||
127
test/e2e/specs/features/example.swagger.yaml
Normal file
127
test/e2e/specs/features/example.swagger.yaml
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
swagger: "2.0"
|
||||||
|
info:
|
||||||
|
description: |
|
||||||
|
This is an API documentation of example.
|
||||||
|
version: "0.1.0"
|
||||||
|
title: Example
|
||||||
|
termsOfService: 'http://www.example.com/terms/'
|
||||||
|
contact:
|
||||||
|
email: developer@example.com
|
||||||
|
license:
|
||||||
|
name: Proprietary license
|
||||||
|
url: 'http://www.example.com/license/'
|
||||||
|
paths:
|
||||||
|
/one:
|
||||||
|
put:
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: NotValidParam
|
||||||
|
type: integer
|
||||||
|
example: 12345
|
||||||
|
required: true
|
||||||
|
description: This example **should not** have an effect
|
||||||
|
- in: query
|
||||||
|
name: ValidParam
|
||||||
|
type: integer
|
||||||
|
x-example: 12345
|
||||||
|
description: This example **should** have an effect
|
||||||
|
- in: body
|
||||||
|
name: body
|
||||||
|
description: property-level examples
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
one:
|
||||||
|
type: string
|
||||||
|
example: hello!
|
||||||
|
two:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
uno:
|
||||||
|
type: string
|
||||||
|
example: wow!
|
||||||
|
dos:
|
||||||
|
type: string
|
||||||
|
example: hey there!
|
||||||
|
- in: body
|
||||||
|
name: body2
|
||||||
|
description: root schema-level example
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
foo:
|
||||||
|
type: string
|
||||||
|
bar:
|
||||||
|
type: integer
|
||||||
|
example:
|
||||||
|
foo: hey
|
||||||
|
bar: 123
|
||||||
|
- in: body
|
||||||
|
name: body3
|
||||||
|
description: nested schema-level example
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
one:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
uno:
|
||||||
|
type: string
|
||||||
|
dos:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
uno: woohoo!
|
||||||
|
dos: amazing!
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
description: schema-level example
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
payload:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
readOnly: true
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
code: 201
|
||||||
|
payload:
|
||||||
|
- id: 1
|
||||||
|
code: AE2
|
||||||
|
name: Yono
|
||||||
|
'202':
|
||||||
|
description: property-level example
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
example: 202
|
||||||
|
payload:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
readOnly: true
|
||||||
|
example: 1
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
example: AE2
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example: Yono
|
||||||
Reference in New Issue
Block a user