Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c4327bfd8 | ||
|
|
fd8274b353 | ||
|
|
762a32b59b | ||
|
|
8189fd2473 | ||
|
|
71d39af443 | ||
|
|
9c8955edd4 | ||
|
|
003a2e7584 | ||
|
|
1f9fb0e68d | ||
|
|
14ef0cc379 | ||
|
|
08cfc77fde | ||
|
|
b8cf080e6c | ||
|
|
245428e7cd | ||
|
|
624a81201f | ||
|
|
b0be261ef8 | ||
|
|
6c5a370ef7 | ||
|
|
fb7f12551f |
+1
-1
@@ -1,6 +1,6 @@
|
||||
FROM alpine:3.5
|
||||
|
||||
MAINTAINER fehguy
|
||||
LABEL maintainer="fehguy"
|
||||
|
||||
ENV VERSION "v2.2.10"
|
||||
ENV FOLDER "swagger-ui-2.2.10"
|
||||
|
||||
@@ -22,7 +22,7 @@ The OpenAPI Specification has undergone 5 revisions since initial creation in 20
|
||||
|
||||
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
|
||||
------------------ | ------------ | -------------------------- | -----
|
||||
3.12.1 | 2018-03-09 | 2.0, 3.0 | [tag v3.12.1](https://github.com/swagger-api/swagger-ui/tree/v3.12.1)
|
||||
3.13.2 | 2018-03-23 | 2.0, 3.0 | [tag v3.13.2](https://github.com/swagger-api/swagger-ui/tree/v3.13.2)
|
||||
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
|
||||
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)
|
||||
|
||||
Vendored
+14
-14
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+3
-3
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -59,6 +59,7 @@ Parameter Name | Description
|
||||
`operationsSorter` | `Function=(a => a)`. Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
|
||||
`showExtensions` | `Boolean=false`. Controls the display of vendor extension (`x-`) fields and values for Operations, Parameters, and Schema.
|
||||
`tagsSorter` | `Function=(a => a)`. Apply a sort to the tag list of each API. It can be 'alpha' (sort by paths alphanumerically) or a function (see [Array.prototype.sort()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) to learn how to write a sort function). Two tag name strings are passed to the sorter for each pass. Default is the order determined by Swagger-UI.
|
||||
`onComplete` | `Function=NOOP`. Provides a mechanism to be notified when Swagger-UI has finished rendering a newly provided definition.
|
||||
|
||||
##### Network
|
||||
|
||||
@@ -77,3 +78,11 @@ Parameter Name | Description
|
||||
--- | ---
|
||||
`modelPropertyMacro` | `Function`. Function to set default values to each property in model. Accepts one argument modelPropertyMacro(property), property is immutable
|
||||
`parameterMacro` | `Function`. Function to set default value to parameters. Accepts two arguments parameterMacro(operation, parameter). Operation and parameter are objects passed for context, both remain immutable
|
||||
|
||||
### Instance methods
|
||||
|
||||
Method Name | Description
|
||||
--- | ---
|
||||
`initOAuth` | `(configObj) => void`. Provide Swagger-UI with information about your OAuth server - see the OAuth2 documentation for more information.
|
||||
`preauthorizeBasic` | `(authDefinitionKey, username, password) => action`. Programmatically set values for a Basic authorization scheme.
|
||||
`preauthorizeApiKey` | `(authDefinitionKey, apiKeyValue) => action`. Programmatically set values for an API key authorization scheme.
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
# OAuth2 configuration
|
||||
You can configure OAuth2 authorization by calling `initOAuth` method with passed configs under the instance of `SwaggerUIBundle`
|
||||
default `client_id` and `client_secret`, `realm`, an application name `appName`, `scopeSeparator`, `additionalQueryStringParams`,
|
||||
`useBasicAuthenticationWithAccessCodeGrant`.
|
||||
You can configure OAuth2 authorization by calling the `initOAuth` method.
|
||||
|
||||
Config Name | Description
|
||||
--- | ---
|
||||
@@ -11,7 +9,7 @@ realm | realm query parameter (for oauth1) added to `authorizationUrl` and `toke
|
||||
appName | application name, displayed in authorization popup. MUST be a string
|
||||
scopeSeparator | scope separator for passing scopes, encoded before calling, default value is a space (encoded value `%20`). MUST be a string
|
||||
additionalQueryStringParams | Additional query parameters added to `authorizationUrl` and `tokenUrl`. MUST be an object
|
||||
useBasicAuthenticationWithAccessCodeGrant | Only activated for the `accessCode` flow. During the `authorization_code` request to the `tokenUrl`, pass the [Client Password](https://tools.ietf.org/html/rfc6749#section-2.3.1) using the HTTP Basic Authentication scheme (`Authorization` header with `Basic base64encoded[client_id:client_secret]`). The default is `false`
|
||||
useBasicAuthenticationWithAccessCodeGrant | Only activated for the `accessCode` flow. During the `authorization_code` request to the `tokenUrl`, pass the [Client Password](https://tools.ietf.org/html/rfc6749#section-2.3.1) using the HTTP Basic Authentication scheme (`Authorization` header with `Basic base64encode(client_id + client_secret)`). The default is `false`
|
||||
|
||||
```javascript
|
||||
const ui = SwaggerUI({...})
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "swagger-ui",
|
||||
"version": "3.12.1",
|
||||
"version": "3.13.2",
|
||||
"main": "dist/swagger-ui.js",
|
||||
"repository": "git@github.com:swagger-api/swagger-ui.git",
|
||||
"contributors": [
|
||||
@@ -19,9 +19,8 @@
|
||||
"build-core": "webpack --config webpack-dist.config.js --colors",
|
||||
"build-standalone": "webpack --config webpack-dist-standalone.config.js --colors",
|
||||
"predev": "npm install",
|
||||
"dev": "npm-run-all --parallel hot-server open-localhost",
|
||||
"dev": "npm-run-all --parallel hot-server",
|
||||
"watch": "webpack --config webpack-watch.config.js --watch --progress",
|
||||
"open-localhost": "node -e 'require(\"open\")(\"http://localhost:3200\")'",
|
||||
"hot-server": "webpack-dev-server --host 0.0.0.0 --config webpack-hot-dev-server.config.js --inline --hot --progress --content-base dev-helpers/",
|
||||
"deps-license": "license-checker --production --csv --out $npm_package_config_deps_check_dir/licenses.csv && license-checker --development --csv --out $npm_package_config_deps_check_dir/licenses-dev.csv",
|
||||
"deps-size": "webpack -p --config webpack.check.js --json | webpack-bundle-size-analyzer >| $npm_package_config_deps_check_dir/sizes.txt",
|
||||
@@ -37,7 +36,8 @@
|
||||
"test-e2e": "sleep 3 && nightwatch test/e2e/scenarios/ --config test/e2e/nightwatch.json",
|
||||
"e2e-initial-render": "nightwatch test/e2e/scenarios/ --config test/e2e/nightwatch.json --group initial-render",
|
||||
"mock-api": "json-server --watch test/e2e/db.json --port 3204",
|
||||
"e2e": "npm-run-all --parallel -r hot-server mock-api test-e2e"
|
||||
"hot-e2e-server": "webpack-dev-server --content-base test/e2e/helpers --host 0.0.0.0 --config webpack-hot-dev-server.config.js --inline --hot --progress",
|
||||
"e2e": "npm-run-all --parallel -r hot-e2e-server mock-api test-e2e"
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^2.0.2",
|
||||
@@ -83,7 +83,7 @@
|
||||
"scroll-to-element": "^2.0.0",
|
||||
"serialize-error": "2.0.0",
|
||||
"shallowequal": "0.2.2",
|
||||
"swagger-client": "^3.5.1",
|
||||
"swagger-client": "^3.5.2",
|
||||
"url-parse": "^1.1.8",
|
||||
"whatwg-fetch": "0.11.1",
|
||||
"worker-loader": "^0.7.1",
|
||||
|
||||
@@ -5,7 +5,7 @@ import ImPropTypes from "react-immutable-proptypes"
|
||||
import { sanitizeUrl } from "core/utils"
|
||||
|
||||
|
||||
class Path extends React.Component {
|
||||
export class InfoBasePath extends React.Component {
|
||||
static propTypes = {
|
||||
host: PropTypes.string,
|
||||
basePath: PropTypes.string
|
||||
@@ -68,6 +68,17 @@ class License extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
export class InfoUrl extends React.PureComponent {
|
||||
static propTypes = {
|
||||
url: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
render() {
|
||||
const { url } = this.props
|
||||
return <a target="_blank" href={ sanitizeUrl(url) }><span className="url"> { url } </span></a>
|
||||
}
|
||||
}
|
||||
|
||||
export default class Info extends React.Component {
|
||||
static propTypes = {
|
||||
info: PropTypes.object,
|
||||
@@ -90,6 +101,8 @@ export default class Info extends React.Component {
|
||||
|
||||
const Markdown = getComponent("Markdown")
|
||||
const VersionStamp = getComponent("VersionStamp")
|
||||
const InfoUrl = getComponent("InfoUrl")
|
||||
const InfoBasePath = getComponent("InfoBasePath")
|
||||
|
||||
return (
|
||||
<div className="info">
|
||||
@@ -97,8 +110,8 @@ export default class Info extends React.Component {
|
||||
<h2 className="title" >{ title }
|
||||
{ version && <VersionStamp version={version}></VersionStamp> }
|
||||
</h2>
|
||||
{ host || basePath ? <Path host={ host } basePath={ basePath } /> : null }
|
||||
{ url && <a target="_blank" href={ sanitizeUrl(url) }><span className="url"> { url } </span></a> }
|
||||
{ host || basePath ? <InfoBasePath host={ host } basePath={ basePath } /> : null }
|
||||
{ url && <InfoUrl url={url} /> }
|
||||
</hgroup>
|
||||
|
||||
<div className="description">
|
||||
|
||||
@@ -60,7 +60,7 @@ export default class LiveResponse extends React.Component {
|
||||
const body = response.get("text")
|
||||
const duration = response.get("duration")
|
||||
const headersKeys = Object.keys(headers)
|
||||
const contentType = headers["content-type"]
|
||||
const contentType = headers["content-type"] || headers["Content-Type"]
|
||||
|
||||
const Curl = getComponent("curl")
|
||||
const ResponseBody = getComponent("responseBody")
|
||||
|
||||
@@ -63,7 +63,7 @@ export default class Models extends Component {
|
||||
|
||||
const content = <ModelWrapper name={ name }
|
||||
expandDepth={ defaultModelsExpandDepth }
|
||||
schema={ schema }
|
||||
schema={ schema || Im.Map() }
|
||||
specPath={Im.List([...specPathBase, name])}
|
||||
getComponent={ getComponent }
|
||||
specSelectors={ specSelectors }
|
||||
|
||||
@@ -81,6 +81,15 @@ export default class OperationContainer extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { isShown } = this.props
|
||||
const resolvedSubtree = this.getResolvedSubtree()
|
||||
|
||||
if(isShown && resolvedSubtree === undefined) {
|
||||
this.requestResolvedSubtree()
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { response, isShown } = nextProps
|
||||
const resolvedSubtree = this.getResolvedSubtree()
|
||||
@@ -96,7 +105,8 @@ export default class OperationContainer extends PureComponent {
|
||||
|
||||
toggleShown =() => {
|
||||
let { layoutActions, tag, operationId, isShown } = this.props
|
||||
if(!isShown) {
|
||||
const resolvedSubtree = this.getResolvedSubtree()
|
||||
if(!isShown && resolvedSubtree === undefined) {
|
||||
// transitioning from collapsed to expanded
|
||||
this.requestResolvedSubtree()
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ export default function() {
|
||||
afterLoad(system) {
|
||||
this.rootInjects = this.rootInjects || {}
|
||||
this.rootInjects.initOAuth = system.authActions.configureAuth
|
||||
this.rootInjects.preauthorizeApiKey = preauthorizeApiKey.bind(null, system)
|
||||
this.rootInjects.preauthorizeBasic = preauthorizeBasic.bind(null, system)
|
||||
},
|
||||
statePlugins: {
|
||||
auth: {
|
||||
@@ -21,3 +23,50 @@ export default function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function preauthorizeBasic(system, key, username, password) {
|
||||
const {
|
||||
authActions: { authorize },
|
||||
specSelectors: { specJson, isOAS3 }
|
||||
} = system
|
||||
|
||||
const definitionBase = isOAS3() ? ["components", "securitySchemes"] : ["securityDefinitions"]
|
||||
|
||||
const schema = specJson().getIn([...definitionBase, key])
|
||||
|
||||
if(!schema) {
|
||||
return null
|
||||
}
|
||||
|
||||
return authorize({
|
||||
[key]: {
|
||||
value: {
|
||||
username,
|
||||
password,
|
||||
},
|
||||
schema: schema.toJS()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function preauthorizeApiKey(system, key, value) {
|
||||
const {
|
||||
authActions: { authorize },
|
||||
specSelectors: { specJson, isOAS3 }
|
||||
} = system
|
||||
|
||||
const definitionBase = isOAS3() ? ["components", "securitySchemes"] : ["securityDefinitions"]
|
||||
|
||||
const schema = specJson().getIn([...definitionBase, key])
|
||||
|
||||
if(!schema) {
|
||||
return null
|
||||
}
|
||||
|
||||
return authorize({
|
||||
[key]: {
|
||||
value,
|
||||
schema: schema.toJS()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { createSelector } from "reselect"
|
||||
import { Map } from "immutable"
|
||||
import win from "../window"
|
||||
|
||||
export default function downloadUrlPlugin (toolbox) {
|
||||
let { fn } = toolbox
|
||||
@@ -12,6 +13,7 @@ export default function downloadUrlPlugin (toolbox) {
|
||||
const config = getConfigs()
|
||||
url = url || specSelectors.url()
|
||||
specActions.updateLoadingStatus("loading")
|
||||
errActions.clear({source: "fetch"})
|
||||
fetch({
|
||||
url,
|
||||
loadSpec: true,
|
||||
@@ -26,7 +28,10 @@ export default function downloadUrlPlugin (toolbox) {
|
||||
function next(res) {
|
||||
if(res instanceof Error || res.status >= 400) {
|
||||
specActions.updateLoadingStatus("failed")
|
||||
return errActions.newThrownErr( new Error((res.message || res.statusText) + " " + url) )
|
||||
errActions.newThrownErr(Object.assign( new Error((res.message || res.statusText) + " " + url), {source: "fetch"}))
|
||||
// Check if the failure was possibly due to CORS or mixed content
|
||||
if (!res.status && res instanceof Error) checkPossibleFailReasons()
|
||||
return
|
||||
}
|
||||
specActions.updateLoadingStatus("success")
|
||||
specActions.updateSpec(res.text)
|
||||
@@ -35,6 +40,38 @@ export default function downloadUrlPlugin (toolbox) {
|
||||
}
|
||||
}
|
||||
|
||||
function checkPossibleFailReasons() {
|
||||
try {
|
||||
let specUrl
|
||||
|
||||
if("URL" in win ) {
|
||||
specUrl = new URL(url)
|
||||
} else {
|
||||
// legacy browser, use <a href> to parse the URL
|
||||
specUrl = document.createElement("a")
|
||||
specUrl.href = url
|
||||
}
|
||||
|
||||
if(specUrl.protocol !== "https:" && win.location.protocol === "https:") {
|
||||
const error = Object.assign(
|
||||
new Error(`Possible mixed-content issue? The page was loaded over https:// but a ${specUrl.protocol}// URL was specified. Check that you are not attempting to load mixed content.`),
|
||||
{source: "fetch"}
|
||||
)
|
||||
errActions.newThrownErr(error)
|
||||
return
|
||||
}
|
||||
if(specUrl.origin !== win.location.origin) {
|
||||
const error = Object.assign(
|
||||
new Error(`Possible cross-origin (CORS) issue? The URL origin (${specUrl.origin}) does not match the page (${win.location.origin}). Check the server returns the correct 'Access-Control-Allow-*' headers.`),
|
||||
{source: "fetch"}
|
||||
)
|
||||
errActions.newThrownErr(error)
|
||||
}
|
||||
} catch (e) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
updateLoadingStatus: (status) => {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
let engaged = false
|
||||
|
||||
export default function() {
|
||||
|
||||
return {
|
||||
statePlugins: {
|
||||
spec: {
|
||||
wrapActions: {
|
||||
updateSpec: (ori) => (...args) => {
|
||||
engaged = true
|
||||
return ori(...args)
|
||||
},
|
||||
updateJsonSpec: (ori, system) => (...args) => {
|
||||
const cb = system.getConfigs().onComplete
|
||||
if(engaged && typeof cb === "function") {
|
||||
// call `onComplete` on next tick, which allows React to
|
||||
// reconcile the DOM before we notify the user
|
||||
setTimeout(cb, 0)
|
||||
engaged = false
|
||||
}
|
||||
|
||||
return ori(...args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { objectify, isFunc, normalizeArray } from "core/utils"
|
||||
import { objectify, isFunc, normalizeArray, deeplyStripKey } from "core/utils"
|
||||
import XML from "xml"
|
||||
import memoizee from "memoizee"
|
||||
|
||||
@@ -29,8 +29,13 @@ export const sampleFromSchema = (schema, config={}) => {
|
||||
let { type, example, properties, additionalProperties, items } = objectify(schema)
|
||||
let { includeReadOnly, includeWriteOnly } = config
|
||||
|
||||
if(example !== undefined)
|
||||
return example
|
||||
if(example !== undefined) {
|
||||
return deeplyStripKey(example, "$$ref", (val) => {
|
||||
// do a couple of quick sanity tests to ensure the value
|
||||
// looks like a $$ref that swagger-client generates.
|
||||
return typeof val === "string" && val.indexOf("#") > -1
|
||||
})
|
||||
}
|
||||
|
||||
if(!type) {
|
||||
if(properties) {
|
||||
@@ -69,13 +74,13 @@ export const sampleFromSchema = (schema, config={}) => {
|
||||
}
|
||||
|
||||
if(type === "array") {
|
||||
if(Array.isArray(items.anyOf)) {
|
||||
return items.anyOf.map(i => sampleFromSchema(i, config))
|
||||
}
|
||||
|
||||
if(Array.isArray(items.oneOf)) {
|
||||
return items.oneOf.map(i => sampleFromSchema(i, config))
|
||||
}
|
||||
if(Array.isArray(items.anyOf)) {
|
||||
return items.anyOf.map(i => sampleFromSchema(i, config))
|
||||
}
|
||||
|
||||
if(Array.isArray(items.oneOf)) {
|
||||
return items.oneOf.map(i => sampleFromSchema(i, config))
|
||||
}
|
||||
|
||||
return [ sampleFromSchema(items, config) ]
|
||||
}
|
||||
@@ -210,7 +215,9 @@ export const sampleXmlFromSchema = (schema, config={}) => {
|
||||
|| enumAttrVal || primitive(props[propName])
|
||||
} else {
|
||||
props[propName].xml.name = props[propName].xml.name || propName
|
||||
props[propName].example = props[propName].example !== undefined ? props[propName].example : example[propName]
|
||||
if(props[propName].example === undefined && example[propName] !== undefined) {
|
||||
props[propName].example = example[propName]
|
||||
}
|
||||
let t = sampleXmlFromSchema(props[propName])
|
||||
if (Array.isArray(t)) {
|
||||
res[displayName] = res[displayName].concat(t)
|
||||
|
||||
@@ -54,7 +54,7 @@ const mergerFn = (oldVal, newVal) => {
|
||||
return newVal
|
||||
}
|
||||
|
||||
return Map().mergeWith(
|
||||
return OrderedMap().mergeWith(
|
||||
mergerFn,
|
||||
oldVal,
|
||||
newVal
|
||||
@@ -66,7 +66,7 @@ const mergerFn = (oldVal, newVal) => {
|
||||
|
||||
export const specJsonWithResolvedSubtrees = createSelector(
|
||||
state,
|
||||
spec => Map().mergeWith(
|
||||
spec => OrderedMap().mergeWith(
|
||||
mergerFn,
|
||||
spec.get("json"),
|
||||
spec.get("resolvedSubtrees")
|
||||
@@ -109,7 +109,7 @@ export const semver = createSelector(
|
||||
)
|
||||
|
||||
export const paths = createSelector(
|
||||
spec,
|
||||
specJsonWithResolvedSubtrees,
|
||||
spec => spec.get("paths")
|
||||
)
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import get from "lodash/get"
|
||||
|
||||
export const updateSpec = (ori, {specActions}) => (...args) => {
|
||||
ori(...args)
|
||||
specActions.parseToJson(...args)
|
||||
@@ -5,7 +7,21 @@ export const updateSpec = (ori, {specActions}) => (...args) => {
|
||||
|
||||
export const updateJsonSpec = (ori, {specActions}) => (...args) => {
|
||||
ori(...args)
|
||||
|
||||
specActions.invalidateResolvedSubtreeCache()
|
||||
|
||||
// Trigger resolution of any path-level $refs.
|
||||
const [json] = args
|
||||
const pathItems = get(json, ["paths"])
|
||||
const pathItemKeys = Object.keys(pathItems)
|
||||
|
||||
pathItemKeys.forEach(k => {
|
||||
const val = get(pathItems, [k])
|
||||
|
||||
if(val.$ref) {
|
||||
specActions.requestResolvedSubtree(["paths", k])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Log the request ( just for debugging, shouldn't affect prod )
|
||||
|
||||
@@ -13,6 +13,7 @@ import downloadUrlPlugin from "core/plugins/download-url"
|
||||
import configsPlugin from "core/plugins/configs"
|
||||
import deepLinkingPlugin from "core/plugins/deep-linking"
|
||||
import filter from "core/plugins/filter"
|
||||
import onComplete from "core/plugins/on-complete"
|
||||
|
||||
import OperationContainer from "core/containers/OperationContainer"
|
||||
|
||||
@@ -45,7 +46,10 @@ import Headers from "core/components/headers"
|
||||
import Errors from "core/components/errors"
|
||||
import ContentType from "core/components/content-type"
|
||||
import Overview from "core/components/overview"
|
||||
import Info from "core/components/info"
|
||||
import Info, {
|
||||
InfoUrl,
|
||||
InfoBasePath
|
||||
} from "core/components/info"
|
||||
import Footer from "core/components/footer"
|
||||
import ParamBody from "core/components/param-body"
|
||||
import Curl from "core/components/curl"
|
||||
@@ -124,7 +128,9 @@ export default function() {
|
||||
OperationExtRow,
|
||||
ParameterExt,
|
||||
OperationContainer,
|
||||
DeepLink
|
||||
DeepLink,
|
||||
InfoUrl,
|
||||
InfoBasePath
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +160,7 @@ export default function() {
|
||||
SplitPaneModePlugin,
|
||||
downloadUrlPlugin,
|
||||
deepLinkingPlugin,
|
||||
filter
|
||||
filter,
|
||||
onComplete
|
||||
]
|
||||
}
|
||||
|
||||
@@ -712,3 +712,25 @@ export const createDeepLinkPath = (str) => typeof str == "string" || str instanc
|
||||
export const escapeDeepLinkPath = (str) => cssEscape( createDeepLinkPath(str) )
|
||||
|
||||
export const getExtensions = (defObj) => defObj.filter((v, k) => /^x-/.test(k))
|
||||
|
||||
// Deeply strips a specific key from an object.
|
||||
//
|
||||
// `predicate` can be used to discriminate the stripping further,
|
||||
// by preserving the key's place in the object based on its value.
|
||||
export function deeplyStripKey(input, keyToStrip, predicate = () => true) {
|
||||
if(typeof input !== "object" || Array.isArray(input) || !keyToStrip) {
|
||||
return input
|
||||
}
|
||||
|
||||
const obj = Object.assign({}, input)
|
||||
|
||||
Object.keys(obj).forEach(k => {
|
||||
if(k === keyToStrip && predicate(obj[k], k)) {
|
||||
delete obj[k]
|
||||
return
|
||||
}
|
||||
obj[k] = deeplyStripKey(obj[k], keyToStrip, predicate)
|
||||
})
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export default class StandaloneLayout extends React.Component {
|
||||
let Container = getComponent("Container")
|
||||
let Row = getComponent("Row")
|
||||
let Col = getComponent("Col")
|
||||
let Errors = getComponent("errors", true)
|
||||
|
||||
const Topbar = getComponent("Topbar", true)
|
||||
const BaseLayout = getComponent("BaseLayout", true)
|
||||
@@ -45,8 +46,8 @@ export default class StandaloneLayout extends React.Component {
|
||||
<div className="info">
|
||||
<div className="loading-container">
|
||||
<h4 className="title">Failed to load API definition.</h4>
|
||||
<p>{lastErrMsg}</p>
|
||||
</div>
|
||||
<Errors/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{ loadingStatus === "failedConfig" &&
|
||||
|
||||
@@ -6,23 +6,8 @@ import ModelExample from "components/model-example"
|
||||
import ModelComponent from "components/model-wrapper"
|
||||
|
||||
describe("<ModelExample/>", function(){
|
||||
// Given
|
||||
let components = {
|
||||
ModelWrapper: ModelComponent
|
||||
}
|
||||
let props = {
|
||||
getComponent: (c) => {
|
||||
return components[c]
|
||||
},
|
||||
specSelectors: {},
|
||||
schema: {},
|
||||
example: "{\"example\": \"value\"}",
|
||||
isExecute: false,
|
||||
getConfigs: () => ({
|
||||
defaultModelRendering: "model",
|
||||
defaultModelExpandDepth: 1
|
||||
})
|
||||
}
|
||||
let components, props
|
||||
|
||||
let exampleSelectedTestInputs = [
|
||||
{ defaultModelRendering: "model", isExecute: true },
|
||||
{ defaultModelRendering: "example", isExecute: true },
|
||||
@@ -30,10 +15,31 @@ describe("<ModelExample/>", function(){
|
||||
{ defaultModelRendering: "othervalue", isExecute: true },
|
||||
{ defaultModelRendering: "othervalue", isExecute: false }
|
||||
]
|
||||
|
||||
let modelSelectedTestInputs = [
|
||||
{ defaultModelRendering: "model", isExecute: false }
|
||||
]
|
||||
|
||||
beforeEach(() => {
|
||||
components = {
|
||||
ModelWrapper: ModelComponent
|
||||
}
|
||||
|
||||
props = {
|
||||
getComponent: (c) => {
|
||||
return components[c]
|
||||
},
|
||||
specSelectors: {},
|
||||
schema: {},
|
||||
example: "{\"example\": \"value\"}",
|
||||
isExecute: false,
|
||||
getConfigs: () => ({
|
||||
defaultModelRendering: "model",
|
||||
defaultModelExpandDepth: 1
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
it("renders model and example tabs", function(){
|
||||
// When
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/* eslint-env mocha */
|
||||
import expect from "expect"
|
||||
import { fromJS } from "immutable"
|
||||
import { preauthorizeBasic, preauthorizeApiKey } from "corePlugins/auth"
|
||||
import { authorize } from "corePlugins/auth/actions"
|
||||
|
||||
const S2_SYSTEM = {
|
||||
authActions: {
|
||||
authorize
|
||||
},
|
||||
specSelectors: {
|
||||
isOAS3: () => false,
|
||||
specJson: () => {
|
||||
return fromJS({
|
||||
swagger: "2.0",
|
||||
securityDefinitions: {
|
||||
"APIKeyHeader": {
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": "X-API-Key"
|
||||
},
|
||||
"basicAuth": {
|
||||
"type": "basic"
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const OAI3_SYSTEM = {
|
||||
authActions: {
|
||||
authorize
|
||||
},
|
||||
specSelectors: {
|
||||
isOAS3: () => true,
|
||||
specJson: () => {
|
||||
return fromJS({
|
||||
openapi: "3.0.0",
|
||||
components: {
|
||||
securitySchemes: {
|
||||
basicAuth: {
|
||||
type: "http",
|
||||
scheme: "basic"
|
||||
},
|
||||
APIKeyHeader: {
|
||||
type: "apiKey",
|
||||
in: "header",
|
||||
name: "X-API-Key"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe("auth plugin - preauthorizers", () => {
|
||||
describe("preauthorizeBasic", () => {
|
||||
it("should return a valid authorize action in Swagger 2", () => {
|
||||
const res = preauthorizeBasic(S2_SYSTEM, "basicAuth", "user", "pass")
|
||||
|
||||
expect(res).toEqual({
|
||||
type: "authorize",
|
||||
payload: {
|
||||
basicAuth: {
|
||||
schema: {
|
||||
type: "basic"
|
||||
},
|
||||
value: {
|
||||
username: "user",
|
||||
password: "pass"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
it("should return a valid authorize action in OpenAPI 3", () => {
|
||||
const res = preauthorizeBasic(OAI3_SYSTEM, "basicAuth", "user", "pass")
|
||||
|
||||
expect(res).toEqual({
|
||||
type: "authorize",
|
||||
payload: {
|
||||
basicAuth: {
|
||||
schema: {
|
||||
type: "http",
|
||||
scheme: "basic"
|
||||
},
|
||||
value: {
|
||||
username: "user",
|
||||
password: "pass"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
it("should return null when the authorization name is invalid in Swagger 2", () => {
|
||||
const res = preauthorizeBasic(S2_SYSTEM, "fakeBasicAuth", "user", "pass")
|
||||
|
||||
expect(res).toEqual(null)
|
||||
})
|
||||
it("should return null when the authorization name is invalid in OpenAPI 3", () => {
|
||||
const res = preauthorizeBasic(OAI3_SYSTEM, "fakeBasicAuth", "user", "pass")
|
||||
|
||||
expect(res).toEqual(null)
|
||||
})
|
||||
})
|
||||
describe("preauthorizeApiKey", () => {
|
||||
it("should return a valid authorize action in Swagger 2", () => {
|
||||
const res = preauthorizeApiKey(S2_SYSTEM, "APIKeyHeader", "Asdf1234")
|
||||
|
||||
expect(res).toEqual({
|
||||
type: "authorize",
|
||||
payload: {
|
||||
APIKeyHeader: {
|
||||
schema: {
|
||||
type: "apiKey",
|
||||
name: "X-API-Key",
|
||||
"in": "header"
|
||||
},
|
||||
value: "Asdf1234"
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
it("should return a valid authorize action in OpenAPI 3", () => {
|
||||
const res = preauthorizeApiKey(OAI3_SYSTEM, "APIKeyHeader", "Asdf1234")
|
||||
|
||||
expect(res).toEqual({
|
||||
type: "authorize",
|
||||
payload: {
|
||||
APIKeyHeader: {
|
||||
schema: {
|
||||
type: "apiKey",
|
||||
"in": "header",
|
||||
name: "X-API-Key"
|
||||
},
|
||||
value: "Asdf1234"
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
it("should return null when the authorization name is invalid in Swagger 2", () => {
|
||||
const res = preauthorizeApiKey(S2_SYSTEM, "FakeAPIKeyHeader", "Asdf1234")
|
||||
|
||||
expect(res).toEqual(null)
|
||||
})
|
||||
it("should return null when the authorization name is invalid in OpenAPI 3", () => {
|
||||
const res = preauthorizeApiKey(OAI3_SYSTEM, "FakeAPIKeyHeader", "Asdf1234")
|
||||
|
||||
expect(res).toEqual(null)
|
||||
})
|
||||
})
|
||||
})
|
||||
+108
-22
@@ -100,6 +100,92 @@ describe("sampleFromSchema", function() {
|
||||
expect(sampleFromSchema(definition, { includeWriteOnly: true })).toEqual(expected)
|
||||
})
|
||||
|
||||
it("returns object without any $$ref fields at the root schema level", function () {
|
||||
var definition = {
|
||||
type: "object",
|
||||
properties: {
|
||||
message: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
example: {
|
||||
value: {
|
||||
message: "Hello, World!"
|
||||
},
|
||||
$$ref: "#/components/examples/WelcomeExample"
|
||||
},
|
||||
$$ref: "#/components/schemas/Welcome"
|
||||
}
|
||||
|
||||
var expected = {
|
||||
"value": {
|
||||
"message": "Hello, World!"
|
||||
}
|
||||
}
|
||||
|
||||
expect(sampleFromSchema(definition, { includeWriteOnly: true })).toEqual(expected)
|
||||
})
|
||||
|
||||
it("returns object without any $$ref fields at nested schema levels", function () {
|
||||
var definition = {
|
||||
type: "object",
|
||||
properties: {
|
||||
message: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
example: {
|
||||
a: {
|
||||
value: {
|
||||
message: "Hello, World!"
|
||||
},
|
||||
$$ref: "#/components/examples/WelcomeExample"
|
||||
}
|
||||
},
|
||||
$$ref: "#/components/schemas/Welcome"
|
||||
}
|
||||
|
||||
var expected = {
|
||||
a: {
|
||||
"value": {
|
||||
"message": "Hello, World!"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(sampleFromSchema(definition, { includeWriteOnly: true })).toEqual(expected)
|
||||
})
|
||||
|
||||
it("returns object with any $$ref fields that appear to be user-created", function () {
|
||||
var definition = {
|
||||
type: "object",
|
||||
properties: {
|
||||
message: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
example: {
|
||||
$$ref: {
|
||||
value: {
|
||||
message: "Hello, World!"
|
||||
},
|
||||
$$ref: "#/components/examples/WelcomeExample"
|
||||
}
|
||||
},
|
||||
$$ref: "#/components/schemas/Welcome"
|
||||
}
|
||||
|
||||
var expected = {
|
||||
$$ref: {
|
||||
"value": {
|
||||
"message": "Hello, World!"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(sampleFromSchema(definition, { includeWriteOnly: true })).toEqual(expected)
|
||||
})
|
||||
|
||||
describe("for array type", function() {
|
||||
it("returns array with sample of array type", function() {
|
||||
var definition = {
|
||||
@@ -108,12 +194,12 @@ describe("sampleFromSchema", function() {
|
||||
type: "integer"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var expected = [ 0 ]
|
||||
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
|
||||
|
||||
it("returns array of examples for array that has example", function() {
|
||||
var definition = {
|
||||
type: "array",
|
||||
@@ -122,9 +208,9 @@ describe("sampleFromSchema", function() {
|
||||
},
|
||||
example: "dog"
|
||||
}
|
||||
|
||||
|
||||
var expected = [ "dog" ]
|
||||
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
|
||||
@@ -132,16 +218,16 @@ describe("sampleFromSchema", function() {
|
||||
var definition = {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
type: "string",
|
||||
},
|
||||
example: [ "dog", "cat" ]
|
||||
}
|
||||
|
||||
|
||||
var expected = [ "dog", "cat" ]
|
||||
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
|
||||
|
||||
it("returns array of samples for oneOf type", function() {
|
||||
var definition = {
|
||||
type: "array",
|
||||
@@ -154,9 +240,9 @@ describe("sampleFromSchema", function() {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var expected = [ 0 ]
|
||||
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
|
||||
@@ -175,9 +261,9 @@ describe("sampleFromSchema", function() {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var expected = [ "string", 0 ]
|
||||
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
|
||||
@@ -198,12 +284,12 @@ describe("sampleFromSchema", function() {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var expected = [ "dog", 1 ]
|
||||
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
|
||||
|
||||
it("returns array of samples for anyOf type", function() {
|
||||
var definition = {
|
||||
type: "array",
|
||||
@@ -216,9 +302,9 @@ describe("sampleFromSchema", function() {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var expected = [ 0 ]
|
||||
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
|
||||
@@ -237,9 +323,9 @@ describe("sampleFromSchema", function() {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var expected = [ "string", 0 ]
|
||||
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
|
||||
@@ -260,9 +346,9 @@ describe("sampleFromSchema", function() {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var expected = [ "dog", 1 ]
|
||||
|
||||
|
||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||
})
|
||||
})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
/* eslint-env mocha */
|
||||
import expect from "expect"
|
||||
import { fromJS } from "immutable"
|
||||
import { fromJSOrdered } from "core/utils"
|
||||
import {
|
||||
parameterValues,
|
||||
contentTypeValues,
|
||||
@@ -9,6 +10,8 @@ import {
|
||||
operationConsumes
|
||||
} from "corePlugins/spec/selectors"
|
||||
|
||||
import Petstore from "./assets/petstore.json"
|
||||
|
||||
describe("spec plugin - selectors", function(){
|
||||
|
||||
describe("parameterValue", function(){
|
||||
@@ -311,7 +314,6 @@ describe("spec plugin - selectors", function(){
|
||||
|
||||
})
|
||||
|
||||
|
||||
describe("specJsonWithResolvedSubtrees", function(){
|
||||
|
||||
it("should return a correctly merged tree", function(){
|
||||
@@ -360,5 +362,93 @@ describe("spec plugin - selectors", function(){
|
||||
}
|
||||
})
|
||||
})
|
||||
it("should preserve initial map key ordering", function(){
|
||||
// Given
|
||||
let state = fromJSOrdered({
|
||||
json: Petstore,
|
||||
resolvedSubtrees: {
|
||||
paths: {
|
||||
"/pet/{petId}": {
|
||||
post: {
|
||||
tags: [
|
||||
"pet"
|
||||
],
|
||||
summary: "Updates a pet in the store with form data",
|
||||
description: "",
|
||||
operationId: "updatePetWithForm",
|
||||
consumes: [
|
||||
"application/x-www-form-urlencoded"
|
||||
],
|
||||
produces: [
|
||||
"application/xml",
|
||||
"application/json"
|
||||
],
|
||||
parameters: [
|
||||
{
|
||||
name: "petId",
|
||||
"in": "path",
|
||||
description: "ID of pet that needs to be updated",
|
||||
required: true,
|
||||
type: "integer",
|
||||
format: "int64"
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
"in": "formData",
|
||||
description: "Updated name of the pet",
|
||||
required: false,
|
||||
type: "string"
|
||||
},
|
||||
{
|
||||
name: "status",
|
||||
"in": "formData",
|
||||
description: "Updated status of the pet",
|
||||
required: false,
|
||||
type: "string"
|
||||
}
|
||||
],
|
||||
responses: {
|
||||
"405": {
|
||||
description: "Invalid input"
|
||||
}
|
||||
},
|
||||
security: [
|
||||
{
|
||||
petstore_auth: [
|
||||
"write:pets",
|
||||
"read:pets"
|
||||
]
|
||||
}
|
||||
],
|
||||
__originalOperationId: "updatePetWithForm"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// When
|
||||
let result = specJsonWithResolvedSubtrees(state)
|
||||
|
||||
// Then
|
||||
const correctOrder = [
|
||||
"/pet",
|
||||
"/pet/findByStatus",
|
||||
"/pet/findByTags",
|
||||
"/pet/{petId}",
|
||||
"/pet/{petId}/uploadImage",
|
||||
"/store/inventory",
|
||||
"/store/order",
|
||||
"/store/order/{orderId}",
|
||||
"/user",
|
||||
"/user/createWithArray",
|
||||
"/user/createWithList",
|
||||
"/user/login",
|
||||
"/user/logout",
|
||||
"/user/{username}"
|
||||
]
|
||||
expect(state.getIn(["json", "paths"]).keySeq().toJS()).toEqual(correctOrder)
|
||||
expect(result.getIn(["paths"]).keySeq().toJS()).toEqual(correctOrder)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -701,6 +701,36 @@ describe("bound system", function(){
|
||||
})
|
||||
})
|
||||
|
||||
describe("rootInjects", function() {
|
||||
it("should attach a rootInject function as an instance method", function() {
|
||||
// This is the same thing as the `afterLoad` tests, but is here for posterity
|
||||
|
||||
// Given
|
||||
const system = new System({
|
||||
plugins: [
|
||||
{
|
||||
afterLoad(system) {
|
||||
this.rootInjects.wow = system.dogeSelectors.wow
|
||||
},
|
||||
statePlugins: {
|
||||
doge: {
|
||||
selectors: {
|
||||
wow: () => (system) => {
|
||||
return "so selective"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// When
|
||||
var res = system.getSystem().wow()
|
||||
expect(res).toEqual("so selective")
|
||||
})
|
||||
})
|
||||
|
||||
describe("error catching", function() {
|
||||
it("should encapsulate thrown errors in an afterLoad method", function() {
|
||||
// Given
|
||||
|
||||
+54
-1
@@ -21,7 +21,8 @@ import {
|
||||
createDeepLinkPath,
|
||||
escapeDeepLinkPath,
|
||||
sanitizeUrl,
|
||||
extractFileNameFromContentDispositionHeader
|
||||
extractFileNameFromContentDispositionHeader,
|
||||
deeplyStripKey
|
||||
} from "core/utils"
|
||||
import win from "core/window"
|
||||
|
||||
@@ -942,6 +943,58 @@ describe("utils", function() {
|
||||
})
|
||||
})
|
||||
|
||||
describe("deeplyStripKey", function() {
|
||||
it("should filter out a specified key", function() {
|
||||
const input = {
|
||||
$$ref: "#/this/is/my/ref",
|
||||
a: {
|
||||
$$ref: "#/this/is/my/other/ref",
|
||||
value: 12345
|
||||
}
|
||||
}
|
||||
const result = deeplyStripKey(input, "$$ref")
|
||||
expect(result).toEqual({
|
||||
a: {
|
||||
value: 12345
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it("should filter out a specified key by predicate", function() {
|
||||
const input = {
|
||||
$$ref: "#/this/is/my/ref",
|
||||
a: {
|
||||
$$ref: "#/keep/this/one",
|
||||
value: 12345
|
||||
}
|
||||
}
|
||||
const result = deeplyStripKey(input, "$$ref", (v) => v !== "#/keep/this/one")
|
||||
expect(result).toEqual({
|
||||
a: {
|
||||
value: 12345,
|
||||
$$ref: "#/keep/this/one"
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it("should only call the predicate when the key matches", function() {
|
||||
const input = {
|
||||
$$ref: "#/this/is/my/ref",
|
||||
a: {
|
||||
$$ref: "#/this/is/my/other/ref",
|
||||
value: 12345
|
||||
}
|
||||
}
|
||||
let count = 0
|
||||
|
||||
const result = deeplyStripKey(input, "$$ref", () => {
|
||||
count++
|
||||
return true
|
||||
})
|
||||
expect(count).toEqual(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe("parse and serialize search", function() {
|
||||
afterEach(function() {
|
||||
win.location.search = ""
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
<!-- HTML for dev server -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Swagger UI</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
|
||||
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||
<style>
|
||||
html
|
||||
{
|
||||
box-sizing: border-box;
|
||||
overflow: -moz-scrollbars-vertical;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
*,
|
||||
*:before,
|
||||
*:after
|
||||
{
|
||||
box-sizing: inherit;
|
||||
}
|
||||
body {
|
||||
margin:0;
|
||||
background: #fafafa;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0">
|
||||
<defs>
|
||||
<symbol viewBox="0 0 20 20" id="unlocked">
|
||||
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="locked">
|
||||
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="close">
|
||||
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="large-arrow">
|
||||
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 20 20" id="large-arrow-down">
|
||||
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>
|
||||
</symbol>
|
||||
|
||||
|
||||
<symbol viewBox="0 0 24 24" id="jump-to">
|
||||
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol viewBox="0 0 24 24" id="expand">
|
||||
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
|
||||
</symbol>
|
||||
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
<div id="swagger-ui"></div>
|
||||
|
||||
<script src="./swagger-ui-bundle.js"> </script>
|
||||
<script src="./swagger-ui-standalone-preset.js"> </script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
window["SwaggerUIBundle"] = window["swagger-ui-bundle"]
|
||||
window["SwaggerUIStandalonePreset"] = window["swagger-ui-standalone-preset"]
|
||||
// Build a system
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "http://petstore.swagger.io/v2/swagger.json",
|
||||
dom_id: '#swagger-ui',
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
onComplete: () => {
|
||||
if(window.completeCount) {
|
||||
window.completeCount++
|
||||
} else {
|
||||
window.completeCount = 1
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
window.ui = ui
|
||||
|
||||
ui.initOAuth({
|
||||
clientId: "your-client-id",
|
||||
clientSecret: "your-client-secret-if-required",
|
||||
realm: "your-realms",
|
||||
appName: "your-app-name",
|
||||
scopeSeparator: " ",
|
||||
additionalQueryStringParams: {}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
const expect = require("expect")
|
||||
|
||||
describe("onComplete option", function () {
|
||||
let mainPage
|
||||
beforeEach(function (client, done) {
|
||||
mainPage = client
|
||||
.url("localhost:3200")
|
||||
.page.main()
|
||||
|
||||
client.waitForElementVisible(".opblock-tag-section", 5000)
|
||||
done()
|
||||
})
|
||||
|
||||
it("triggers the page-provided onComplete exactly 1 times", function (client, done) {
|
||||
client.execute(function() {
|
||||
return window.completeCount
|
||||
}, [], (result) => {
|
||||
expect(result.value).toEqual(1)
|
||||
client.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -63,7 +63,6 @@ module.exports = require("./make-webpack-config")(rules, {
|
||||
},
|
||||
devServer: {
|
||||
port: 3200,
|
||||
contentBase: path.join(__dirname, "dev-helpers"),
|
||||
publicPath: "/",
|
||||
noInfo: true,
|
||||
hot: true,
|
||||
|
||||
Reference in New Issue
Block a user