Merge branch 'master' into xlink-deprecated
This commit is contained in:
66
.github/issue_template.md
vendored
66
.github/issue_template.md
vendored
@@ -1,3 +1,63 @@
|
|||||||
When reporting an issue, please provide the following details:
|
<!---
|
||||||
- swagger-ui version
|
Thanks for filing an issue 😄 ! Before you submit, please read the following:
|
||||||
- a swagger file reproducing the issue
|
|
||||||
|
Search open/closed issues before submitting since someone might have asked the same thing before!
|
||||||
|
|
||||||
|
Issues on GitHub are only related to problems of Swagger-UI itself. We'll try to offer support
|
||||||
|
here for your use case, but we can't offer help with projects that use Swagger-UI indirectly,
|
||||||
|
like Springfox or swagger-node.
|
||||||
|
|
||||||
|
Likewise, we can't accept features or bugs in the Swagger/OpenAPI specifications themselves,
|
||||||
|
or anything that violates the specifications.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!--- Provide a general summary of the issue in the title above -->
|
||||||
|
|
||||||
|
|
||||||
|
| Q | A
|
||||||
|
| ------------------------------- | -------
|
||||||
|
| Bug or feature request? |
|
||||||
|
| Which Swagger/OpenAPI version? |
|
||||||
|
| Which Swagger-UI version? |
|
||||||
|
| How did you install Swagger-UI? |
|
||||||
|
| Which broswer & version? |
|
||||||
|
| Which operating system? |
|
||||||
|
|
||||||
|
|
||||||
|
### Demonstration API definition
|
||||||
|
<!--- If you're describing a bug, please provide an API definition that reproduces your problem -->
|
||||||
|
<!--- If you have link to a demo repo please link that! -->
|
||||||
|
|
||||||
|
<!--- If your spec is large, please put it into a Gist (https://gist.github.com) instead of pasting it here. -->
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
your: "API definition goes here"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration (browser query string, constructor, config.yaml)
|
||||||
|
<!--- If describing a bug, tell us what your configuration looks like -->
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"your": { "constructorConfig": "here" }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`?yourQueryStringConfig=here`
|
||||||
|
|
||||||
|
### Expected Behavior
|
||||||
|
<!--- If you're describing a bug, tell us what should happen -->
|
||||||
|
<!--- If you're suggesting a change/improvement, tell us how it should work -->
|
||||||
|
|
||||||
|
### Current Behavior
|
||||||
|
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
|
||||||
|
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
|
||||||
|
|
||||||
|
### Possible Solution
|
||||||
|
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
|
||||||
|
<!--- or ideas how to implement the addition or change -->
|
||||||
|
|
||||||
|
### Context
|
||||||
|
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||||
|
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,3 +6,5 @@ npm-debug.log*
|
|||||||
.eslintcache
|
.eslintcache
|
||||||
package-lock.json
|
package-lock.json
|
||||||
*.iml
|
*.iml
|
||||||
|
selenium-debug.log
|
||||||
|
test/e2e/db.json
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ deploy:
|
|||||||
email: apiteam@swagger.io
|
email: apiteam@swagger.io
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
api_key:
|
api_key:
|
||||||
secure: "IJkLaACa+rfERf1O5nwlqOyuo9sbul3FBhBt4Un9P+DvEet3AoDPV9NQVLd8SkmQYKGbGQWF4BIdjrO5nqFD6Te+JTeUX5Uo/DFS/fu9qw1xv0dQpvbJFuoYnnFlbzGTEs4CFa8lbu3ZromFHQGOQxRobjsG1Kf0dWFSSzmND3g="
|
secure: "YKk5L1BL4oAixvLjWp+i85fNFXK85HKOlUt6QypkZkt23My5aywuYsv5VCLjjOtuWc72zbmOzP82DTBsuRswCRViXWCiNYhl42QTdvadHu0uIlM/FL6aNlvPpzXIws4bMvz1aYOTzFTnSnNuvCTzF1daW0+2ClOo3r0nLEdDfFg="
|
||||||
on:
|
on:
|
||||||
tags: true
|
tags: true
|
||||||
repo: swagger-api/swagger-ui
|
repo: swagger-api/swagger-ui
|
||||||
|
|||||||
54
CONTRIBUTING.md
Normal file
54
CONTRIBUTING.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
## Contributing to Swagger-UI
|
||||||
|
|
||||||
|
We love contributions from our community of users! This document explains our guidelines and workflows. Please take care to follow them, as it helps us keep things moving smoothly.
|
||||||
|
|
||||||
|
#### Environment setup
|
||||||
|
|
||||||
|
0. Install Node.js (4 or newer) and npm (3 or newer).
|
||||||
|
1. Make a fork of Swagger-UI on GitHub, then clone your fork to your machine.
|
||||||
|
2. Run `npm install` in your Swagger-UI directory.
|
||||||
|
3. Run `npm run dev`. `localhost:3200` should open automatically.
|
||||||
|
4. You're ready to go!
|
||||||
|
|
||||||
|
#### Branching model
|
||||||
|
|
||||||
|
Feature branches should be prefixed with `ft/`.
|
||||||
|
|
||||||
|
Bugfix branches should be prefixed with `bug/`.
|
||||||
|
|
||||||
|
Version branches should be prefixed with `v/`.
|
||||||
|
|
||||||
|
After the forward slash, include a short description of what you're fixing. For example: `bug/fix-everything-that-was-broken`. For versions, add the version that will be released via the branch, for example: `v/1.2.3`.
|
||||||
|
|
||||||
|
If there's an issue filed that you're addressing in your branch, include the issue number directly after the forward slash. For example: `bug/1234-fix-all-the-other-things`.
|
||||||
|
|
||||||
|
#### Filing issues
|
||||||
|
|
||||||
|
- **Do** include the Swagger-UI build you're using - you can find this by opening your console and checking `window.versions.swaggerUi`
|
||||||
|
- **Do** include a spec that demonstrates the issue you're experiencing.
|
||||||
|
- **Do** include screenshots, if needed. GIFs are even better!
|
||||||
|
- **Do** place code inside of a pre-formatted container by surrounding the code with triple backticks.
|
||||||
|
- **Don't** open tickets discussing issues with the Swagger/OpenAPI specification itself, or for issues with projects that use Swagger-UI.
|
||||||
|
- **Don't** open an issue without searching the issue tracker for duplicates first.
|
||||||
|
|
||||||
|
#### Committing
|
||||||
|
|
||||||
|
- Break your commits into logical atomic units. Well-segmented commits make it _much_ easier for others to step through your changes.
|
||||||
|
- Limit your subject (first) line to 50 characters (GitHub truncates more than 70).
|
||||||
|
- Provide a body if you'd like to explain your commit in detail.
|
||||||
|
- Capitalize the beginning of your subject line, and do not end the subject line with a period.
|
||||||
|
- Your subject line should complete this sentence: `If applied, this commit will [your subject line].`
|
||||||
|
- Don't use [magic GitHub words](https://help.github.com/articles/closing-issues-using-keywords/) in your commits to close issues - do that in the pull request for your code instead.
|
||||||
|
|
||||||
|
_Adapted from [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/#seven-rules)._
|
||||||
|
|
||||||
|
#### Making pull requests
|
||||||
|
|
||||||
|
- **Do** summarize your changes in the PR body. If in doubt, write a bullet-point list titled `This PR does the following:`.
|
||||||
|
- **Do** include references to issues that your PR solves, and use [magic GitHub words](https://help.github.com/articles/closing-issues-using-keywords/) to close those issues automatically when your PR is merged.
|
||||||
|
- **Do** include tests that cover new or changed functionality.
|
||||||
|
- **Do** be careful to follow our ESLint style rules. We recommend installing an ESLint plugin if you use a graphical code editor.
|
||||||
|
- **Do** make sure that tests and the linter are passing by running `npm test` locally, otherwise we can't merge your pull request.
|
||||||
|
- **Don't** include any changes to files in the `dist/` directory - we update those files only during releases.
|
||||||
|
- **Don't** mention maintainers in your original PR body - we probably would've seen it anyway, so it just increases the noise in our inboxes. Do feel free to ping maintainers if a week has passed and you've heard nothing from us.
|
||||||
|
- **Don't** open PRs for custom functionality that only serves a small subset of our users - custom functionality should be implemented outside of our codebase, via a plugin.
|
||||||
33
README.md
33
README.md
@@ -18,16 +18,17 @@ This repo publishes to two different NPM packages:
|
|||||||
For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x).
|
For the older version of swagger-ui, refer to the [*2.x branch*](https://github.com/swagger-api/swagger-ui/tree/2.x).
|
||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
The OpenAPI Specification has undergone 4 revisions since initial creation in 2010. Compatibility between swagger-ui and the OpenAPI Specification is as follows:
|
The OpenAPI Specification has undergone 5 revisions since initial creation in 2010. Compatibility between swagger-ui and the OpenAPI Specification is as follows:
|
||||||
|
|
||||||
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes | Status
|
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
|
||||||
------------------ | ------------ | -------------------------- | ----- | ------
|
------------------ | ------------ | -------------------------- | -----
|
||||||
3.0.19 | 2017-07-14 | 2.0 | [tag v3.0.19](https://github.com/swagger-api/swagger-ui/tree/v3.0.19) |
|
3.1.4 | 2017-08-05 | 2.0, 3.0 | [tag v3.1.4](https://github.com/swagger-api/swagger-ui/tree/v3.1.4)
|
||||||
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) |
|
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
|
||||||
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.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.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.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)
|
||||||
1.0.13 | 2013-03-08 | 1.1, 1.2 | [tag v1.0.13](https://github.com/swagger-api/swagger-ui/tree/v1.0.13) |
|
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)
|
||||||
1.0.1 | 2011-10-11 | 1.0, 1.1 | [tag v1.0.1](https://github.com/swagger-api/swagger-ui/tree/v1.0.1) |
|
1.0.13 | 2013-03-08 | 1.1, 1.2 | [tag v1.0.13](https://github.com/swagger-api/swagger-ui/tree/v1.0.13)
|
||||||
|
1.0.1 | 2011-10-11 | 1.0, 1.1 | [tag v1.0.1](https://github.com/swagger-api/swagger-ui/tree/v1.0.1)
|
||||||
|
|
||||||
|
|
||||||
### How to run
|
### How to run
|
||||||
@@ -58,6 +59,15 @@ If you'd like to make modifications to the codebase, run the dev server with: `n
|
|||||||
|
|
||||||
If you'd like to rebuild the `/dist` folder with your codebase changes, run `npm run build`.
|
If you'd like to rebuild the `/dist` folder with your codebase changes, run `npm run build`.
|
||||||
|
|
||||||
|
|
||||||
|
##### Integration Tests
|
||||||
|
|
||||||
|
You will need JDK of version 7 or higher as instructed here
|
||||||
|
http://nightwatchjs.org/gettingstarted#selenium-server-setup
|
||||||
|
|
||||||
|
Integration tests can be run locally with `npm run e2e` - be sure you aren't running a dev server when testing!
|
||||||
|
|
||||||
|
|
||||||
##### Browser support
|
##### Browser support
|
||||||
Swagger UI works in the latest versions of Chrome, Safari, Firefox, Edge and IE11.
|
Swagger UI works in the latest versions of Chrome, Safari, Firefox, Edge and IE11.
|
||||||
|
|
||||||
@@ -96,7 +106,8 @@ To use swagger-ui's bundles, you should take a look at the [source of swagger-ui
|
|||||||
|
|
||||||
#### OAuth2 configuration
|
#### OAuth2 configuration
|
||||||
You can configure OAuth2 authorization by calling `initOAuth` method with passed configs under the instance of `SwaggerUIBundle`
|
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`.
|
default `client_id` and `client_secret`, `realm`, an application name `appName`, `scopeSeparator`, `additionalQueryStringParams`,
|
||||||
|
`useBasicAuthenticationWithAccessCodeGrant`.
|
||||||
|
|
||||||
Config Name | Description
|
Config Name | Description
|
||||||
--- | ---
|
--- | ---
|
||||||
@@ -106,6 +117,7 @@ realm | realm query parameter (for oauth1) added to `authorizationUrl` and `toke
|
|||||||
appName | application name, displayed in authorization popup. MUST be a string
|
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
|
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
|
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`
|
||||||
|
|
||||||
```
|
```
|
||||||
const ui = SwaggerUIBundle({...})
|
const ui = SwaggerUIBundle({...})
|
||||||
@@ -135,6 +147,7 @@ urls.primaryName | When using `urls`, you can use this subparameter. If the valu
|
|||||||
spec | A JSON object describing the OpenAPI Specification. When used, the `url` parameter will not be parsed. This is useful for testing manually-generated specifications without hosting them.
|
spec | A JSON object describing the OpenAPI Specification. When used, the `url` parameter will not be parsed. This is useful for testing manually-generated specifications without hosting them.
|
||||||
validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation.
|
validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation.
|
||||||
dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger.
|
dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger.
|
||||||
|
domNode | The HTML DOM element inside which SwaggerUi will put the user interface for swagger. Overrides `dom_id`.
|
||||||
oauth2RedirectUrl | OAuth redirect URL
|
oauth2RedirectUrl | OAuth redirect URL
|
||||||
tagsSorter | 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.
|
tagsSorter | 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.
|
||||||
operationsSorter | 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.
|
operationsSorter | 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.
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
{
|
{
|
||||||
box-sizing: inherit;
|
box-sizing: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin:0;
|
margin:0;
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
|
|||||||
9
dist/index.html
vendored
9
dist/index.html
vendored
@@ -11,15 +11,15 @@
|
|||||||
<style>
|
<style>
|
||||||
html
|
html
|
||||||
{
|
{
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: -moz-scrollbars-vertical;
|
overflow: -moz-scrollbars-vertical;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
*,
|
*,
|
||||||
*:before,
|
*:before,
|
||||||
*:after
|
*:after
|
||||||
{
|
{
|
||||||
box-sizing: inherit;
|
box-sizing: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -76,6 +76,7 @@ window.onload = function() {
|
|||||||
const ui = SwaggerUIBundle({
|
const ui = SwaggerUIBundle({
|
||||||
url: "http://petstore.swagger.io/v2/swagger.json",
|
url: "http://petstore.swagger.io/v2/swagger.json",
|
||||||
dom_id: '#swagger-ui',
|
dom_id: '#swagger-ui',
|
||||||
|
deepLinking: true,
|
||||||
presets: [
|
presets: [
|
||||||
SwaggerUIBundle.presets.apis,
|
SwaggerUIBundle.presets.apis,
|
||||||
SwaggerUIStandalonePreset
|
SwaggerUIStandalonePreset
|
||||||
|
|||||||
24
dist/swagger-ui-bundle.js
vendored
24
dist/swagger-ui-bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui-bundle.js.map
vendored
2
dist/swagger-ui-bundle.js.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AAsyKA;;;;;;AAktEA;;;;;;;;;;;;;;;;;;;;;;;;;;AAkqTA;;;;;;;;;;;;;;AAs8JA;;;;;;;;;AA4tnBA;;;;;AAmpQA;;;;;;AA+mXA","sourceRoot":""}
|
{"version":3,"file":"swagger-ui-bundle.js","sources":["webpack:///swagger-ui-bundle.js"],"mappings":"AAAA;;;;;AAoyKA;;;;;;AAy+EA;;;;;;;;;;;;;;;;;;;;;;;;;;AAw1TA;;;;;;;;;;;;;;AAs8JA;;;;;;;;;AAw6oBA;;;;;AAirQA;AAm4DA;;;;;;AAo4YA;;;;;;AA8jaA;AAumvBA","sourceRoot":""}
|
||||||
6
dist/swagger-ui-standalone-preset.js
vendored
6
dist/swagger-ui-standalone-preset.js
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui-standalone-preset.js.map
vendored
2
dist/swagger-ui-standalone-preset.js.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA40CA;;;;;;AAqlFA","sourceRoot":""}
|
{"version":3,"file":"swagger-ui-standalone-preset.js","sources":["webpack:///swagger-ui-standalone-preset.js"],"mappings":"AAAA;;;;;AA00CA;;;;;;AAmlFA","sourceRoot":""}
|
||||||
5
dist/swagger-ui.css
vendored
5
dist/swagger-ui.css
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui.css.map
vendored
2
dist/swagger-ui.css.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"swagger-ui.css","sources":[],"mappings":";;;","sourceRoot":""}
|
{"version":3,"file":"swagger-ui.css","sources":[],"mappings":"","sourceRoot":""}
|
||||||
4
dist/swagger-ui.js
vendored
4
dist/swagger-ui.js
vendored
File diff suppressed because one or more lines are too long
2
dist/swagger-ui.js.map
vendored
2
dist/swagger-ui.js.map
vendored
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAk/aA","sourceRoot":""}
|
{"version":3,"file":"swagger-ui.js","sources":["webpack:///swagger-ui.js"],"mappings":"AAAA;;;;;;AAowcA","sourceRoot":""}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
var path = require("path")
|
var path = require("path")
|
||||||
|
|
||||||
var webpack = require("webpack")
|
var webpack = require('webpack')
|
||||||
var ExtractTextPlugin = require("extract-text-webpack-plugin")
|
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||||
var deepExtend = require("deep-extend")
|
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||||
const {gitDescribeSync} = require("git-describe")
|
var deepExtend = require('deep-extend')
|
||||||
|
const {gitDescribeSync} = require('git-describe')
|
||||||
const os = require("os")
|
const os = require("os")
|
||||||
|
|
||||||
var pkg = require("./package.json")
|
var pkg = require("./package.json")
|
||||||
@@ -60,7 +61,8 @@ module.exports = function(rules, options) {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
if( specialOptions.minimize ) {
|
if( specialOptions.minimize ) { // production mode
|
||||||
|
|
||||||
plugins.push(
|
plugins.push(
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
new webpack.optimize.UglifyJsPlugin({
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
@@ -74,6 +76,8 @@ module.exports = function(rules, options) {
|
|||||||
|
|
||||||
plugins.push( new webpack.NoEmitOnErrorsPlugin())
|
plugins.push( new webpack.NoEmitOnErrorsPlugin())
|
||||||
|
|
||||||
|
} else { // development mode
|
||||||
|
plugins.push(new CopyWebpackPlugin([ { from: 'test/e2e/specs', to: 'test-specs' } ]))
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins.push(
|
plugins.push(
|
||||||
|
|||||||
18
package.json
18
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "swagger-ui",
|
"name": "swagger-ui",
|
||||||
"version": "3.0.19",
|
"version": "3.1.4",
|
||||||
"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": [
|
||||||
@@ -32,7 +32,11 @@
|
|||||||
"test": "npm run lint-errors && npm run just-test-in-node",
|
"test": "npm run lint-errors && npm run just-test-in-node",
|
||||||
"test-in-node": "npm run lint-errors && npm run just-test-in-node",
|
"test-in-node": "npm run lint-errors && npm run just-test-in-node",
|
||||||
"just-test": "karma start --config karma.conf.js",
|
"just-test": "karma start --config karma.conf.js",
|
||||||
"just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core test/components test/bugs test/swagger-ui-dist-package"
|
"just-test-in-node": "mocha --recursive --compilers js:babel-core/register test/core test/components test/bugs test/swagger-ui-dist-package",
|
||||||
|
"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"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"base64-js": "^1.2.0",
|
"base64-js": "^1.2.0",
|
||||||
@@ -43,7 +47,6 @@
|
|||||||
"ieee754": "^1.1.8",
|
"ieee754": "^1.1.8",
|
||||||
"immutable": "^3.x.x",
|
"immutable": "^3.x.x",
|
||||||
"js-yaml": "^3.5.5",
|
"js-yaml": "^3.5.5",
|
||||||
"less": "2.7.1",
|
|
||||||
"lodash": "4.17.2",
|
"lodash": "4.17.2",
|
||||||
"matcher": "^0.1.2",
|
"matcher": "^0.1.2",
|
||||||
"memoizee": "0.4.1",
|
"memoizee": "0.4.1",
|
||||||
@@ -58,6 +61,7 @@
|
|||||||
"react-height": "^2.0.0",
|
"react-height": "^2.0.0",
|
||||||
"react-hot-loader": "1.3.1",
|
"react-hot-loader": "1.3.1",
|
||||||
"react-immutable-proptypes": "2.1.0",
|
"react-immutable-proptypes": "2.1.0",
|
||||||
|
"react-markdown": "^2.5.0",
|
||||||
"react-motion": "0.4.4",
|
"react-motion": "0.4.4",
|
||||||
"react-object-inspector": "0.2.1",
|
"react-object-inspector": "0.2.1",
|
||||||
"react-redux": "^4.x.x",
|
"react-redux": "^4.x.x",
|
||||||
@@ -71,7 +75,7 @@
|
|||||||
"scroll-to-element": "^2.0.0",
|
"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.18",
|
"swagger-client": "3.0.19",
|
||||||
"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",
|
||||||
@@ -90,6 +94,8 @@
|
|||||||
"babel-preset-react": "^6.23.0",
|
"babel-preset-react": "^6.23.0",
|
||||||
"babel-preset-stage-0": "^6.22.0",
|
"babel-preset-stage-0": "^6.22.0",
|
||||||
"babel-runtime": "^6.23.0",
|
"babel-runtime": "^6.23.0",
|
||||||
|
"chromedriver": "^2.30.1",
|
||||||
|
"copy-webpack-plugin": "^4.0.1",
|
||||||
"css-loader": "0.28.4",
|
"css-loader": "0.28.4",
|
||||||
"deep-extend": "^0.5.0",
|
"deep-extend": "^0.5.0",
|
||||||
"deepmerge": "^1.3.2",
|
"deepmerge": "^1.3.2",
|
||||||
@@ -100,9 +106,9 @@
|
|||||||
"extract-text-webpack-plugin": "^2.1.2",
|
"extract-text-webpack-plugin": "^2.1.2",
|
||||||
"file-loader": "0.11.2",
|
"file-loader": "0.11.2",
|
||||||
"git-describe": "^4.0.1",
|
"git-describe": "^4.0.1",
|
||||||
"html-webpack-plugin": "^2.28.0",
|
|
||||||
"imports-loader": "0.7.1",
|
"imports-loader": "0.7.1",
|
||||||
"json-loader": "0.5.4",
|
"json-loader": "0.5.4",
|
||||||
|
"json-server": "^0.11.0",
|
||||||
"karma": "^1.7.0",
|
"karma": "^1.7.0",
|
||||||
"karma-chrome-launcher": "^2.2.0",
|
"karma-chrome-launcher": "^2.2.0",
|
||||||
"karma-mocha": "^1.3.0",
|
"karma-mocha": "^1.3.0",
|
||||||
@@ -111,6 +117,7 @@
|
|||||||
"less": "2.7.2",
|
"less": "2.7.2",
|
||||||
"license-checker": "^11.0.0",
|
"license-checker": "^11.0.0",
|
||||||
"mocha": "^3.4.2",
|
"mocha": "^3.4.2",
|
||||||
|
"nightwatch": "^0.9.16",
|
||||||
"node-sass": "^4.5.0",
|
"node-sass": "^4.5.0",
|
||||||
"npm-run-all": "4.0.2",
|
"npm-run-all": "4.0.2",
|
||||||
"null-loader": "0.1.1",
|
"null-loader": "0.1.1",
|
||||||
@@ -121,6 +128,7 @@
|
|||||||
"react-test-renderer": "^15.5.4",
|
"react-test-renderer": "^15.5.4",
|
||||||
"rimraf": "^2.6.0",
|
"rimraf": "^2.6.0",
|
||||||
"sass-loader": "^6.0.2",
|
"sass-loader": "^6.0.2",
|
||||||
|
"selenium-server-standalone-jar": "3.4.0",
|
||||||
"standard": "^10.0.2",
|
"standard": "^10.0.2",
|
||||||
"standard-loader": "^6.0.1",
|
"standard-loader": "^6.0.1",
|
||||||
"style-loader": "0.18.2",
|
"style-loader": "0.18.2",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default class ArrayModel extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
let { getComponent, required, schema, depth, expandDepth } = this.props
|
let { getComponent, schema, depth, expandDepth, name } = this.props
|
||||||
let items = schema.get("items")
|
let items = schema.get("items")
|
||||||
let title = schema.get("title") || name
|
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 )
|
||||||
@@ -31,7 +31,7 @@ export default class ArrayModel extends Component {
|
|||||||
return <span className="model">
|
return <span className="model">
|
||||||
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent="[...]">
|
<ModelCollapse title={titleEl} collapsed={ depth > expandDepth } collapsedContent="[...]">
|
||||||
[
|
[
|
||||||
<span><Model { ...this.props } schema={ items } required={ false }/></span>
|
<span><Model { ...this.props } schema={ items } required={ false } depth={ depth + 1 } /></span>
|
||||||
]
|
]
|
||||||
{
|
{
|
||||||
properties.size ? <span>
|
properties.size ? <span>
|
||||||
@@ -41,7 +41,6 @@ export default class ArrayModel extends Component {
|
|||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
</ModelCollapse>
|
</ModelCollapse>
|
||||||
{ required && <span style={{ color: "red" }}>*</span>}
|
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ const noop = ()=>{}
|
|||||||
export default class ContentType extends React.Component {
|
export default class ContentType extends React.Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
contentTypes: PropTypes.oneOfType([ImPropTypes.list, ImPropTypes.set]),
|
contentTypes: PropTypes.oneOfType([ImPropTypes.list, ImPropTypes.set, ImPropTypes.seq]),
|
||||||
value: PropTypes.string,
|
value: PropTypes.string,
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
className: PropTypes.string
|
className: PropTypes.string
|
||||||
@@ -22,7 +22,9 @@ export default class ContentType extends React.Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// Needed to populate the form, initially
|
// Needed to populate the form, initially
|
||||||
this.props.onChange(this.props.contentTypes.first())
|
if(this.props.contentTypes) {
|
||||||
|
this.props.onChange(this.props.contentTypes.first())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeWrapper = e => this.props.onChange(e.target.value)
|
onChangeWrapper = e => this.props.onChange(e.target.value)
|
||||||
|
|||||||
@@ -88,12 +88,13 @@ export default class Info extends React.Component {
|
|||||||
const { url:externalDocsUrl, description:externalDocsDescription } = (externalDocs || fromJS({})).toJS()
|
const { url:externalDocsUrl, description:externalDocsDescription } = (externalDocs || fromJS({})).toJS()
|
||||||
|
|
||||||
const Markdown = getComponent("Markdown")
|
const Markdown = getComponent("Markdown")
|
||||||
|
const VersionStamp = getComponent("VersionStamp")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="info">
|
<div className="info">
|
||||||
<hgroup className="main">
|
<hgroup className="main">
|
||||||
<h2 className="title" >{ title }
|
<h2 className="title" >{ title }
|
||||||
{ version && <small><pre className="version"> { version } </pre></small> }
|
{ version && <VersionStamp version={version}></VersionStamp> }
|
||||||
</h2>
|
</h2>
|
||||||
{ host || basePath ? <Path host={ host } basePath={ basePath } /> : null }
|
{ host || basePath ? <Path host={ host } basePath={ basePath } /> : null }
|
||||||
{ url && <a target="_blank" href={ url }><span className="url"> { url } </span></a> }
|
{ url && <a target="_blank" href={ url }><span className="url"> { url } </span></a> }
|
||||||
|
|||||||
@@ -129,7 +129,8 @@ export class Select extends React.Component {
|
|||||||
value: PropTypes.any,
|
value: PropTypes.any,
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
multiple: PropTypes.bool,
|
multiple: PropTypes.bool,
|
||||||
allowEmptyValue: PropTypes.bool
|
allowEmptyValue: PropTypes.bool,
|
||||||
|
className: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
@@ -142,7 +143,7 @@ export class Select extends React.Component {
|
|||||||
|
|
||||||
let value
|
let value
|
||||||
|
|
||||||
if (props.value !== undefined) {
|
if (props.value) {
|
||||||
value = props.value
|
value = props.value
|
||||||
} else {
|
} else {
|
||||||
value = props.multiple ? [""] : ""
|
value = props.multiple ? [""] : ""
|
||||||
@@ -178,7 +179,7 @@ export class Select extends React.Component {
|
|||||||
let value = this.state.value.toJS ? this.state.value.toJS() : this.state.value
|
let value = this.state.value.toJS ? this.state.value.toJS() : this.state.value
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<select multiple={ multiple } value={ value } onChange={ this.onChange } >
|
<select className={this.props.className} multiple={ multiple } value={ value } onChange={ this.onChange } >
|
||||||
{ allowEmptyValue ? <option value="">--</option> : null }
|
{ allowEmptyValue ? <option value="">--</option> : null }
|
||||||
{
|
{
|
||||||
allowedValues.map(function (item, key) {
|
allowedValues.map(function (item, key) {
|
||||||
|
|||||||
@@ -69,7 +69,10 @@ export default class BaseLayout extends React.Component {
|
|||||||
<div className="scheme-container">
|
<div className="scheme-container">
|
||||||
<Col className="schemes wrapper" mobile={12}>
|
<Col className="schemes wrapper" mobile={12}>
|
||||||
{ schemes && schemes.size ? (
|
{ schemes && schemes.size ? (
|
||||||
<Schemes schemes={ schemes } specActions={ specActions } />
|
<Schemes
|
||||||
|
currentScheme={specSelectors.operationScheme()}
|
||||||
|
schemes={ schemes }
|
||||||
|
specActions={ specActions } />
|
||||||
) : null }
|
) : null }
|
||||||
|
|
||||||
{ securityDefinitions ? (
|
{ securityDefinitions ? (
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ export default class ModelExample extends React.Component {
|
|||||||
<li className={ "tabitem" + ( isExecute || this.state.activeTab === "example" ? " active" : "") }>
|
<li className={ "tabitem" + ( isExecute || this.state.activeTab === "example" ? " active" : "") }>
|
||||||
<a className="tablinks" data-name="example" onClick={ this.activeTab }>Example Value</a>
|
<a className="tablinks" data-name="example" onClick={ this.activeTab }>Example Value</a>
|
||||||
</li>
|
</li>
|
||||||
<li className={ "tabitem" + ( !isExecute && this.state.activeTab === "model" ? " active" : "") }>
|
{ schema ? <li className={ "tabitem" + ( !isExecute && this.state.activeTab === "model" ? " active" : "") }>
|
||||||
<a className={ "tablinks" + ( isExecute ? " inactive" : "" )} data-name="model" onClick={ this.activeTab }>Model</a>
|
<a className={ "tablinks" + ( isExecute ? " inactive" : "" )} data-name="model" onClick={ this.activeTab }>Model</a>
|
||||||
</li>
|
</li> : null }
|
||||||
</ul>
|
</ul>
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ export default class Model extends Component {
|
|||||||
if ( ref.indexOf("#/definitions/") !== -1 ) {
|
if ( ref.indexOf("#/definitions/") !== -1 ) {
|
||||||
return ref.replace(/^.*#\/definitions\//, "")
|
return ref.replace(/^.*#\/definitions\//, "")
|
||||||
}
|
}
|
||||||
|
if ( ref.indexOf("#/components/schemas/") !== -1 ) {
|
||||||
|
return ref.replace("#/components/schemas/", "")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getRefSchema =( model )=> {
|
getRefSchema =( model )=> {
|
||||||
@@ -26,7 +29,7 @@ export default class Model extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { schema, getComponent, required, name, isRef } = this.props
|
let { getComponent, specSelectors, schema, required, name, isRef } = this.props
|
||||||
let ObjectModel = getComponent("ObjectModel")
|
let ObjectModel = getComponent("ObjectModel")
|
||||||
let ArrayModel = getComponent("ArrayModel")
|
let ArrayModel = getComponent("ArrayModel")
|
||||||
let PrimitiveModel = getComponent("PrimitiveModel")
|
let PrimitiveModel = getComponent("PrimitiveModel")
|
||||||
@@ -34,6 +37,8 @@ export default class Model extends Component {
|
|||||||
let modelName = $$ref && this.getModelName( $$ref )
|
let modelName = $$ref && this.getModelName( $$ref )
|
||||||
let modelSchema, type
|
let modelSchema, type
|
||||||
|
|
||||||
|
const deprecated = specSelectors.isOAS3() && schema.get("deprecated")
|
||||||
|
|
||||||
if ( schema && (schema.get("type") || schema.get("properties")) ) {
|
if ( schema && (schema.get("type") || schema.get("properties")) ) {
|
||||||
modelSchema = schema
|
modelSchema = schema
|
||||||
} else if ( $$ref ) {
|
} else if ( $$ref ) {
|
||||||
@@ -47,17 +52,30 @@ export default class Model extends Component {
|
|||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case "object":
|
case "object":
|
||||||
return <ObjectModel className="object" { ...this.props } schema={ modelSchema }
|
return <ObjectModel
|
||||||
name={ name || modelName }
|
className="object" { ...this.props }
|
||||||
isRef={ isRef!== undefined ? isRef : !!$$ref }/>
|
schema={ modelSchema }
|
||||||
|
name={ modelName || name }
|
||||||
|
deprecated={deprecated}
|
||||||
|
isRef={ isRef!== undefined ? isRef : !!$$ref } />
|
||||||
case "array":
|
case "array":
|
||||||
return <ArrayModel className="array" { ...this.props } schema={ modelSchema } required={ required } />
|
return <ArrayModel
|
||||||
|
className="array" { ...this.props }
|
||||||
|
schema={ modelSchema }
|
||||||
|
name={ modelName || name }
|
||||||
|
deprecated={deprecated}
|
||||||
|
required={ required } />
|
||||||
case "string":
|
case "string":
|
||||||
case "number":
|
case "number":
|
||||||
case "integer":
|
case "integer":
|
||||||
case "boolean":
|
case "boolean":
|
||||||
default:
|
default:
|
||||||
return <PrimitiveModel getComponent={ getComponent } schema={ modelSchema } required={ required }/>
|
return <PrimitiveModel
|
||||||
}
|
{ ...this.props }
|
||||||
|
getComponent={ getComponent }
|
||||||
|
schema={ modelSchema }
|
||||||
|
name={ modelName || name }
|
||||||
|
deprecated={deprecated}
|
||||||
|
required={ required }/> }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@ export default class Models extends Component {
|
|||||||
<h4 onClick={() => layoutActions.show("models", !showModels)}>
|
<h4 onClick={() => layoutActions.show("models", !showModels)}>
|
||||||
<span>Models</span>
|
<span>Models</span>
|
||||||
<svg width="20" height="20">
|
<svg width="20" height="20">
|
||||||
<use href="#large-arrow" xlinkHref="#large-arrow" />
|
<use xlinkHref={showModels ? "#large-arrow-down" : "#large-arrow"} />
|
||||||
</svg>
|
</svg>
|
||||||
</h4>
|
</h4>
|
||||||
<Collapse isOpened={showModels}>
|
<Collapse isOpened={showModels}>
|
||||||
|
|||||||
@@ -17,20 +17,25 @@ export default class ObjectModel extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
let { schema, name, isRef, getComponent, depth, ...props } = this.props
|
let { schema, name, isRef, getComponent, depth, expandDepth, ...otherProps } = this.props
|
||||||
let { expandDepth } = this.props
|
let { specSelectors } = otherProps
|
||||||
|
let { isOAS3 } = specSelectors
|
||||||
|
|
||||||
let description = schema.get("description")
|
let description = schema.get("description")
|
||||||
let properties = schema.get("properties")
|
let properties = schema.get("properties")
|
||||||
let additionalProperties = schema.get("additionalProperties")
|
let additionalProperties = schema.get("additionalProperties")
|
||||||
let title = schema.get("title") || name
|
let title = schema.get("title") || name
|
||||||
let required = schema.get("required")
|
let requiredProperties = schema.get("required")
|
||||||
|
|
||||||
const JumpToPath = getComponent("JumpToPath", true)
|
const JumpToPath = getComponent("JumpToPath", true)
|
||||||
const Markdown = getComponent("Markdown")
|
const Markdown = getComponent("Markdown")
|
||||||
const Model = getComponent("Model")
|
const Model = getComponent("Model")
|
||||||
const ModelCollapse = getComponent("ModelCollapse")
|
const ModelCollapse = getComponent("ModelCollapse")
|
||||||
|
|
||||||
const JumpToPathSection = ({ name }) => <span className="model-jump-to-path"><JumpToPath path={`definitions.${name}`} /></span>
|
const JumpToPathSection = ({ name }) => {
|
||||||
|
const path = isOAS3 && isOAS3() ? `components.schemas.${name}` : `definitions.${name}`
|
||||||
|
return <span className="model-jump-to-path"><JumpToPath path={path} /></span>
|
||||||
|
}
|
||||||
const collapsedContent = (<span>
|
const collapsedContent = (<span>
|
||||||
<span>{ braceOpen }</span>...<span>{ braceClose }</span>
|
<span>{ braceOpen }</span>...<span>{ braceClose }</span>
|
||||||
{
|
{
|
||||||
@@ -38,6 +43,10 @@ export default class ObjectModel extends Component {
|
|||||||
}
|
}
|
||||||
</span>)
|
</span>)
|
||||||
|
|
||||||
|
const anyOf = specSelectors.isOAS3() ? schema.get("anyOf") : null
|
||||||
|
const oneOf = specSelectors.isOAS3() ? schema.get("oneOf") : null
|
||||||
|
const not = specSelectors.isOAS3() ? schema.get("not") : null
|
||||||
|
|
||||||
const titleEl = title && <span className="model-title">
|
const titleEl = 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>
|
||||||
@@ -51,7 +60,7 @@ export default class ObjectModel extends Component {
|
|||||||
}
|
}
|
||||||
<span className="inner-object">
|
<span className="inner-object">
|
||||||
{
|
{
|
||||||
<table className="model" style={{ marginLeft: "2em" }}><tbody>
|
<table className="model"><tbody>
|
||||||
{
|
{
|
||||||
!description ? null : <tr style={{ color: "#999", fontStyle: "italic" }}>
|
!description ? null : <tr style={{ color: "#999", fontStyle: "italic" }}>
|
||||||
<td>description:</td>
|
<td>description:</td>
|
||||||
@@ -63,16 +72,18 @@ export default class ObjectModel extends Component {
|
|||||||
{
|
{
|
||||||
!(properties && properties.size) ? null : properties.entrySeq().map(
|
!(properties && properties.size) ? null : properties.entrySeq().map(
|
||||||
([key, value]) => {
|
([key, value]) => {
|
||||||
let isRequired = List.isList(required) && required.contains(key)
|
let isRequired = List.isList(requiredProperties) && requiredProperties.contains(key)
|
||||||
let propertyStyle = { verticalAlign: "top", paddingRight: "0.2em" }
|
let propertyStyle = { verticalAlign: "top", paddingRight: "0.2em" }
|
||||||
if ( isRequired ) {
|
if ( isRequired ) {
|
||||||
propertyStyle.fontWeight = "bold"
|
propertyStyle.fontWeight = "bold"
|
||||||
}
|
}
|
||||||
|
|
||||||
return (<tr key={key}>
|
return (<tr key={key}>
|
||||||
<td style={ propertyStyle }>{ key }:</td>
|
<td style={ propertyStyle }>
|
||||||
|
{ key }{ isRequired && <span style={{ color: "red" }}>*</span> }
|
||||||
|
</td>
|
||||||
<td style={{ verticalAlign: "top" }}>
|
<td style={{ verticalAlign: "top" }}>
|
||||||
<Model key={ `object-${name}-${key}_${value}` } { ...props }
|
<Model key={ `object-${name}-${key}_${value}` } { ...otherProps }
|
||||||
required={ isRequired }
|
required={ isRequired }
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
schema={ value }
|
schema={ value }
|
||||||
@@ -86,13 +97,55 @@ export default class ObjectModel extends Component {
|
|||||||
: <tr>
|
: <tr>
|
||||||
<td>{ "< * >:" }</td>
|
<td>{ "< * >:" }</td>
|
||||||
<td>
|
<td>
|
||||||
<Model { ...props } required={ false }
|
<Model { ...otherProps } required={ false }
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
schema={ additionalProperties }
|
schema={ additionalProperties }
|
||||||
depth={ depth + 1 } />
|
depth={ depth + 1 } />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
!anyOf ? null
|
||||||
|
: <tr>
|
||||||
|
<td>{ "anyOf ->" }</td>
|
||||||
|
<td>
|
||||||
|
{anyOf.map((schema, k) => {
|
||||||
|
return <div key={k}><Model { ...otherProps } required={ false }
|
||||||
|
getComponent={ getComponent }
|
||||||
|
schema={ schema }
|
||||||
|
depth={ depth + 1 } /></div>
|
||||||
|
})}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
!oneOf ? null
|
||||||
|
: <tr>
|
||||||
|
<td>{ "oneOf ->" }</td>
|
||||||
|
<td>
|
||||||
|
{oneOf.map((schema, k) => {
|
||||||
|
return <div key={k}><Model { ...otherProps } required={ false }
|
||||||
|
getComponent={ getComponent }
|
||||||
|
schema={ schema }
|
||||||
|
depth={ depth + 1 } /></div>
|
||||||
|
})}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
!not ? null
|
||||||
|
: <tr>
|
||||||
|
<td>{ "not ->" }</td>
|
||||||
|
<td>
|
||||||
|
{not.map((schema, k) => {
|
||||||
|
return <div key={k}><Model { ...otherProps } required={ false }
|
||||||
|
getComponent={ getComponent }
|
||||||
|
schema={ schema }
|
||||||
|
depth={ depth + 1 } /></div>
|
||||||
|
})}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
</tbody></table>
|
</tbody></table>
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ export default class Operation extends PureComponent {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Collapse isOpened={shown} animated>
|
<Collapse isOpened={shown}>
|
||||||
<div className="opblock-body">
|
<div className="opblock-body">
|
||||||
{ deprecated && <h4 className="opblock-title_normal"> Warning: Deprecated</h4>}
|
{ deprecated && <h4 className="opblock-title_normal"> Warning: Deprecated</h4>}
|
||||||
{ description &&
|
{ description &&
|
||||||
@@ -210,6 +210,7 @@ export default class Operation extends PureComponent {
|
|||||||
}
|
}
|
||||||
<Parameters
|
<Parameters
|
||||||
parameters={parameters}
|
parameters={parameters}
|
||||||
|
operation={operation}
|
||||||
onChangeKey={onChangeKey}
|
onChangeKey={onChangeKey}
|
||||||
onTryoutClick = { this.onTryoutClick }
|
onTryoutClick = { this.onTryoutClick }
|
||||||
onCancelClick = { this.onCancelClick }
|
onCancelClick = { this.onCancelClick }
|
||||||
@@ -228,7 +229,7 @@ export default class Operation extends PureComponent {
|
|||||||
path={ path }
|
path={ path }
|
||||||
method={ method }
|
method={ method }
|
||||||
specActions={ specActions }
|
specActions={ specActions }
|
||||||
operationScheme={ operationScheme } />
|
currentScheme={ operationScheme } />
|
||||||
</div> : null
|
</div> : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ export default class Operations extends React.Component {
|
|||||||
taggedOps.map( (tagObj, tag) => {
|
taggedOps.map( (tagObj, tag) => {
|
||||||
let operations = tagObj.get("operations")
|
let operations = tagObj.get("operations")
|
||||||
let tagDescription = tagObj.getIn(["tagDetails", "description"], null)
|
let tagDescription = tagObj.getIn(["tagDetails", "description"], null)
|
||||||
|
let tagExternalDocsDescription = tagObj.getIn(["tagDetails", "externalDocs", "description"])
|
||||||
|
let tagExternalDocsUrl = tagObj.getIn(["tagDetails", "externalDocs", "url"])
|
||||||
|
|
||||||
let isShownKey = ["operations-tag", tag]
|
let isShownKey = ["operations-tag", tag]
|
||||||
let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list")
|
let showTag = layoutSelectors.isShown(isShownKey, docExpansion === "full" || docExpansion === "list")
|
||||||
@@ -89,6 +91,22 @@ export default class Operations extends React.Component {
|
|||||||
</small>
|
</small>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{ !tagExternalDocsDescription ? null :
|
||||||
|
<small>
|
||||||
|
{ tagExternalDocsDescription }
|
||||||
|
{ tagExternalDocsUrl ? ": " : null }
|
||||||
|
{ tagExternalDocsUrl ?
|
||||||
|
<a
|
||||||
|
href={tagExternalDocsUrl}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
target={"_blank"}
|
||||||
|
>{tagExternalDocsUrl}</a> : null
|
||||||
|
}
|
||||||
|
</small>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
<button className="expand-operation" title="Expand operation" onClick={() => layoutActions.show(isShownKey, !showTag)}>
|
<button className="expand-operation" title="Expand operation" onClick={() => layoutActions.show(isShownKey, !showTag)}>
|
||||||
<svg className="arrow" width="20" height="20">
|
<svg className="arrow" width="20" height="20">
|
||||||
<use href={showTag ? "#large-arrow-down" : "#large-arrow"} xlinkHref={showTag ? "#large-arrow-down" : "#large-arrow"} />
|
<use href={showTag ? "#large-arrow-down" : "#large-arrow"} xlinkHref={showTag ? "#large-arrow-down" : "#large-arrow"} />
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ export default class ParamBody extends PureComponent {
|
|||||||
let { param, fn:{inferSchema} } = this.props
|
let { param, fn:{inferSchema} } = this.props
|
||||||
let schema = inferSchema(param.toJS())
|
let schema = inferSchema(param.toJS())
|
||||||
|
|
||||||
return getSampleSchema(schema, xml)
|
return getSampleSchema(schema, xml, {
|
||||||
|
includeWriteOnly: true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange = (value, { isEditBox, isXml }) => {
|
onChange = (value, { isEditBox, isXml }) => {
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ export default class ParameterRow extends Component {
|
|||||||
render() {
|
render() {
|
||||||
let {param, onChange, getComponent, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props
|
let {param, onChange, getComponent, isExecute, fn, onChangeConsumes, specSelectors, pathMethod} = this.props
|
||||||
|
|
||||||
|
let { isOAS3 } = specSelectors
|
||||||
|
|
||||||
// const onChangeWrapper = (value) => onChange(param, value)
|
// const onChangeWrapper = (value) => onChange(param, value)
|
||||||
const JsonSchemaForm = getComponent("JsonSchemaForm")
|
const JsonSchemaForm = getComponent("JsonSchemaForm")
|
||||||
const ParamBody = getComponent("ParamBody")
|
const ParamBody = getComponent("ParamBody")
|
||||||
@@ -80,10 +82,11 @@ export default class ParameterRow extends Component {
|
|||||||
|
|
||||||
let schema = param.get("schema")
|
let schema = param.get("schema")
|
||||||
|
|
||||||
|
let type = isOAS3 && isOAS3() ? param.getIn(["schema", "type"]) : param.get("type")
|
||||||
let isFormData = inType === "formData"
|
let isFormData = inType === "formData"
|
||||||
let isFormDataSupported = "FormData" in win
|
let isFormDataSupported = "FormData" in win
|
||||||
let required = param.get("required")
|
let required = param.get("required")
|
||||||
let itemType = param.getIn(["items", "type"])
|
let itemType = param.getIn(isOAS3 && isOAS3() ? ["schema", "items", "type"] : ["items", "type"])
|
||||||
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
|
let parameter = specSelectors.getParameter(pathMethod, param.get("name"))
|
||||||
let value = parameter ? parameter.get("value") : ""
|
let value = parameter ? parameter.get("value") : ""
|
||||||
|
|
||||||
@@ -94,7 +97,10 @@ export default class ParameterRow extends Component {
|
|||||||
{ param.get("name") }
|
{ param.get("name") }
|
||||||
{ !required ? null : <span style={{color: "red"}}> *</span> }
|
{ !required ? null : <span style={{color: "red"}}> *</span> }
|
||||||
</div>
|
</div>
|
||||||
<div className="parameter__type">{ param.get("type") } { itemType && `[${itemType}]` }</div>
|
<div className="parameter__type">{ type } { itemType && `[${itemType}]` }</div>
|
||||||
|
<div className="parameter__deprecated">
|
||||||
|
{ isOAS3 && isOAS3() && param.get("deprecated") ? "deprecated": null }
|
||||||
|
</div>
|
||||||
<div className="parameter__in">({ param.get("in") })</div>
|
<div className="parameter__in">({ param.get("in") })</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ export default class Parameters extends Component {
|
|||||||
return (
|
return (
|
||||||
<div className="opblock-section">
|
<div className="opblock-section">
|
||||||
<div className="opblock-section-header">
|
<div className="opblock-section-header">
|
||||||
<h4 className="opblock-title">Parameters</h4>
|
<div className="tab-header">
|
||||||
|
<h4 className="opblock-title">Parameters</h4>
|
||||||
|
</div>
|
||||||
{ allowTryItOut ? (
|
{ allowTryItOut ? (
|
||||||
<TryItOutButton enabled={ tryItOutEnabled } onCancelClick={ onCancelClick } onTryoutClick={ onTryoutClick } />
|
<TryItOutButton enabled={ tryItOutEnabled } onCancelClick={ onCancelClick } onTryoutClick={ onTryoutClick } />
|
||||||
) : null }
|
) : null }
|
||||||
|
|||||||
@@ -7,11 +7,12 @@ export default class Primitive extends Component {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
schema: PropTypes.object.isRequired,
|
schema: PropTypes.object.isRequired,
|
||||||
getComponent: PropTypes.func.isRequired,
|
getComponent: PropTypes.func.isRequired,
|
||||||
required: PropTypes.bool
|
name: PropTypes.string,
|
||||||
|
depth: PropTypes.number
|
||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
let { schema, getComponent, required } = this.props
|
let { schema, getComponent, name, depth } = this.props
|
||||||
|
|
||||||
if(!schema || !schema.get) {
|
if(!schema || !schema.get) {
|
||||||
// don't render if schema isn't correctly formed
|
// don't render if schema isn't correctly formed
|
||||||
@@ -24,32 +25,34 @@ export default class Primitive extends Component {
|
|||||||
let enumArray = schema.get("enum")
|
let enumArray = schema.get("enum")
|
||||||
let description = schema.get("description")
|
let description = schema.get("description")
|
||||||
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
|
let properties = schema.filter( ( v, key) => ["enum", "type", "format", "description", "$$ref"].indexOf(key) === -1 )
|
||||||
let style = required ? { fontWeight: "bold" } : {}
|
|
||||||
const Markdown = getComponent("Markdown")
|
const Markdown = getComponent("Markdown")
|
||||||
const EnumModel = getComponent("EnumModel")
|
const EnumModel = getComponent("EnumModel")
|
||||||
|
|
||||||
return <span className="prop">
|
return <span className="model">
|
||||||
<span className="prop-type" style={ style }>{ type }</span> { required && <span style={{ color: "red" }}>*</span>}
|
<span className="prop">
|
||||||
{ format && <span className="prop-format">(${format})</span>}
|
{ name && <span className={`${depth === 1 && "model-title"} prop-name`}>{ name }</span> }
|
||||||
{
|
<span className="prop-type">{ type }</span>
|
||||||
properties.size ? properties.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={ propStyle }>
|
{ format && <span className="prop-format">(${format})</span>}
|
||||||
<br />{ key }: { String(v) }</span>)
|
{
|
||||||
: null
|
properties.size ? properties.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={ propStyle }>
|
||||||
}
|
<br />{ key }: { String(v) }</span>)
|
||||||
{
|
: null
|
||||||
!description ? null :
|
}
|
||||||
<Markdown source={ description } />
|
{
|
||||||
}
|
!description ? null :
|
||||||
{
|
<Markdown source={ description } />
|
||||||
xml && xml.size ? (<span><br /><span style={ propStyle }>xml:</span>
|
}
|
||||||
{
|
{
|
||||||
xml.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={ propStyle }><br/> {key}: { String(v) }</span>).toArray()
|
xml && xml.size ? (<span><br /><span style={ propStyle }>xml:</span>
|
||||||
}
|
{
|
||||||
</span>): null
|
xml.entrySeq().map( ( [ key, v ] ) => <span key={`${key}-${v}`} style={ propStyle }><br/> {key}: { String(v) }</span>).toArray()
|
||||||
}
|
}
|
||||||
{
|
</span>): null
|
||||||
enumArray && <EnumModel value={ enumArray } getComponent={ getComponent } />
|
}
|
||||||
}
|
{
|
||||||
|
enumArray && <EnumModel value={ enumArray } getComponent={ getComponent } />
|
||||||
|
}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,15 +3,8 @@ import PropTypes from "prop-types"
|
|||||||
import Remarkable from "react-remarkable"
|
import Remarkable from "react-remarkable"
|
||||||
import sanitize from "sanitize-html"
|
import sanitize from "sanitize-html"
|
||||||
|
|
||||||
const sanitizeOptions = {
|
|
||||||
textFilter: function(text) {
|
|
||||||
return text
|
|
||||||
.replace(/"/g, "\"")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Markdown({ source }) {
|
function Markdown({ source }) {
|
||||||
const sanitized = sanitize(source, sanitizeOptions)
|
const sanitized = sanitizer(source)
|
||||||
|
|
||||||
// sometimes the sanitizer returns "undefined" as a string
|
// sometimes the sanitizer returns "undefined" as a string
|
||||||
if(!source || !sanitized || sanitized === "undefined") {
|
if(!source || !sanitized || sanitized === "undefined") {
|
||||||
@@ -31,3 +24,14 @@ Markdown.propTypes = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default Markdown
|
export default Markdown
|
||||||
|
|
||||||
|
const sanitizeOptions = {
|
||||||
|
textFilter: function(text) {
|
||||||
|
return text
|
||||||
|
.replace(/"/g, "\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sanitizer(str) {
|
||||||
|
return sanitize(str, sanitizeOptions)
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export default class ResponseBody extends React.Component {
|
|||||||
|
|
||||||
// Image
|
// Image
|
||||||
} else if (/^image\//i.test(contentType)) {
|
} else if (/^image\//i.test(contentType)) {
|
||||||
bodyEl = <img src={ url } />
|
bodyEl = <img style={{ maxWidth: "100%" }} src={ window.URL.createObjectURL(content) } />
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
} else if (/^audio\//i.test(contentType)) {
|
} else if (/^audio\//i.test(contentType)) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import PropTypes from "prop-types"
|
import PropTypes from "prop-types"
|
||||||
import { fromJS } from "immutable"
|
import { fromJS, Seq } from "immutable"
|
||||||
import { getSampleSchema } from "core/utils"
|
import { getSampleSchema } from "core/utils"
|
||||||
|
|
||||||
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
|
const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
|
||||||
@@ -31,6 +31,13 @@ const getExampleComponent = ( sampleResponse, examples, HighlightCode ) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class Response extends React.Component {
|
export default class Response extends React.Component {
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
responseContentType: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
code: PropTypes.string.isRequired,
|
code: PropTypes.string.isRequired,
|
||||||
@@ -59,16 +66,34 @@ export default class Response extends React.Component {
|
|||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
let { inferSchema } = fn
|
let { inferSchema } = fn
|
||||||
|
let { isOAS3 } = specSelectors
|
||||||
|
|
||||||
let schema = inferSchema(response.toJS())
|
|
||||||
let headers = response.get("headers")
|
let headers = response.get("headers")
|
||||||
let examples = response.get("examples")
|
let examples = response.get("examples")
|
||||||
|
let links = response.get("links")
|
||||||
const Headers = getComponent("headers")
|
const Headers = getComponent("headers")
|
||||||
const HighlightCode = getComponent("highlightCode")
|
const HighlightCode = getComponent("highlightCode")
|
||||||
const ModelExample = getComponent("modelExample")
|
const ModelExample = getComponent("modelExample")
|
||||||
const Markdown = getComponent( "Markdown" )
|
const Markdown = getComponent( "Markdown" )
|
||||||
|
const OperationLink = getComponent("operationLink")
|
||||||
|
const ContentType = getComponent("contentType")
|
||||||
|
|
||||||
let sampleResponse = schema ? getSampleSchema(schema, contentType, { includeReadOnly: true }) : null
|
var sampleResponse
|
||||||
|
var schema
|
||||||
|
|
||||||
|
if(isOAS3()) {
|
||||||
|
let oas3SchemaForContentType = response.getIn(["content", this.state.responseContentType, "schema"])
|
||||||
|
sampleResponse = oas3SchemaForContentType ? getSampleSchema(oas3SchemaForContentType.toJS(), this.state.responseContentType, {
|
||||||
|
includeReadOnly: true
|
||||||
|
}) : null
|
||||||
|
schema = oas3SchemaForContentType ? inferSchema(oas3SchemaForContentType.toJS()) : null
|
||||||
|
} else {
|
||||||
|
schema = inferSchema(response.toJS())
|
||||||
|
sampleResponse = schema ? getSampleSchema(schema, contentType, {
|
||||||
|
includeReadOnly: true,
|
||||||
|
includeWriteOnly: true // writeOnly has no filtering effect in swagger 2.0
|
||||||
|
}) : null
|
||||||
|
}
|
||||||
let example = getExampleComponent( sampleResponse, examples, HighlightCode )
|
let example = getExampleComponent( sampleResponse, examples, HighlightCode )
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -82,6 +107,12 @@ export default class Response extends React.Component {
|
|||||||
<Markdown source={ response.get( "description" ) } />
|
<Markdown source={ response.get( "description" ) } />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{ isOAS3 ? <ContentType
|
||||||
|
value={this.state.responseContentType}
|
||||||
|
contentTypes={ response.get("content") ? response.get("content").keySeq() : Seq() }
|
||||||
|
onChange={(val) => this.setState({ responseContentType: val })}
|
||||||
|
className="response-content-type" /> : null }
|
||||||
|
|
||||||
{ example ? (
|
{ example ? (
|
||||||
<ModelExample
|
<ModelExample
|
||||||
getComponent={ getComponent }
|
getComponent={ getComponent }
|
||||||
@@ -94,8 +125,15 @@ export default class Response extends React.Component {
|
|||||||
<Headers headers={ headers }/>
|
<Headers headers={ headers }/>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
</td>
|
|
||||||
|
|
||||||
|
</td>
|
||||||
|
{specSelectors.isOAS3() ? <td className="col response-col_links">
|
||||||
|
{ links ?
|
||||||
|
links.toSeq().map((link, key) => {
|
||||||
|
return <OperationLink key={key} name={key} link={ link } getComponent={getComponent}/>
|
||||||
|
})
|
||||||
|
: <i>No links</i>}
|
||||||
|
</td> : null}
|
||||||
</tr>
|
</tr>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,13 +42,13 @@ export default class Responses extends React.Component {
|
|||||||
<div className="responses-wrapper">
|
<div className="responses-wrapper">
|
||||||
<div className="opblock-section-header">
|
<div className="opblock-section-header">
|
||||||
<h4>Responses</h4>
|
<h4>Responses</h4>
|
||||||
<label>
|
{ specSelectors.isOAS3() ? null : <label>
|
||||||
<span>Response content type</span>
|
<span>Response content type</span>
|
||||||
<ContentType value={producesValue}
|
<ContentType value={producesValue}
|
||||||
onChange={this.onChangeProducesWrapper}
|
onChange={this.onChangeProducesWrapper}
|
||||||
contentTypes={produces}
|
contentTypes={produces}
|
||||||
className="execute-content-type"/>
|
className="execute-content-type"/>
|
||||||
</label>
|
</label> }
|
||||||
</div>
|
</div>
|
||||||
<div className="responses-inner">
|
<div className="responses-inner">
|
||||||
{
|
{
|
||||||
@@ -68,6 +68,7 @@ export default class Responses extends React.Component {
|
|||||||
<tr className="responses-header">
|
<tr className="responses-header">
|
||||||
<td className="col col_header response-col_status">Code</td>
|
<td className="col col_header response-col_status">Code</td>
|
||||||
<td className="col col_header response-col_description">Description</td>
|
<td className="col col_header response-col_description">Description</td>
|
||||||
|
{ specSelectors.isOAS3() ? <td className="col col_header response-col_links">Links</td> : null }
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ export default class Schemes extends React.Component {
|
|||||||
static propTypes = {
|
static propTypes = {
|
||||||
specActions: PropTypes.object.isRequired,
|
specActions: PropTypes.object.isRequired,
|
||||||
schemes: PropTypes.object.isRequired,
|
schemes: PropTypes.object.isRequired,
|
||||||
|
currentScheme: PropTypes.string.isRequired,
|
||||||
path: PropTypes.string,
|
path: PropTypes.string,
|
||||||
method: PropTypes.string,
|
method: PropTypes.string,
|
||||||
operationScheme: PropTypes.string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
@@ -19,8 +19,9 @@ export default class Schemes extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if ( this.props.operationScheme && !nextProps.schemes.has(this.props.operationScheme) ) {
|
if ( !this.props.currentScheme || !nextProps.schemes.includes(this.props.currentScheme) ) {
|
||||||
//fire 'change' event if our selected scheme is no longer an option
|
// if we don't have a selected currentScheme or if our selected scheme is no longer an option,
|
||||||
|
// then fire 'change' event and select the first scheme in the list of options
|
||||||
this.setScheme(nextProps.schemes.first())
|
this.setScheme(nextProps.schemes.first())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/core/components/version-stamp.jsx
Normal file
12
src/core/components/version-stamp.jsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
|
||||||
|
const VersionStamp = ({ version }) => {
|
||||||
|
return <small><pre className="version"> { version } </pre></small>
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionStamp.propTypes = {
|
||||||
|
version: PropTypes.string.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VersionStamp
|
||||||
@@ -20,7 +20,7 @@ export default function curl( request ){
|
|||||||
if ( request.get("body") ){
|
if ( request.get("body") ){
|
||||||
|
|
||||||
if(type === "multipart/form-data" && request.get("method") === "POST") {
|
if(type === "multipart/form-data" && request.get("method") === "POST") {
|
||||||
for( let [ k,v ] of request.get("body").values()) {
|
for( let [ k,v ] of request.get("body").entrySeq()) {
|
||||||
curlified.push( "-F" )
|
curlified.push( "-F" )
|
||||||
if (v instanceof win.File) {
|
if (v instanceof win.File) {
|
||||||
curlified.push( `"${k}=@${v.name};type=${v.type}"` )
|
curlified.push( `"${k}=@${v.name};type=${v.type}"` )
|
||||||
|
|||||||
@@ -4,34 +4,7 @@ import System from "core/system"
|
|||||||
import win from "core/window"
|
import win from "core/window"
|
||||||
import ApisPreset from "core/presets/apis"
|
import ApisPreset from "core/presets/apis"
|
||||||
import * as AllPlugins from "core/plugins/all"
|
import * as AllPlugins from "core/plugins/all"
|
||||||
import { parseSearch, filterConfigs } from "core/utils"
|
import { parseSearch } from "core/utils"
|
||||||
|
|
||||||
const CONFIGS = [
|
|
||||||
"url",
|
|
||||||
"urls",
|
|
||||||
"urls.primaryName",
|
|
||||||
"spec",
|
|
||||||
"validatorUrl",
|
|
||||||
"onComplete",
|
|
||||||
"onFailure",
|
|
||||||
"authorizations",
|
|
||||||
"docExpansion",
|
|
||||||
"tagsSorter",
|
|
||||||
"maxDisplayedTags",
|
|
||||||
"filter",
|
|
||||||
"operationsSorter",
|
|
||||||
"supportedSubmitMethods",
|
|
||||||
"dom_id",
|
|
||||||
"defaultModelRendering",
|
|
||||||
"oauth2RedirectUrl",
|
|
||||||
"showRequestHeaders",
|
|
||||||
"custom",
|
|
||||||
"modelPropertyMacro",
|
|
||||||
"parameterMacro",
|
|
||||||
"displayOperationId",
|
|
||||||
"displayRequestDuration",
|
|
||||||
"deepLinking",
|
|
||||||
]
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION, HOSTNAME, BUILD_TIME } = buildInfo
|
const { GIT_DIRTY, GIT_COMMIT, PACKAGE_VERSION, HOSTNAME, BUILD_TIME } = buildInfo
|
||||||
@@ -50,6 +23,7 @@ module.exports = function SwaggerUI(opts) {
|
|||||||
const defaults = {
|
const defaults = {
|
||||||
// Some general settings, that we floated to the top
|
// Some general settings, that we floated to the top
|
||||||
dom_id: null,
|
dom_id: null,
|
||||||
|
domNode: null,
|
||||||
spec: {},
|
spec: {},
|
||||||
url: "",
|
url: "",
|
||||||
urls: null,
|
urls: null,
|
||||||
@@ -126,7 +100,13 @@ module.exports = function SwaggerUI(opts) {
|
|||||||
|
|
||||||
let localConfig = system.specSelectors.getLocalConfig ? system.specSelectors.getLocalConfig() : {}
|
let localConfig = system.specSelectors.getLocalConfig ? system.specSelectors.getLocalConfig() : {}
|
||||||
let mergedConfig = deepExtend({}, localConfig, constructorConfig, fetchedConfig || {}, queryConfig)
|
let mergedConfig = deepExtend({}, localConfig, constructorConfig, fetchedConfig || {}, queryConfig)
|
||||||
store.setConfigs(filterConfigs(mergedConfig, CONFIGS))
|
|
||||||
|
// deep extend mangles domNode, we need to set it manually
|
||||||
|
if(opts.domNode) {
|
||||||
|
mergedConfig.domNode = opts.domNode
|
||||||
|
}
|
||||||
|
|
||||||
|
store.setConfigs(mergedConfig)
|
||||||
|
|
||||||
if (fetchedConfig !== null) {
|
if (fetchedConfig !== null) {
|
||||||
if (!queryConfig.url && typeof mergedConfig.spec === "object" && Object.keys(mergedConfig.spec).length) {
|
if (!queryConfig.url && typeof mergedConfig.spec === "object" && Object.keys(mergedConfig.spec).length) {
|
||||||
@@ -139,10 +119,13 @@ module.exports = function SwaggerUI(opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mergedConfig.dom_id) {
|
if(mergedConfig.domNode) {
|
||||||
system.render(mergedConfig.dom_id, "App")
|
system.render(mergedConfig.domNode, "App")
|
||||||
|
} else if(mergedConfig.dom_id) {
|
||||||
|
let domNode = document.querySelector(mergedConfig.dom_id)
|
||||||
|
system.render(domNode, "App")
|
||||||
} else {
|
} else {
|
||||||
console.error("Skipped rendering: no `dom_id` was specified")
|
console.error("Skipped rendering: no `dom_id` or `domNode` was specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
return system
|
return system
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ export class JsonSchema_string extends Component {
|
|||||||
|
|
||||||
if ( enumValue ) {
|
if ( enumValue ) {
|
||||||
const Select = getComponent("Select")
|
const Select = getComponent("Select")
|
||||||
return (<Select allowedValues={ enumValue }
|
return (<Select className={ errors.length ? "invalid" : ""}
|
||||||
|
allowedValues={ enumValue }
|
||||||
value={ value }
|
value={ value }
|
||||||
allowEmptyValue={ !required }
|
allowEmptyValue={ !required }
|
||||||
onChange={ this.onEnumChange }/>)
|
onChange={ this.onEnumChange }/>)
|
||||||
@@ -121,6 +122,7 @@ export class JsonSchema_array extends PureComponent {
|
|||||||
render() {
|
render() {
|
||||||
let { getComponent, required, schema, fn } = this.props
|
let { getComponent, required, schema, fn } = this.props
|
||||||
|
|
||||||
|
let errors = schema.errors || []
|
||||||
let itemSchema = fn.inferSchema(schema.items)
|
let itemSchema = fn.inferSchema(schema.items)
|
||||||
|
|
||||||
const JsonSchemaForm = getComponent("JsonSchemaForm")
|
const JsonSchemaForm = getComponent("JsonSchemaForm")
|
||||||
@@ -131,19 +133,17 @@ export class JsonSchema_array extends PureComponent {
|
|||||||
|
|
||||||
if ( enumValue ) {
|
if ( enumValue ) {
|
||||||
const Select = getComponent("Select")
|
const Select = getComponent("Select")
|
||||||
return (<Select multiple={ true }
|
return (<Select className={ errors.length ? "invalid" : ""}
|
||||||
|
multiple={ true }
|
||||||
value={ value }
|
value={ value }
|
||||||
allowedValues={ enumValue }
|
allowedValues={ enumValue }
|
||||||
allowEmptyValue={ !required }
|
allowEmptyValue={ !required }
|
||||||
onChange={ this.onEnumChange }/>)
|
onChange={ this.onEnumChange }/>)
|
||||||
}
|
}
|
||||||
|
|
||||||
let errors = schema.errors || []
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{ !value || value.count() < 1 ?
|
{ !value || value.count() < 1 ? null :
|
||||||
(errors.length ? <span style={{ color: "red", fortWeight: "bold" }}>{ errors[0] }</span> : null) :
|
|
||||||
value.map( (item,i) => {
|
value.map( (item,i) => {
|
||||||
let schema = Object.assign({}, itemSchema)
|
let schema = Object.assign({}, itemSchema)
|
||||||
if ( errors.length ) {
|
if ( errors.length ) {
|
||||||
@@ -153,12 +153,12 @@ export class JsonSchema_array extends PureComponent {
|
|||||||
return (
|
return (
|
||||||
<div key={i} className="json-schema-form-item">
|
<div key={i} className="json-schema-form-item">
|
||||||
<JsonSchemaForm fn={fn} getComponent={getComponent} value={item} onChange={(val) => this.onItemChange(val, i)} schema={schema} />
|
<JsonSchemaForm fn={fn} getComponent={getComponent} value={item} onChange={(val) => this.onItemChange(val, i)} schema={schema} />
|
||||||
<Button className="json-schema-form-item-remove" onClick={()=> this.removeItem(i)} > - </Button>
|
<Button className="btn btn-sm json-schema-form-item-remove" onClick={()=> this.removeItem(i)} > - </Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}).toArray()
|
}).toArray()
|
||||||
}
|
}
|
||||||
<Button className="json-schema-form-item-add" onClick={this.addItem}> Add item </Button>
|
<Button className={`btn btn-sm json-schema-form-item-add ${errors.length ? "invalid" : null}`} onClick={this.addItem}> Add item </Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -170,12 +170,14 @@ export class JsonSchema_boolean extends Component {
|
|||||||
|
|
||||||
onEnumChange = (val) => this.props.onChange(val)
|
onEnumChange = (val) => this.props.onChange(val)
|
||||||
render() {
|
render() {
|
||||||
let { getComponent, required, value } = this.props
|
let { getComponent, value, schema } = this.props
|
||||||
|
let errors = schema.errors || []
|
||||||
const Select = getComponent("Select")
|
const Select = getComponent("Select")
|
||||||
|
|
||||||
return (<Select value={ String(value) }
|
return (<Select className={ errors.length ? "invalid" : ""}
|
||||||
|
value={ String(value) }
|
||||||
allowedValues={ fromJS(["true", "false"]) }
|
allowedValues={ fromJS(["true", "false"]) }
|
||||||
allowEmptyValue={ !required }
|
allowEmptyValue={ true }
|
||||||
onChange={ this.onEnumChange }/>)
|
onChange={ this.onEnumChange }/>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,11 +68,21 @@ export default function authorize ( { auth, authActions, errActions, configs, au
|
|||||||
|
|
||||||
// pass action authorizeOauth2 and authentication data through window
|
// pass action authorizeOauth2 and authentication data through window
|
||||||
// to authorize with oauth2
|
// to authorize with oauth2
|
||||||
|
|
||||||
|
let callback
|
||||||
|
if (flow === "implicit") {
|
||||||
|
callback = authActions.preAuthorizeImplicit
|
||||||
|
} else if (authConfigs.useBasicAuthenticationWithAccessCodeGrant) {
|
||||||
|
callback = authActions.authorizeAccessCodeWithBasicAuthentication
|
||||||
|
} else {
|
||||||
|
callback = authActions.authorizeAccessCodeWithFormParams
|
||||||
|
}
|
||||||
|
|
||||||
win.swaggerUIRedirectOauth2 = {
|
win.swaggerUIRedirectOauth2 = {
|
||||||
auth: auth,
|
auth: auth,
|
||||||
state: state,
|
state: state,
|
||||||
redirectUrl: redirectUrl,
|
redirectUrl: redirectUrl,
|
||||||
callback: flow === "implicit" ? authActions.preAuthorizeImplicit : authActions.authorizeAccessCode,
|
callback: callback,
|
||||||
errCb: errActions.newAuthErr
|
errCb: errActions.newAuthErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ export const authorizeApplication = ( auth ) => ( { authActions } ) => {
|
|||||||
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth, headers })
|
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth, headers })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const authorizeAccessCode = ( { auth, redirectUrl } ) => ( { authActions } ) => {
|
export const authorizeAccessCodeWithFormParams = ( { auth, redirectUrl } ) => ( { authActions } ) => {
|
||||||
let { schema, name, clientId, clientSecret } = auth
|
let { schema, name, clientId, clientSecret } = auth
|
||||||
let form = {
|
let form = {
|
||||||
grant_type: "authorization_code",
|
grant_type: "authorization_code",
|
||||||
@@ -124,6 +124,21 @@ export const authorizeAccessCode = ( { auth, redirectUrl } ) => ( { authActions
|
|||||||
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth})
|
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const authorizeAccessCodeWithBasicAuthentication = ( { auth, redirectUrl } ) => ( { authActions } ) => {
|
||||||
|
let { schema, name, clientId, clientSecret } = auth
|
||||||
|
let headers = {
|
||||||
|
Authorization: "Basic " + btoa(clientId + ":" + clientSecret)
|
||||||
|
}
|
||||||
|
let form = {
|
||||||
|
grant_type: "authorization_code",
|
||||||
|
code: auth.code,
|
||||||
|
client_id: clientId,
|
||||||
|
redirect_uri: redirectUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
return authActions.authorizeRequest({body: buildFormData(form), name, url: schema.get("tokenUrl"), auth, headers})
|
||||||
|
}
|
||||||
|
|
||||||
export const authorizeRequest = ( data ) => ( { fn, authActions, errActions, authSelectors } ) => {
|
export const authorizeRequest = ( data ) => ( { fn, authActions, errActions, authSelectors } ) => {
|
||||||
let { body, query={}, headers={}, name, url, auth } = data
|
let { body, query={}, headers={}, name, url, auth } = data
|
||||||
let { additionalQueryStringParams } = authSelectors.getConfigs() || {}
|
let { additionalQueryStringParams } = authSelectors.getConfigs() || {}
|
||||||
@@ -135,7 +150,6 @@ export const authorizeRequest = ( data ) => ( { fn, authActions, errActions, aut
|
|||||||
|
|
||||||
let _headers = Object.assign({
|
let _headers = Object.assign({
|
||||||
"Accept":"application/json, text/plain, */*",
|
"Accept":"application/json, text/plain, */*",
|
||||||
"Access-Control-Allow-Origin": "*",
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded"
|
"Content-Type": "application/x-www-form-urlencoded"
|
||||||
}, headers)
|
}, headers)
|
||||||
|
|
||||||
|
|||||||
49
src/core/plugins/oas3/components/callbacks.jsx
Normal file
49
src/core/plugins/oas3/components/callbacks.jsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
|
||||||
|
const Callbacks = (props) => {
|
||||||
|
let { callbacks, getComponent } = props
|
||||||
|
// const Markdown = getComponent("Markdown")
|
||||||
|
const Operation = getComponent("operation", true)
|
||||||
|
|
||||||
|
if(!callbacks) {
|
||||||
|
return <span>No callbacks</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
let callbackElements = callbacks.map((callback, callbackName) => {
|
||||||
|
return <div key={callbackName}>
|
||||||
|
<h2>{callbackName}</h2>
|
||||||
|
{ callback.map((pathItem, pathItemName) => {
|
||||||
|
return <div key={pathItemName}>
|
||||||
|
{ pathItem.map((operation, method) => {
|
||||||
|
return <Operation
|
||||||
|
operation={operation}
|
||||||
|
key={method}
|
||||||
|
method={method}
|
||||||
|
isShownKey={["callbacks", operation.get("id"), callbackName]}
|
||||||
|
path={pathItemName}
|
||||||
|
allowTryItOut={false}
|
||||||
|
{...props}></Operation>
|
||||||
|
// return <pre>{JSON.stringify(operation)}</pre>
|
||||||
|
}) }
|
||||||
|
</div>
|
||||||
|
}) }
|
||||||
|
</div>
|
||||||
|
// return <div>
|
||||||
|
// <h2>{name}</h2>
|
||||||
|
// {callback.description && <Markdown source={callback.description}/>}
|
||||||
|
// <pre>{JSON.stringify(callback)}</pre>
|
||||||
|
// </div>
|
||||||
|
})
|
||||||
|
return <div>
|
||||||
|
{callbackElements}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
Callbacks.propTypes = {
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
callbacks: PropTypes.array.isRequired
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Callbacks
|
||||||
9
src/core/plugins/oas3/components/index.js
Normal file
9
src/core/plugins/oas3/components/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Callbacks from "./callbacks"
|
||||||
|
import RequestBody from "./request-body"
|
||||||
|
import OperationLink from "./operation-link.jsx"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Callbacks,
|
||||||
|
RequestBody,
|
||||||
|
operationLink: OperationLink
|
||||||
|
}
|
||||||
43
src/core/plugins/oas3/components/operation-link.jsx
Normal file
43
src/core/plugins/oas3/components/operation-link.jsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import React, { Component } from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import ImPropTypes from "react-immutable-proptypes"
|
||||||
|
|
||||||
|
class OperationLink extends Component {
|
||||||
|
render() {
|
||||||
|
const { link, name, getComponent } = this.props
|
||||||
|
|
||||||
|
const Markdown = getComponent("Markdown")
|
||||||
|
|
||||||
|
let targetOp = link.get("operationId") || link.get("operationRef")
|
||||||
|
let parameters = link.get("parameters") && link.get("parameters").toJS()
|
||||||
|
let description = link.get("description")
|
||||||
|
|
||||||
|
return <div style={{ marginBottom: "1.5em" }}>
|
||||||
|
<div style={{ marginBottom: ".5em" }}>
|
||||||
|
<b><code>{name}</code></b>
|
||||||
|
{ description ? <Markdown source={description}></Markdown> : null }
|
||||||
|
</div>
|
||||||
|
<pre>
|
||||||
|
Operation `{targetOp}`<br /><br />
|
||||||
|
Parameters {padString(0, JSON.stringify(parameters, null, 2)) || "{}"}<br />
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function padString(n, string) {
|
||||||
|
if(typeof string !== "string") { return "" }
|
||||||
|
return string
|
||||||
|
.split("\n")
|
||||||
|
.map((line, i) => i > 0 ? Array(n + 1).join(" ") + line : line)
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
OperationLink.propTypes = {
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
link: ImPropTypes.orderedMap.isRequired,
|
||||||
|
name: PropTypes.String
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OperationLink
|
||||||
44
src/core/plugins/oas3/components/request-body.jsx
Normal file
44
src/core/plugins/oas3/components/request-body.jsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import ImPropTypes from "react-immutable-proptypes"
|
||||||
|
import { OrderedMap } from "immutable"
|
||||||
|
import { getSampleSchema } from "core/utils"
|
||||||
|
|
||||||
|
|
||||||
|
const RequestBody = ({ requestBody, getComponent, specSelectors, contentType }) => {
|
||||||
|
const Markdown = getComponent("Markdown")
|
||||||
|
const ModelExample = getComponent("modelExample")
|
||||||
|
const HighlightCode = getComponent("highlightCode")
|
||||||
|
|
||||||
|
const requestBodyDescription = (requestBody && requestBody.get("description")) || null
|
||||||
|
const requestBodyContent = (requestBody && requestBody.get("content")) || new OrderedMap()
|
||||||
|
contentType = contentType || requestBodyContent.keySeq().first()
|
||||||
|
|
||||||
|
const mediaTypeValue = requestBodyContent.get(contentType)
|
||||||
|
|
||||||
|
const sampleSchema = getSampleSchema(mediaTypeValue.get("schema").toJS(), contentType, {
|
||||||
|
includeWriteOnly: true
|
||||||
|
})
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
{ requestBodyDescription &&
|
||||||
|
<Markdown source={requestBodyDescription} />
|
||||||
|
}
|
||||||
|
<ModelExample
|
||||||
|
getComponent={ getComponent }
|
||||||
|
specSelectors={ specSelectors }
|
||||||
|
expandDepth={1}
|
||||||
|
schema={mediaTypeValue.get("schema")}
|
||||||
|
example={<HighlightCode value={sampleSchema} />}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestBody.propTypes = {
|
||||||
|
requestBody: ImPropTypes.orderedMap.isRequired,
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
specSelectors: PropTypes.object.isRequired,
|
||||||
|
contentType: PropTypes.string.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RequestBody
|
||||||
36
src/core/plugins/oas3/helpers.js
Normal file
36
src/core/plugins/oas3/helpers.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import React from "react"
|
||||||
|
|
||||||
|
export function isOAS3(jsSpec) {
|
||||||
|
const oasVersion = jsSpec.get("openapi")
|
||||||
|
if(!oasVersion) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return oasVersion.startsWith("3.0.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSwagger2(jsSpec) {
|
||||||
|
const swaggerVersion = jsSpec.get("swagger")
|
||||||
|
if(!swaggerVersion) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return swaggerVersion.startsWith("2")
|
||||||
|
}
|
||||||
|
|
||||||
|
export function OAS3ComponentWrapFactory(Component) {
|
||||||
|
return (Ori, system) => (props) => {
|
||||||
|
if(system && system.specSelectors && system.specSelectors.specJson) {
|
||||||
|
const spec = system.specSelectors.specJson()
|
||||||
|
|
||||||
|
if(isOAS3(spec)) {
|
||||||
|
return <Component {...props} {...system} Ori={Ori}></Component>
|
||||||
|
} else {
|
||||||
|
return <Ori {...props}></Ori>
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("OAS3 wrapper: couldn't get spec")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/core/plugins/oas3/index.js
Normal file
17
src/core/plugins/oas3/index.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// import reducers from "./reducers"
|
||||||
|
// import * as actions from "./actions"
|
||||||
|
import * as wrapSelectors from "./wrap-selectors"
|
||||||
|
import components from "./components"
|
||||||
|
import wrapComponents from "./wrap-components"
|
||||||
|
|
||||||
|
export default function() {
|
||||||
|
return {
|
||||||
|
components,
|
||||||
|
wrapComponents,
|
||||||
|
statePlugins: {
|
||||||
|
spec: {
|
||||||
|
wrapSelectors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/core/plugins/oas3/wrap-components/index.js
Normal file
15
src/core/plugins/oas3/wrap-components/index.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import Markdown from "./markdown"
|
||||||
|
import parameters from "./parameters"
|
||||||
|
import VersionStamp from "./version-stamp"
|
||||||
|
import OnlineValidatorBadge from "./online-validator-badge"
|
||||||
|
import Model from "./model"
|
||||||
|
import TryItOutButton from "./try-it-out-button"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Markdown,
|
||||||
|
parameters,
|
||||||
|
VersionStamp,
|
||||||
|
model: Model,
|
||||||
|
onlineValidatorBadge: OnlineValidatorBadge,
|
||||||
|
TryItOutButton
|
||||||
|
}
|
||||||
11
src/core/plugins/oas3/wrap-components/markdown.js
Normal file
11
src/core/plugins/oas3/wrap-components/markdown.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import React from "react"
|
||||||
|
import ReactMarkdown from "react-markdown"
|
||||||
|
import { OAS3ComponentWrapFactory } from "../helpers"
|
||||||
|
import { sanitizer } from "core/components/providers/markdown"
|
||||||
|
|
||||||
|
export default OAS3ComponentWrapFactory(({ source }) => { return source ? (
|
||||||
|
<ReactMarkdown
|
||||||
|
source={sanitizer(source)}
|
||||||
|
className={"renderedMarkdown"}
|
||||||
|
/>
|
||||||
|
) : null})
|
||||||
36
src/core/plugins/oas3/wrap-components/model.jsx
Normal file
36
src/core/plugins/oas3/wrap-components/model.jsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import React, { Component } from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import { OAS3ComponentWrapFactory } from "../helpers"
|
||||||
|
import { Model } from "core/components/model"
|
||||||
|
|
||||||
|
class ModelComponent extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
schema: PropTypes.object.isRequired,
|
||||||
|
name: PropTypes.string,
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
specSelectors: PropTypes.object.isRequired,
|
||||||
|
expandDepth: PropTypes.number
|
||||||
|
}
|
||||||
|
|
||||||
|
render(){
|
||||||
|
let { schema } = this.props
|
||||||
|
let classes = ["model-box"]
|
||||||
|
let isDeprecated = schema.get("deprecated") === true
|
||||||
|
let message = null
|
||||||
|
|
||||||
|
if(isDeprecated) {
|
||||||
|
classes.push("deprecated")
|
||||||
|
message = <span className="model-deprecated-warning">Deprecated:</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className={classes.join(" ")}>
|
||||||
|
{message}
|
||||||
|
<Model { ...this.props }
|
||||||
|
depth={ 1 }
|
||||||
|
expandDepth={ this.props.expandDepth || 0 }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OAS3ComponentWrapFactory(ModelComponent)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { OAS3ComponentWrapFactory } from "../helpers"
|
||||||
|
|
||||||
|
// We're disabling the Online Validator Badge until the online validator
|
||||||
|
// can handle OAS3 specs.
|
||||||
|
export default OAS3ComponentWrapFactory(() => null)
|
||||||
181
src/core/plugins/oas3/wrap-components/parameters.jsx
Normal file
181
src/core/plugins/oas3/wrap-components/parameters.jsx
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
import React, { Component } from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import Im, { Map } from "immutable"
|
||||||
|
import ImPropTypes from "react-immutable-proptypes"
|
||||||
|
import { OAS3ComponentWrapFactory } from "../helpers"
|
||||||
|
|
||||||
|
// More readable, just iterate over maps, only
|
||||||
|
const eachMap = (iterable, fn) => iterable.valueSeq().filter(Im.Map.isMap).map(fn)
|
||||||
|
|
||||||
|
class Parameters extends Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
callbackVisible: false,
|
||||||
|
parametersVisible: true,
|
||||||
|
requestBodyContentType: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
parameters: ImPropTypes.list.isRequired,
|
||||||
|
specActions: PropTypes.object.isRequired,
|
||||||
|
operation: PropTypes.object.isRequired,
|
||||||
|
getComponent: PropTypes.func.isRequired,
|
||||||
|
specSelectors: PropTypes.object.isRequired,
|
||||||
|
fn: PropTypes.object.isRequired,
|
||||||
|
tryItOutEnabled: PropTypes.bool,
|
||||||
|
allowTryItOut: PropTypes.bool,
|
||||||
|
onTryoutClick: PropTypes.func,
|
||||||
|
onCancelClick: PropTypes.func,
|
||||||
|
onChangeKey: PropTypes.array,
|
||||||
|
pathMethod: PropTypes.array.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
onTryoutClick: Function.prototype,
|
||||||
|
onCancelClick: Function.prototype,
|
||||||
|
tryItOutEnabled: false,
|
||||||
|
allowTryItOut: true,
|
||||||
|
onChangeKey: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange = ( param, value, isXml ) => {
|
||||||
|
let {
|
||||||
|
specActions: { changeParam },
|
||||||
|
onChangeKey,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
changeParam( onChangeKey, param.get("name"), value, isXml)
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeConsumesWrapper = ( val ) => {
|
||||||
|
let {
|
||||||
|
specActions: { changeConsumesValue },
|
||||||
|
onChangeKey
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
changeConsumesValue(onChangeKey, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleTab = (tab) => {
|
||||||
|
if(tab === "parameters"){
|
||||||
|
return this.setState({
|
||||||
|
parametersVisible: true,
|
||||||
|
callbackVisible: false
|
||||||
|
})
|
||||||
|
}else if(tab === "callbacks"){
|
||||||
|
return this.setState({
|
||||||
|
callbackVisible: true,
|
||||||
|
parametersVisible: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(){
|
||||||
|
|
||||||
|
let {
|
||||||
|
onTryoutClick,
|
||||||
|
onCancelClick,
|
||||||
|
parameters,
|
||||||
|
allowTryItOut,
|
||||||
|
tryItOutEnabled,
|
||||||
|
|
||||||
|
fn,
|
||||||
|
getComponent,
|
||||||
|
specSelectors,
|
||||||
|
pathMethod,
|
||||||
|
operation
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
const ParameterRow = getComponent("parameterRow")
|
||||||
|
const TryItOutButton = getComponent("TryItOutButton")
|
||||||
|
const ContentType = getComponent("contentType")
|
||||||
|
const Callbacks = getComponent("Callbacks", true)
|
||||||
|
const RequestBody = getComponent("RequestBody", true)
|
||||||
|
|
||||||
|
const isExecute = tryItOutEnabled && allowTryItOut
|
||||||
|
const { isOAS3 } = specSelectors
|
||||||
|
|
||||||
|
const requestBody = operation.get("requestBody")
|
||||||
|
return (
|
||||||
|
<div className="opblock-section">
|
||||||
|
<div className="opblock-section-header">
|
||||||
|
<div className="tab-header">
|
||||||
|
<div onClick={() => this.toggleTab("parameters")} className={`tab-item ${this.state.parametersVisible && "active"}`}>
|
||||||
|
<h4 className="opblock-title"><span>Parameters</span></h4>
|
||||||
|
</div>
|
||||||
|
{ operation.get("callbacks") ?
|
||||||
|
(
|
||||||
|
<div onClick={() => this.toggleTab("callbacks")} className={`tab-item ${this.state.callbackVisible && "active"}`}>
|
||||||
|
<h4 className="opblock-title"><span>Callbacks</span></h4>
|
||||||
|
</div>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
{ allowTryItOut ? (
|
||||||
|
<TryItOutButton enabled={ tryItOutEnabled } onCancelClick={ onCancelClick } onTryoutClick={ onTryoutClick } />
|
||||||
|
) : null }
|
||||||
|
</div>
|
||||||
|
{this.state.parametersVisible ? <div className="parameters-container">
|
||||||
|
{ !parameters.count() ? <div className="opblock-description-wrapper"><p>No parameters</p></div> :
|
||||||
|
<div className="table-container">
|
||||||
|
<table className="parameters">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th className="col col_header parameters-col_name">Name</th>
|
||||||
|
<th className="col col_header parameters-col_description">Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{
|
||||||
|
eachMap(parameters, (parameter) => (
|
||||||
|
<ParameterRow fn={ fn }
|
||||||
|
getComponent={ getComponent }
|
||||||
|
param={ parameter }
|
||||||
|
key={ parameter.get( "name" ) }
|
||||||
|
onChange={ this.onChange }
|
||||||
|
onChangeConsumes={this.onChangeConsumesWrapper}
|
||||||
|
specSelectors={ specSelectors }
|
||||||
|
pathMethod={ pathMethod }
|
||||||
|
isExecute={ isExecute }/>
|
||||||
|
)).toArray()
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div> : "" }
|
||||||
|
|
||||||
|
{this.state.callbackVisible ? <div className="callbacks-container opblock-description-wrapper">
|
||||||
|
<Callbacks callbacks={Map(operation.get("callbacks"))} />
|
||||||
|
</div> : "" }
|
||||||
|
{
|
||||||
|
isOAS3() && requestBody && this.state.parametersVisible &&
|
||||||
|
<div className="opblock-section">
|
||||||
|
<div className="opblock-section-header">
|
||||||
|
<h4 className={`opblock-title parameter__name ${requestBody.get("required") && "required"}`}>Request body</h4>
|
||||||
|
<label>
|
||||||
|
<ContentType
|
||||||
|
value={this.state.requestBodyContentType}
|
||||||
|
contentTypes={ requestBody.get("content").keySeq() }
|
||||||
|
onChange={(val) => this.setState({ requestBodyContentType: val })}
|
||||||
|
className="body-param-content-type" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="opblock-description-wrapper">
|
||||||
|
<RequestBody
|
||||||
|
requestBody={requestBody}
|
||||||
|
contentType={this.state.requestBodyContentType}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default OAS3ComponentWrapFactory(Parameters)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { OAS3ComponentWrapFactory } from "../helpers"
|
||||||
|
|
||||||
|
export default OAS3ComponentWrapFactory(() => {
|
||||||
|
return null
|
||||||
|
})
|
||||||
13
src/core/plugins/oas3/wrap-components/version-stamp.jsx
Normal file
13
src/core/plugins/oas3/wrap-components/version-stamp.jsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import React from "react"
|
||||||
|
import { OAS3ComponentWrapFactory } from "../helpers"
|
||||||
|
|
||||||
|
export default OAS3ComponentWrapFactory((props) => {
|
||||||
|
const { Ori } = props
|
||||||
|
|
||||||
|
return <span>
|
||||||
|
<Ori {...props} />
|
||||||
|
<small style={{ backgroundColor: "#89bf04" }}>
|
||||||
|
<pre className="version">OAS3</pre>
|
||||||
|
</small>
|
||||||
|
</span>
|
||||||
|
})
|
||||||
67
src/core/plugins/oas3/wrap-selectors.js
Normal file
67
src/core/plugins/oas3/wrap-selectors.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { createSelector } from "reselect"
|
||||||
|
import { Map } from "immutable"
|
||||||
|
import { isOAS3 as isOAS3Helper, isSwagger2 as isSwagger2Helper } from "./helpers"
|
||||||
|
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
function onlyOAS3(selector) {
|
||||||
|
return (ori, system) => (...args) => {
|
||||||
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
|
if(isOAS3Helper(spec)) {
|
||||||
|
return selector(...args)
|
||||||
|
} else {
|
||||||
|
return ori(...args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = state => {
|
||||||
|
return state || Map()
|
||||||
|
}
|
||||||
|
|
||||||
|
const nullSelector = createSelector(() => null)
|
||||||
|
|
||||||
|
const OAS3NullSelector = onlyOAS3(nullSelector)
|
||||||
|
|
||||||
|
const specJson = createSelector(
|
||||||
|
state,
|
||||||
|
spec => spec.get("json", Map())
|
||||||
|
)
|
||||||
|
|
||||||
|
const specResolved = createSelector(
|
||||||
|
state,
|
||||||
|
spec => spec.get("resolved", Map())
|
||||||
|
)
|
||||||
|
|
||||||
|
const spec = state => {
|
||||||
|
let res = specResolved(state)
|
||||||
|
if(res.count() < 1)
|
||||||
|
res = specJson(state)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrappers
|
||||||
|
|
||||||
|
export const definitions = onlyOAS3(createSelector(
|
||||||
|
spec,
|
||||||
|
spec => spec.getIn(["components", "schemas"]) || Map()
|
||||||
|
))
|
||||||
|
|
||||||
|
export const host = OAS3NullSelector
|
||||||
|
export const basePath = OAS3NullSelector
|
||||||
|
export const consumes = OAS3NullSelector
|
||||||
|
export const produces = OAS3NullSelector
|
||||||
|
export const schemes = OAS3NullSelector
|
||||||
|
|
||||||
|
// New selectors
|
||||||
|
|
||||||
|
export const isOAS3 = (ori, system) => () => {
|
||||||
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
|
return isOAS3Helper(spec)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isSwagger2 = (ori, system) => () => {
|
||||||
|
const spec = system.getSystem().specSelectors.specJson()
|
||||||
|
return isSwagger2Helper(spec)
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ const primitive = (schema) => {
|
|||||||
|
|
||||||
export const sampleFromSchema = (schema, config={}) => {
|
export const sampleFromSchema = (schema, config={}) => {
|
||||||
let { type, example, properties, additionalProperties, items } = objectify(schema)
|
let { type, example, properties, additionalProperties, items } = objectify(schema)
|
||||||
let { includeReadOnly } = config
|
let { includeReadOnly, includeWriteOnly } = config
|
||||||
|
|
||||||
if(example !== undefined)
|
if(example !== undefined)
|
||||||
return example
|
return example
|
||||||
@@ -46,16 +46,20 @@ 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].readOnly && !includeReadOnly ) {
|
||||||
obj[name] = sampleFromSchema(props[name], { includeReadOnly: includeReadOnly })
|
continue
|
||||||
}
|
}
|
||||||
|
if ( props[name].writeOnly && !includeWriteOnly ) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
obj[name] = sampleFromSchema(props[name], config)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( additionalProperties === true ) {
|
if ( additionalProperties === true ) {
|
||||||
obj.additionalProp1 = {}
|
obj.additionalProp1 = {}
|
||||||
} else if ( additionalProperties ) {
|
} else if ( additionalProperties ) {
|
||||||
let additionalProps = objectify(additionalProperties)
|
let additionalProps = objectify(additionalProperties)
|
||||||
let additionalPropVal = sampleFromSchema(additionalProps, { includeReadOnly: includeReadOnly })
|
let additionalPropVal = sampleFromSchema(additionalProps, config)
|
||||||
|
|
||||||
for (let i = 1; i < 4; i++) {
|
for (let i = 1; i < 4; i++) {
|
||||||
obj["additionalProp" + i] = additionalPropVal
|
obj["additionalProp" + i] = additionalPropVal
|
||||||
@@ -65,7 +69,7 @@ export const sampleFromSchema = (schema, config={}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(type === "array") {
|
if(type === "array") {
|
||||||
return [ sampleFromSchema(items, { includeReadOnly: includeReadOnly }) ]
|
return [ sampleFromSchema(items, config) ]
|
||||||
}
|
}
|
||||||
|
|
||||||
if(schema["enum"]) {
|
if(schema["enum"]) {
|
||||||
@@ -96,7 +100,7 @@ export const inferSchema = (thing) => {
|
|||||||
export const sampleXmlFromSchema = (schema, config={}) => {
|
export const sampleXmlFromSchema = (schema, config={}) => {
|
||||||
let objectifySchema = objectify(schema)
|
let objectifySchema = objectify(schema)
|
||||||
let { type, properties, additionalProperties, items, example } = objectifySchema
|
let { type, properties, additionalProperties, items, example } = objectifySchema
|
||||||
let { includeReadOnly } = config
|
let { includeReadOnly, includeWriteOnly } = config
|
||||||
let defaultValue = objectifySchema.default
|
let defaultValue = objectifySchema.default
|
||||||
let res = {}
|
let res = {}
|
||||||
let _attr = {}
|
let _attr = {}
|
||||||
@@ -177,27 +181,32 @@ export const sampleXmlFromSchema = (schema, config={}) => {
|
|||||||
example = example || {}
|
example = example || {}
|
||||||
|
|
||||||
for (let propName in props) {
|
for (let propName in props) {
|
||||||
if ( !props[propName].readOnly || includeReadOnly ) {
|
if ( props[propName].readOnly && !includeReadOnly ) {
|
||||||
props[propName].xml = props[propName].xml || {}
|
continue
|
||||||
|
}
|
||||||
|
if ( props[propName].writeOnly && !includeWriteOnly ) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if (props[propName].xml.attribute) {
|
props[propName].xml = props[propName].xml || {}
|
||||||
let enumAttrVal = Array.isArray(props[propName].enum) && props[propName].enum[0]
|
|
||||||
let attrExample = props[propName].example
|
if (props[propName].xml.attribute) {
|
||||||
let attrDefault = props[propName].default
|
let enumAttrVal = Array.isArray(props[propName].enum) && props[propName].enum[0]
|
||||||
_attr[props[propName].xml.name || propName] = attrExample!== undefined && attrExample
|
let attrExample = props[propName].example
|
||||||
|| example[propName] !== undefined && example[propName] || attrDefault !== undefined && attrDefault
|
let attrDefault = props[propName].default
|
||||||
|| enumAttrVal || primitive(props[propName])
|
_attr[props[propName].xml.name || propName] = attrExample!== undefined && attrExample
|
||||||
|
|| example[propName] !== undefined && example[propName] || attrDefault !== undefined && attrDefault
|
||||||
|
|| 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]
|
||||||
|
let t = sampleXmlFromSchema(props[propName])
|
||||||
|
if (Array.isArray(t)) {
|
||||||
|
res[displayName] = res[displayName].concat(t)
|
||||||
} else {
|
} else {
|
||||||
props[propName].xml.name = props[propName].xml.name || propName
|
res[displayName].push(t)
|
||||||
props[propName].example = props[propName].example !== undefined ? props[propName].example : example[propName]
|
|
||||||
let t = sampleXmlFromSchema(props[propName])
|
|
||||||
if (Array.isArray(t)) {
|
|
||||||
res[displayName] = res[displayName].concat(t)
|
|
||||||
} else {
|
|
||||||
res[displayName].push(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,15 @@ export const spec = state => {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const isOAS3 = createSelector(
|
||||||
|
// isOAS3 is stubbed out here to work around an issue with injecting more selectors
|
||||||
|
// in the OAS3 plugin, and to ensure that the function is always available.
|
||||||
|
// It's not perfect, but our hybrid (core+plugin code) implementation for OAS3
|
||||||
|
// needs this. //KS
|
||||||
|
spec,
|
||||||
|
() => false
|
||||||
|
)
|
||||||
|
|
||||||
export const info = createSelector(
|
export const info = createSelector(
|
||||||
spec,
|
spec,
|
||||||
spec => returnSelfOrNewMap(spec && spec.get("info"))
|
spec => returnSelfOrNewMap(spec && spec.get("info"))
|
||||||
|
|||||||
@@ -58,8 +58,7 @@ export const makeMappedContainer = (getSystem, getStore, memGetComponent, getCom
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const render = (getSystem, getStore, getComponent, getComponents, dom) => {
|
export const render = (getSystem, getStore, getComponent, getComponents, domNode) => {
|
||||||
let domNode = document.querySelector(dom)
|
|
||||||
let App = (getComponent(getSystem, getStore, getComponents, "App", "root"))
|
let App = (getComponent(getSystem, getStore, getComponents, "App", "root"))
|
||||||
ReactDOM.render(( <App/> ), domNode)
|
ReactDOM.render(( <App/> ), domNode)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import BasePreset from "./base"
|
import BasePreset from "./base"
|
||||||
|
import OAS3Plugin from "../plugins/oas3"
|
||||||
|
|
||||||
// Just the base, for now.
|
// Just the base, for now.
|
||||||
|
|
||||||
@@ -6,5 +7,6 @@ export default function PresetApis() {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
BasePreset,
|
BasePreset,
|
||||||
|
OAS3Plugin
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import ObjectModel from "core/components/object-model"
|
|||||||
import ArrayModel from "core/components/array-model"
|
import ArrayModel from "core/components/array-model"
|
||||||
import PrimitiveModel from "core/components/primitive-model"
|
import PrimitiveModel from "core/components/primitive-model"
|
||||||
import TryItOutButton from "core/components/try-it-out-button"
|
import TryItOutButton from "core/components/try-it-out-button"
|
||||||
|
import VersionStamp from "core/components/version-stamp"
|
||||||
|
|
||||||
import Markdown from "core/components/providers/markdown"
|
import Markdown from "core/components/providers/markdown"
|
||||||
|
|
||||||
@@ -105,7 +106,8 @@ export default function() {
|
|||||||
PrimitiveModel,
|
PrimitiveModel,
|
||||||
TryItOutButton,
|
TryItOutButton,
|
||||||
Markdown,
|
Markdown,
|
||||||
BaseLayout
|
BaseLayout,
|
||||||
|
VersionStamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export default class Store {
|
|||||||
this.boundSystem = Object.assign({},
|
this.boundSystem = Object.assign({},
|
||||||
this.getRootInjects(),
|
this.getRootInjects(),
|
||||||
this.getWrappedAndBoundActions(dispatch),
|
this.getWrappedAndBoundActions(dispatch),
|
||||||
this.getBoundSelectors(getState, this.getSystem),
|
this.getWrappedAndBoundSelectors(getState, this.getSystem),
|
||||||
this.getStateThunks(getState),
|
this.getStateThunks(getState),
|
||||||
this.getFn(),
|
this.getFn(),
|
||||||
this.getConfigs()
|
this.getConfigs()
|
||||||
@@ -176,6 +176,36 @@ export default class Store {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getWrappedAndBoundSelectors(getState, getSystem) {
|
||||||
|
let selectorGroups = this.getBoundSelectors(getState, getSystem)
|
||||||
|
return objMap(selectorGroups, (selectors, selectorGroupName) => {
|
||||||
|
let stateName = [selectorGroupName.slice(0, -9)] // selectors = 9 chars
|
||||||
|
let wrappers = this.system.statePlugins[stateName].wrapSelectors
|
||||||
|
if(wrappers) {
|
||||||
|
return objMap(selectors, (selector, selectorName) => {
|
||||||
|
let wrap = wrappers[selectorName]
|
||||||
|
if(!wrap) {
|
||||||
|
return selector
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Array.isArray(wrap)) {
|
||||||
|
wrap = [wrap]
|
||||||
|
}
|
||||||
|
return wrap.reduce((acc, fn) => {
|
||||||
|
let wrappedSelector = (...args) => {
|
||||||
|
return fn(acc, this.getSystem())(getState().getIn(stateName), ...args)
|
||||||
|
}
|
||||||
|
if(!isFn(wrappedSelector)) {
|
||||||
|
throw new TypeError("wrapSelector needs to return a function that returns a new function (ie the wrapped action)")
|
||||||
|
}
|
||||||
|
return wrappedSelector
|
||||||
|
}, selector || Function.prototype)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return selectors
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
getStates(state) {
|
getStates(state) {
|
||||||
return Object.keys(this.system.statePlugins).reduce((obj, key) => {
|
return Object.keys(this.system.statePlugins).reduce((obj, key) => {
|
||||||
obj[key] = state.get(key)
|
obj[key] = state.get(key)
|
||||||
@@ -197,8 +227,17 @@ export default class Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getComponents(component) {
|
getComponents(component) {
|
||||||
if(typeof component !== "undefined")
|
const res = this.system.components[component]
|
||||||
|
|
||||||
|
if(Array.isArray(res)) {
|
||||||
|
return res.reduce((ori, wrapper) => {
|
||||||
|
return wrapper(ori, this.getSystem())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if(typeof component !== "undefined") {
|
||||||
return this.system.components[component]
|
return this.system.components[component]
|
||||||
|
}
|
||||||
|
|
||||||
return this.system.components
|
return this.system.components
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,6 +330,24 @@ function systemExtend(dest={}, src={}) {
|
|||||||
return dest
|
return dest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wrap components
|
||||||
|
// Parses existing components in the system, and prepares them for wrapping via getComponents
|
||||||
|
if(src.wrapComponents) {
|
||||||
|
objMap(src.wrapComponents, (wrapperFn, key) => {
|
||||||
|
const ori = dest.components[key]
|
||||||
|
if(ori && Array.isArray(ori)) {
|
||||||
|
dest.components[key] = ori.concat([wrapperFn])
|
||||||
|
} else if(ori) {
|
||||||
|
dest.components[key] = [ori, wrapperFn]
|
||||||
|
} else {
|
||||||
|
dest.components[key] = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
delete src.wrapComponents
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Account for wrapActions, make it an array and append to it
|
// Account for wrapActions, make it an array and append to it
|
||||||
// Modifies `src`
|
// Modifies `src`
|
||||||
// 80% of this code is just safe traversal. We need to address that ( ie: use a lib )
|
// 80% of this code is just safe traversal. We need to address that ( ie: use a lib )
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function fromJSOrdered (js) {
|
|||||||
return !isObject(js) ? js :
|
return !isObject(js) ? js :
|
||||||
Array.isArray(js) ?
|
Array.isArray(js) ?
|
||||||
Im.Seq(js).map(fromJSOrdered).toList() :
|
Im.Seq(js).map(fromJSOrdered).toList() :
|
||||||
Im.Seq(js).map(fromJSOrdered).toOrderedMap()
|
Im.OrderedMap(js).map(fromJSOrdered)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bindToState(obj, state) {
|
export function bindToState(obj, state) {
|
||||||
@@ -468,6 +468,18 @@ export const validateFile = ( val ) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const validateBoolean = ( val ) => {
|
||||||
|
if ( !(val === "true" || val === "false" || val === true || val === false) ) {
|
||||||
|
return "Value must be a boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateString = ( val ) => {
|
||||||
|
if ( val && typeof val !== "string" ) {
|
||||||
|
return "Value must be a string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// validation of parameters before execute
|
// validation of parameters before execute
|
||||||
export const validateParam = (param, isXml) => {
|
export const validateParam = (param, isXml) => {
|
||||||
let errors = []
|
let errors = []
|
||||||
@@ -475,52 +487,69 @@ export const validateParam = (param, isXml) => {
|
|||||||
let required = param.get("required")
|
let required = param.get("required")
|
||||||
let type = param.get("type")
|
let type = param.get("type")
|
||||||
|
|
||||||
let stringCheck = type === "string" && !value
|
/*
|
||||||
let arrayCheck = type === "array" && Array.isArray(value) && !value.length
|
If the parameter is required OR the parameter has a value (meaning optional, but filled in)
|
||||||
let listCheck = type === "array" && Im.List.isList(value) && !value.count()
|
then we should do our validation routine.
|
||||||
let fileCheck = type === "file" && !(value instanceof win.File)
|
Only bother validating the parameter if the type was specified.
|
||||||
|
*/
|
||||||
|
if ( type && (required || value) ) {
|
||||||
|
// These checks should evaluate to true if the parameter's value is valid
|
||||||
|
let stringCheck = type === "string" && value && !validateString(value)
|
||||||
|
let arrayCheck = type === "array" && Array.isArray(value) && value.length
|
||||||
|
let listCheck = type === "array" && Im.List.isList(value) && value.count()
|
||||||
|
let fileCheck = type === "file" && value instanceof win.File
|
||||||
|
let booleanCheck = type === "boolean" && !validateBoolean(value)
|
||||||
|
let numberCheck = type === "number" && !validateNumber(value) // validateNumber returns undefined if the value is a number
|
||||||
|
let integerCheck = type === "integer" && !validateInteger(value) // validateInteger returns undefined if the value is an integer
|
||||||
|
|
||||||
if ( required && (stringCheck || arrayCheck || listCheck || fileCheck) ) {
|
if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) {
|
||||||
errors.push("Required field is not provided")
|
errors.push("Required field is not provided")
|
||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( value === null || value === undefined ) {
|
if ( type === "string" ) {
|
||||||
return errors
|
let err = validateString(value)
|
||||||
}
|
if (!err) return errors
|
||||||
|
errors.push(err)
|
||||||
|
} else if ( type === "boolean" ) {
|
||||||
|
let err = validateBoolean(value)
|
||||||
|
if (!err) return errors
|
||||||
|
errors.push(err)
|
||||||
|
} else if ( type === "number" ) {
|
||||||
|
let err = validateNumber(value)
|
||||||
|
if (!err) return errors
|
||||||
|
errors.push(err)
|
||||||
|
} else if ( type === "integer" ) {
|
||||||
|
let err = validateInteger(value)
|
||||||
|
if (!err) return errors
|
||||||
|
errors.push(err)
|
||||||
|
} else if ( type === "array" ) {
|
||||||
|
let itemType
|
||||||
|
|
||||||
if ( type === "number" ) {
|
if ( !value.count() ) { return errors }
|
||||||
let err = validateNumber(value)
|
|
||||||
if (!err) return errors
|
|
||||||
errors.push(err)
|
|
||||||
} else if ( type === "integer" ) {
|
|
||||||
let err = validateInteger(value)
|
|
||||||
if (!err) return errors
|
|
||||||
errors.push(err)
|
|
||||||
} else if ( type === "array" ) {
|
|
||||||
let itemType
|
|
||||||
|
|
||||||
if ( !value.count() ) { return errors }
|
itemType = param.getIn(["items", "type"])
|
||||||
|
|
||||||
itemType = param.getIn(["items", "type"])
|
value.forEach((item, index) => {
|
||||||
|
let err
|
||||||
|
|
||||||
value.forEach((item, index) => {
|
if (itemType === "number") {
|
||||||
let err
|
err = validateNumber(item)
|
||||||
|
} else if (itemType === "integer") {
|
||||||
|
err = validateInteger(item)
|
||||||
|
} else if (itemType === "string") {
|
||||||
|
err = validateString(item)
|
||||||
|
}
|
||||||
|
|
||||||
if (itemType === "number") {
|
if ( err ) {
|
||||||
err = validateNumber(item)
|
errors.push({ index: index, error: err})
|
||||||
} else if (itemType === "integer") {
|
}
|
||||||
err = validateInteger(item)
|
})
|
||||||
}
|
} else if ( type === "file" ) {
|
||||||
|
let err = validateFile(value)
|
||||||
if ( err ) {
|
if (!err) return errors
|
||||||
errors.push({ index: index, error: err})
|
errors.push(err)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
} else if ( type === "file" ) {
|
|
||||||
let err = validateFile(value)
|
|
||||||
if (!err) return errors
|
|
||||||
errors.push(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors
|
return errors
|
||||||
@@ -596,18 +625,6 @@ export const buildFormData = (data) => {
|
|||||||
return formArr.join("&")
|
return formArr.join("&")
|
||||||
}
|
}
|
||||||
|
|
||||||
export const filterConfigs = (configs, allowed) => {
|
|
||||||
let i, filteredConfigs = {}
|
|
||||||
|
|
||||||
for (i in configs) {
|
|
||||||
if (allowed.indexOf(i) !== -1) {
|
|
||||||
filteredConfigs[i] = configs[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filteredConfigs
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is this really required as a helper? Perhaps. TODO: expose the system of presets.apis in docs, so we know what is supported
|
// Is this really required as a helper? Perhaps. TODO: expose the system of presets.apis in docs, so we know what is supported
|
||||||
export const shallowEqualKeys = (a,b, keys) => {
|
export const shallowEqualKeys = (a,b, keys) => {
|
||||||
return !!find(keys, (key) => {
|
return !!find(keys, (key) => {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ SwaggerUI({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Or if you're updating the core plugins.. you'll add it to [src/js/bootstrap-plugin](https://github.com/SmartBear/swagger-ux/blob/master/src/js/bootstrap-plugin.js)
|
Or if you're updating the core plugins.. you'll add it to the base preset: [src/core/presets/base.js](https://github.com/swagger-api/swagger-ui/blob/master/src/core/presets/base.js)
|
||||||
|
|
||||||
Each Plugin is a function that returns an object. That object will get merged with the `system` and later bound to the state.
|
Each Plugin is a function that returns an object. That object will get merged with the `system` and later bound to the state.
|
||||||
Here is an example of each `type`
|
Here is an example of each `type`
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ export default class Topbar extends React.Component {
|
|||||||
<div className="wrapper">
|
<div className="wrapper">
|
||||||
<div className="topbar-wrapper">
|
<div className="topbar-wrapper">
|
||||||
<Link href="#" title="Swagger UX">
|
<Link href="#" title="Swagger UX">
|
||||||
<img height="30" width="30" src={ Logo } alt="Swagger UX"/>
|
<img height="30" width="30" src={ Logo } alt="Swagger UI"/>
|
||||||
<span>swagger</span>
|
<span>swagger</span>
|
||||||
</Link>
|
</Link>
|
||||||
<form className="download-url-wrapper" onSubmit={formOnSubmit}>
|
<form className="download-url-wrapper" onSubmit={formOnSubmit}>
|
||||||
|
|||||||
@@ -14,6 +14,12 @@
|
|||||||
|
|
||||||
@include text_headline();
|
@include text_headline();
|
||||||
|
|
||||||
|
&.btn-sm
|
||||||
|
{
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 4px 23px;
|
||||||
|
}
|
||||||
|
|
||||||
&[disabled]
|
&[disabled]
|
||||||
{
|
{
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
@@ -165,6 +171,10 @@
|
|||||||
button
|
button
|
||||||
{
|
{
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|
||||||
|
&.invalid
|
||||||
|
{
|
||||||
|
@include invalidFormElement();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ select
|
|||||||
|
|
||||||
background: #f7f7f7;
|
background: #f7f7f7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.invalid {
|
||||||
|
@include invalidFormElement();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.opblock-body select
|
.opblock-body select
|
||||||
@@ -55,10 +59,7 @@ input[type=file]
|
|||||||
|
|
||||||
&.invalid
|
&.invalid
|
||||||
{
|
{
|
||||||
animation: shake .4s 1;
|
@include invalidFormElement();
|
||||||
|
|
||||||
border-color: $_color-delete;
|
|
||||||
background: lighten($_color-delete, 35%);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,3 @@
|
|||||||
html
|
|
||||||
{
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
*,
|
|
||||||
*:before,
|
|
||||||
*:after
|
|
||||||
{
|
|
||||||
box-sizing: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
body
|
|
||||||
{
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
background: #fafafa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper
|
.wrapper
|
||||||
{
|
{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -74,6 +56,11 @@ body
|
|||||||
{
|
{
|
||||||
border-color: $color;
|
border-color: $color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tab-header .tab-item.active h4 span:after
|
||||||
|
{
|
||||||
|
background: $color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -144,6 +131,51 @@ body
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
box-shadow: 0 0 3px rgba(#000,.19);
|
box-shadow: 0 0 3px rgba(#000,.19);
|
||||||
|
|
||||||
|
.tab-header
|
||||||
|
{
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.tab-item
|
||||||
|
{
|
||||||
|
padding: 0 40px;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:first-of-type
|
||||||
|
{
|
||||||
|
padding: 0 40px 0 0;
|
||||||
|
}
|
||||||
|
&.active
|
||||||
|
{
|
||||||
|
h4
|
||||||
|
{
|
||||||
|
span
|
||||||
|
{
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
|
||||||
|
&:after
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
bottom: -15px;
|
||||||
|
left: 50%;
|
||||||
|
|
||||||
|
width: 120%;
|
||||||
|
height: 4px;
|
||||||
|
|
||||||
|
content: '';
|
||||||
|
transform: translateX(-50%);
|
||||||
|
|
||||||
|
background: #888;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
&.is-open
|
&.is-open
|
||||||
{
|
{
|
||||||
@@ -160,6 +192,8 @@ body
|
|||||||
|
|
||||||
padding: 8px 20px;
|
padding: 8px 20px;
|
||||||
|
|
||||||
|
min-height: 50px;
|
||||||
|
|
||||||
background: rgba(#fff,.8);
|
background: rgba(#fff,.8);
|
||||||
box-shadow: 0 1px 2px rgba(#000,.1);
|
box-shadow: 0 1px 2px rgba(#000,.1);
|
||||||
|
|
||||||
@@ -172,6 +206,7 @@ body
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
margin-left: auto;
|
||||||
|
|
||||||
@include text_headline();
|
@include text_headline();
|
||||||
|
|
||||||
@@ -487,6 +522,22 @@ body
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.response-col_links
|
||||||
|
{
|
||||||
|
padding-left: 2em;
|
||||||
|
max-width: 40em;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
@include text_body();
|
||||||
|
|
||||||
|
.response-undocumented
|
||||||
|
{
|
||||||
|
font-size: 11px;
|
||||||
|
|
||||||
|
@include text_code(#999);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.response-col_description__inner
|
.response-col_description__inner
|
||||||
{
|
{
|
||||||
span
|
span
|
||||||
@@ -508,6 +559,15 @@ body
|
|||||||
{
|
{
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a
|
||||||
|
{
|
||||||
|
@include text_code(#89bf04);
|
||||||
|
text-decoration: underline;
|
||||||
|
&:hover {
|
||||||
|
color: #81b10c;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,6 +694,17 @@ body
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.renderedMarkdown {
|
||||||
|
p {
|
||||||
|
@include text_body();
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.response-content-type {
|
||||||
|
padding-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes blinker
|
@keyframes blinker
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -166,3 +166,9 @@ $browser-context: 16;
|
|||||||
@warn 'Breakpoint mixin supports: tablet, mobile, desktop';
|
@warn 'Breakpoint mixin supports: tablet, mobile, desktop';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin invalidFormElement() {
|
||||||
|
animation: shake .4s 1;
|
||||||
|
border-color: $_color-delete;
|
||||||
|
background: lighten($_color-delete, 35%);
|
||||||
|
}
|
||||||
@@ -3,6 +3,13 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
|
|
||||||
|
.deprecated
|
||||||
|
{
|
||||||
|
span, td {
|
||||||
|
color: #aaa !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@include text_code();
|
@include text_code();
|
||||||
&-toggle
|
&-toggle
|
||||||
{
|
{
|
||||||
@@ -192,6 +199,11 @@ section.models
|
|||||||
position: relative;
|
position: relative;
|
||||||
top: 4px;
|
top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.deprecated
|
||||||
|
{
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -202,13 +214,19 @@ section.models
|
|||||||
@include text_headline(#555);
|
@include text_headline(#555);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.model-deprecated-warning
|
||||||
|
{
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-right: 1em;
|
||||||
|
@include text_headline($_color-delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
span
|
span
|
||||||
{
|
{
|
||||||
> span.model
|
> span.model
|
||||||
{
|
{
|
||||||
padding: 0 0 0 10px;
|
|
||||||
|
|
||||||
.brace-close
|
.brace-close
|
||||||
{
|
{
|
||||||
padding: 0 0 0 10px;
|
padding: 0 0 0 10px;
|
||||||
@@ -216,6 +234,12 @@ span
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.prop-name
|
||||||
|
{
|
||||||
|
display: inline-block;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
.prop-type
|
.prop-type
|
||||||
{
|
{
|
||||||
color: #55a;
|
color: #55a;
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ table
|
|||||||
|
|
||||||
&:first-of-type
|
&:first-of-type
|
||||||
{
|
{
|
||||||
width: 100px;
|
width: 124px;
|
||||||
padding: 0;
|
padding: 0 0 0 2em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,8 @@ table
|
|||||||
|
|
||||||
&:first-of-type
|
&:first-of-type
|
||||||
{
|
{
|
||||||
width: 20%;
|
max-width: 20%;
|
||||||
|
min-width: 6em;
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,6 +98,10 @@ table
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 340px;
|
max-width: 340px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.parameter__name
|
.parameter__name
|
||||||
@@ -134,6 +139,14 @@ table
|
|||||||
@include text_code(#888);
|
@include text_code(#888);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.parameter__deprecated
|
||||||
|
{
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: italic;
|
||||||
|
|
||||||
|
@include text_code(#f00);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.table-container
|
.table-container
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -43,6 +43,7 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
border: 2px solid #547f00;
|
border: 2px solid #547f00;
|
||||||
|
border-radius: 4px 0 0 4px;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,5 +14,6 @@
|
|||||||
@import 'information';
|
@import 'information';
|
||||||
@import 'authorize';
|
@import 'authorize';
|
||||||
@import 'errors';
|
@import 'errors';
|
||||||
|
@include text_body();
|
||||||
@import 'split-pane-mode';
|
@import 'split-pane-mode';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
env:
|
env:
|
||||||
mocha: true
|
mocha: true
|
||||||
|
rules:
|
||||||
|
"react/prop-types": 1 # bah humbug
|
||||||
|
"no-unused-vars": 1 # unused vars in tests can be useful for indicating a full signature
|
||||||
|
|||||||
72
test/components/schemes.js
Normal file
72
test/components/schemes.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
/* eslint-env mocha */
|
||||||
|
import React from "react"
|
||||||
|
import expect, { createSpy } from "expect"
|
||||||
|
import { shallow } from "enzyme"
|
||||||
|
import { fromJS } from "immutable"
|
||||||
|
import Schemes from "components/schemes"
|
||||||
|
|
||||||
|
describe("<Schemes/>", function(){
|
||||||
|
it("calls props.specActions.setScheme() when no currentScheme is selected", function(){
|
||||||
|
|
||||||
|
let setSchemeSpy = createSpy()
|
||||||
|
|
||||||
|
// Given
|
||||||
|
let props = {
|
||||||
|
specActions: {
|
||||||
|
setScheme: setSchemeSpy
|
||||||
|
},
|
||||||
|
schemes: fromJS([
|
||||||
|
"http",
|
||||||
|
"https"
|
||||||
|
]),
|
||||||
|
currentScheme: undefined,
|
||||||
|
path: "/test",
|
||||||
|
method: "get"
|
||||||
|
}
|
||||||
|
|
||||||
|
// When
|
||||||
|
let wrapper = shallow(<Schemes {...props}/>)
|
||||||
|
|
||||||
|
// Then currentScheme should default to first scheme in options list
|
||||||
|
expect(props.specActions.setScheme).toHaveBeenCalledWith("http", "/test" , "get")
|
||||||
|
|
||||||
|
// When the currentScheme is no longer in the list of options
|
||||||
|
props.schemes = fromJS([
|
||||||
|
"https"
|
||||||
|
])
|
||||||
|
wrapper.setProps(props)
|
||||||
|
|
||||||
|
// Then currentScheme should default to first scheme in options list, again
|
||||||
|
expect(props.specActions.setScheme).toHaveBeenCalledWith("https", "/test", "get")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("doesn't call props.specActions.setScheme() when schemes hasn't changed", function(){
|
||||||
|
|
||||||
|
let setSchemeSpy = createSpy()
|
||||||
|
|
||||||
|
// Given
|
||||||
|
let props = {
|
||||||
|
specActions: {
|
||||||
|
setScheme: setSchemeSpy
|
||||||
|
},
|
||||||
|
schemes: fromJS([
|
||||||
|
"http",
|
||||||
|
"https"
|
||||||
|
]),
|
||||||
|
currentScheme: "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
// When
|
||||||
|
let wrapper = shallow(<Schemes {...props}/>)
|
||||||
|
|
||||||
|
// Should be called initially, to set the global state
|
||||||
|
expect(setSchemeSpy.calls.length).toEqual(1)
|
||||||
|
|
||||||
|
// After an update
|
||||||
|
wrapper.instance().componentWillReceiveProps(props)
|
||||||
|
|
||||||
|
// Should not be called again, since `currentScheme` is in schemes
|
||||||
|
expect(setSchemeSpy.calls.length).toEqual(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -132,10 +132,10 @@ describe("curlify", function() {
|
|||||||
url: "http://example.com",
|
url: "http://example.com",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "content-type": "multipart/form-data" },
|
headers: { "content-type": "multipart/form-data" },
|
||||||
body: [
|
body: {
|
||||||
["id", "123"],
|
id: "123",
|
||||||
["name", "Sahar"]
|
name: "Sahar"
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let curlified = curl(Im.fromJS(req))
|
let curlified = curl(Im.fromJS(req))
|
||||||
@@ -152,10 +152,10 @@ describe("curlify", function() {
|
|||||||
url: "http://example.com",
|
url: "http://example.com",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "content-type": "multipart/form-data" },
|
headers: { "content-type": "multipart/form-data" },
|
||||||
body: [
|
body: {
|
||||||
["id", "123"],
|
id: "123",
|
||||||
["file", file]
|
file
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let curlified = curl(Im.fromJS(req))
|
let curlified = curl(Im.fromJS(req))
|
||||||
|
|||||||
@@ -1,6 +1,105 @@
|
|||||||
import { createXMLExample } from "corePlugins/samples/fn"
|
import { createXMLExample, sampleFromSchema } from "corePlugins/samples/fn"
|
||||||
import expect from "expect"
|
import expect from "expect"
|
||||||
|
|
||||||
|
describe("sampleFromSchema", function() {
|
||||||
|
it("returns object with no readonly fields for parameter", function () {
|
||||||
|
var definition = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "integer"
|
||||||
|
},
|
||||||
|
readOnlyDog: {
|
||||||
|
readOnly: true,
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
name: "animals"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var expected = {
|
||||||
|
id: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(sampleFromSchema(definition, { includeReadOnly: false })).toEqual(expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns object with readonly fields for parameter, with includeReadOnly", function () {
|
||||||
|
var definition = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "integer"
|
||||||
|
},
|
||||||
|
readOnlyDog: {
|
||||||
|
readOnly: true,
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
name: "animals"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var expected = {
|
||||||
|
id: 0,
|
||||||
|
readOnlyDog: "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(sampleFromSchema(definition, { includeReadOnly: true })).toEqual(expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns object without writeonly fields for parameter", function () {
|
||||||
|
var definition = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "integer"
|
||||||
|
},
|
||||||
|
writeOnlyDog: {
|
||||||
|
writeOnly: true,
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
name: "animals"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var expected = {
|
||||||
|
id: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns object with writeonly fields for parameter, with includeWriteOnly", function () {
|
||||||
|
var definition = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "integer"
|
||||||
|
},
|
||||||
|
writeOnlyDog: {
|
||||||
|
writeOnly: true,
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
name: "animals"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var expected = {
|
||||||
|
id: 0,
|
||||||
|
writeOnlyDog: "string"
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(sampleFromSchema(definition, { includeWriteOnly: true })).toEqual(expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("createXMLExample", function () {
|
describe("createXMLExample", function () {
|
||||||
var sut = createXMLExample
|
var sut = createXMLExample
|
||||||
@@ -554,6 +653,69 @@ describe("createXMLExample", function () {
|
|||||||
expect(sut(definition, { includeReadOnly: false })).toEqual(expected)
|
expect(sut(definition, { includeReadOnly: false })).toEqual(expected)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("returns object with readonly fields for parameter, with includeReadOnly", function () {
|
||||||
|
var expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals>\n\t<id>0</id>\n\t<dog>string</dog>\n</animals>"
|
||||||
|
var definition = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "integer"
|
||||||
|
},
|
||||||
|
dog: {
|
||||||
|
readOnly: true,
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
name: "animals"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(sut(definition, { includeReadOnly: true })).toEqual(expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns object without writeonly fields for parameter", function () {
|
||||||
|
var expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals>\n\t<id>0</id>\n</animals>"
|
||||||
|
var definition = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "integer"
|
||||||
|
},
|
||||||
|
dog: {
|
||||||
|
writeOnly: true,
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
name: "animals"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(sut(definition)).toEqual(expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns object with writeonly fields for parameter, with includeWriteOnly", function () {
|
||||||
|
var expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals>\n\t<id>0</id>\n\t<dog>string</dog>\n</animals>"
|
||||||
|
var definition = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: "integer"
|
||||||
|
},
|
||||||
|
dog: {
|
||||||
|
writeOnly: true,
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
name: "animals"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(sut(definition, { includeWriteOnly: true })).toEqual(expected)
|
||||||
|
})
|
||||||
|
|
||||||
it("returns object with passed property as attribute", function () {
|
it("returns object with passed property as attribute", function () {
|
||||||
var expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals id=\"0\">\n\t<dog>string</dog>\n</animals>"
|
var expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals id=\"0\">\n\t<dog>string</dog>\n</animals>"
|
||||||
var definition = {
|
var definition = {
|
||||||
|
|||||||
@@ -326,6 +326,122 @@ describe("bound system", function(){
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("wrapSelectors", () => {
|
||||||
|
it("should wrap a selector and provide a reference to the original", function(){
|
||||||
|
|
||||||
|
// Given
|
||||||
|
const system = new System({
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
statePlugins: {
|
||||||
|
doge: {
|
||||||
|
selectors: {
|
||||||
|
wow: () => (system) => {
|
||||||
|
return "original"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statePlugins: {
|
||||||
|
doge: {
|
||||||
|
wrapSelectors: {
|
||||||
|
wow: (ori) => (system) => {
|
||||||
|
// Then
|
||||||
|
return ori() + " wrapper"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// When
|
||||||
|
var res = system.getSystem().dogeSelectors.wow(1)
|
||||||
|
expect(res).toEqual("original wrapper")
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should provide a live reference to the system to a wrapper", function(done){
|
||||||
|
|
||||||
|
// Given
|
||||||
|
const mySystem = new System({
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
statePlugins: {
|
||||||
|
doge: {
|
||||||
|
selectors: {
|
||||||
|
wow: () => (system) => {
|
||||||
|
return "original"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statePlugins: {
|
||||||
|
doge: {
|
||||||
|
wrapSelectors: {
|
||||||
|
wow: (ori, system) => () => {
|
||||||
|
// Then
|
||||||
|
expect(mySystem.getSystem()).toEqual(system.getSystem())
|
||||||
|
done()
|
||||||
|
return ori() + " wrapper"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
mySystem.getSystem().dogeSelectors.wow(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should provide the state as the first argument to the inner function", function(done){
|
||||||
|
|
||||||
|
// Given
|
||||||
|
const mySystem = new System({
|
||||||
|
state: {
|
||||||
|
doge: {
|
||||||
|
abc: "123"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
statePlugins: {
|
||||||
|
doge: {
|
||||||
|
selectors: {
|
||||||
|
wow: () => (system) => {
|
||||||
|
return "original"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
statePlugins: {
|
||||||
|
doge: {
|
||||||
|
wrapSelectors: {
|
||||||
|
wow: (ori, system) => (dogeState) => {
|
||||||
|
// Then
|
||||||
|
expect(dogeState.toJS().abc).toEqual("123")
|
||||||
|
done()
|
||||||
|
return ori() + " wrapper"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
mySystem.getSystem().dogeSelectors.wow(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
139
test/core/system/wrapComponent.js
Normal file
139
test/core/system/wrapComponent.js
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
import React from "react"
|
||||||
|
import expect from "expect"
|
||||||
|
import { render } from "enzyme"
|
||||||
|
import System from "core/system"
|
||||||
|
|
||||||
|
describe("wrapComponents", () => {
|
||||||
|
describe("should wrap a component and provide a reference to the original", () => {
|
||||||
|
it("with stateless components", function(){
|
||||||
|
// Given
|
||||||
|
const system = new System({
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
components: {
|
||||||
|
wow: ({ name }) => <div>{name} component</div>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
wrapComponents: {
|
||||||
|
wow: (OriginalComponent) => (props) => {
|
||||||
|
return <container>
|
||||||
|
<OriginalComponent {...props}></OriginalComponent>
|
||||||
|
<OriginalComponent name="Wrapped"></OriginalComponent>
|
||||||
|
</container>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// When
|
||||||
|
var Component = system.getSystem().getComponents("wow")
|
||||||
|
const wrapper = render(<Component name="Normal" />)
|
||||||
|
|
||||||
|
const container = wrapper.children().first()
|
||||||
|
expect(container[0].name).toEqual("container")
|
||||||
|
|
||||||
|
const children = container.children()
|
||||||
|
expect(children.length).toEqual(2)
|
||||||
|
expect(children.eq(0).text()).toEqual("Normal component")
|
||||||
|
expect(children.eq(1).text()).toEqual("Wrapped component")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("with React classes", function(){
|
||||||
|
class MyComponent extends React.Component {
|
||||||
|
render() {
|
||||||
|
return <div>{this.props.name} component</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given
|
||||||
|
const system = new System({
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
components: {
|
||||||
|
wow: MyComponent
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
wrapComponents: {
|
||||||
|
wow: (OriginalComponent) => {
|
||||||
|
return class WrapperComponent extends React.Component {
|
||||||
|
render() {
|
||||||
|
return <container>
|
||||||
|
<OriginalComponent {...this.props}></OriginalComponent>
|
||||||
|
<OriginalComponent name="Wrapped"></OriginalComponent>
|
||||||
|
</container>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// When
|
||||||
|
var Component = system.getSystem().getComponents("wow")
|
||||||
|
const wrapper = render(<Component name="Normal" />)
|
||||||
|
|
||||||
|
const container = wrapper.children().first()
|
||||||
|
expect(container[0].name).toEqual("container")
|
||||||
|
|
||||||
|
const children = container.children()
|
||||||
|
expect(children.length).toEqual(2)
|
||||||
|
expect(children.eq(0).text()).toEqual("Normal component")
|
||||||
|
expect(children.eq(1).text()).toEqual("Wrapped component")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should provide a reference to the system to the wrapper", function(){
|
||||||
|
|
||||||
|
// Given
|
||||||
|
|
||||||
|
const mySystem = new System({
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
// Make a selector
|
||||||
|
statePlugins: {
|
||||||
|
doge: {
|
||||||
|
selectors: {
|
||||||
|
wow: () => () => {
|
||||||
|
return "WOW much data"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Create a component
|
||||||
|
components: {
|
||||||
|
wow: () => <div>Original component</div>
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Wrap the component and use the system
|
||||||
|
wrapComponents: {
|
||||||
|
wow: (OriginalComponent, system) => (props) => {
|
||||||
|
return <container>
|
||||||
|
<OriginalComponent {...props}></OriginalComponent>
|
||||||
|
<div>{system.dogeSelectors.wow()}</div>
|
||||||
|
</container>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// Then
|
||||||
|
var Component = mySystem.getSystem().getComponents("wow")
|
||||||
|
const wrapper = render(<Component name="Normal" />)
|
||||||
|
|
||||||
|
const container = wrapper.children().first()
|
||||||
|
expect(container[0].name).toEqual("container")
|
||||||
|
|
||||||
|
const children = container.children()
|
||||||
|
expect(children.length).toEqual(2)
|
||||||
|
expect(children.eq(0).text()).toEqual("Original component")
|
||||||
|
expect(children.eq(1).text()).toEqual("WOW much data")
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
/* eslint-env mocha */
|
/* eslint-env mocha */
|
||||||
import expect from "expect"
|
import expect from "expect"
|
||||||
import { fromJS } from "immutable"
|
import { fromJS } from "immutable"
|
||||||
import { mapToList, validateNumber, validateInteger, validateParam, validateFile } from "core/utils"
|
import { mapToList, validateNumber, validateInteger, validateParam, validateFile, fromJSOrdered } from "core/utils"
|
||||||
import win from "core/window"
|
import win from "core/window"
|
||||||
|
|
||||||
describe("utils", function(){
|
describe("utils", function() {
|
||||||
|
|
||||||
describe("mapToList", function(){
|
describe("mapToList", function(){
|
||||||
|
|
||||||
@@ -175,7 +175,19 @@ describe("utils", function(){
|
|||||||
let param = null
|
let param = null
|
||||||
let result = null
|
let result = null
|
||||||
|
|
||||||
|
it("skips validation when `type` is not specified", function() {
|
||||||
|
// invalid type
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: undefined,
|
||||||
|
value: ""
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
})
|
||||||
|
|
||||||
it("validates required strings", function() {
|
it("validates required strings", function() {
|
||||||
|
// invalid string
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
required: true,
|
required: true,
|
||||||
type: "string",
|
type: "string",
|
||||||
@@ -183,9 +195,39 @@ describe("utils", function(){
|
|||||||
})
|
})
|
||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
expect( result ).toEqual( ["Required field is not provided"] )
|
||||||
|
|
||||||
|
// valid string
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "string",
|
||||||
|
value: "test string"
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("validates optional strings", function() {
|
||||||
|
// valid (empty) string
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "string",
|
||||||
|
value: ""
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
|
||||||
|
// valid string
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "string",
|
||||||
|
value: "test"
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required files", function() {
|
it("validates required files", function() {
|
||||||
|
// invalid file
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
required: true,
|
required: true,
|
||||||
type: "file",
|
type: "file",
|
||||||
@@ -193,9 +235,48 @@ describe("utils", function(){
|
|||||||
})
|
})
|
||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
expect( result ).toEqual( ["Required field is not provided"] )
|
||||||
|
|
||||||
|
// valid file
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "file",
|
||||||
|
value: new win.File()
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("validates optional files", function() {
|
||||||
|
// invalid file
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "file",
|
||||||
|
value: "not a file"
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Value must be a file"] )
|
||||||
|
|
||||||
|
// valid (empty) file
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "file",
|
||||||
|
value: undefined
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
|
||||||
|
// valid file
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "file",
|
||||||
|
value: new win.File()
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates required arrays", function() {
|
it("validates required arrays", function() {
|
||||||
|
// invalid (empty) array
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
required: true,
|
required: true,
|
||||||
type: "array",
|
type: "array",
|
||||||
@@ -204,75 +285,51 @@ describe("utils", function(){
|
|||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
expect( result ).toEqual( ["Required field is not provided"] )
|
||||||
|
|
||||||
|
// invalid (not an array)
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
required: true,
|
required: true,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: []
|
value: undefined
|
||||||
})
|
})
|
||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( ["Required field is not provided"] )
|
expect( result ).toEqual( ["Required field is not provided"] )
|
||||||
})
|
|
||||||
|
|
||||||
it("validates numbers", function() {
|
// invalid array, items do not match correct type
|
||||||
// string instead of a number
|
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
required: false,
|
required: true,
|
||||||
type: "number",
|
type: "array",
|
||||||
value: "test"
|
value: [1],
|
||||||
|
items: {
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
})
|
})
|
||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( ["Value must be a number"] )
|
expect( result ).toEqual( [{index: 0, error: "Value must be a string"}] )
|
||||||
|
|
||||||
// undefined value
|
// valid array, with no 'type' for items
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
required: false,
|
required: true,
|
||||||
type: "number",
|
type: "array",
|
||||||
value: undefined
|
value: ["1"]
|
||||||
})
|
})
|
||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( [] )
|
expect( result ).toEqual( [] )
|
||||||
|
|
||||||
// null value
|
// valid array, items match type
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
required: false,
|
required: true,
|
||||||
type: "number",
|
type: "array",
|
||||||
value: null
|
value: ["1"],
|
||||||
|
items: {
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
})
|
})
|
||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( [] )
|
expect( result ).toEqual( [] )
|
||||||
})
|
})
|
||||||
|
|
||||||
it("validates integers", function() {
|
it("validates optional arrays", function() {
|
||||||
// string instead of integer
|
// valid, empty array
|
||||||
param = fromJS({
|
|
||||||
required: false,
|
|
||||||
type: "integer",
|
|
||||||
value: "test"
|
|
||||||
})
|
|
||||||
result = validateParam( param, false )
|
|
||||||
expect( result ).toEqual( ["Value must be an integer"] )
|
|
||||||
|
|
||||||
// undefined value
|
|
||||||
param = fromJS({
|
|
||||||
required: false,
|
|
||||||
type: "integer",
|
|
||||||
value: undefined
|
|
||||||
})
|
|
||||||
result = validateParam( param, false )
|
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
|
|
||||||
// null value
|
|
||||||
param = fromJS({
|
|
||||||
required: false,
|
|
||||||
type: "integer",
|
|
||||||
value: null
|
|
||||||
})
|
|
||||||
result = validateParam( param, false )
|
|
||||||
expect( result ).toEqual( [] )
|
|
||||||
})
|
|
||||||
|
|
||||||
it("validates arrays", function() {
|
|
||||||
// empty array
|
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
required: false,
|
required: false,
|
||||||
type: "array",
|
type: "array",
|
||||||
@@ -281,7 +338,7 @@ describe("utils", function(){
|
|||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( [] )
|
expect( result ).toEqual( [] )
|
||||||
|
|
||||||
// numbers
|
// invalid, items do not match correct type
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
required: false,
|
required: false,
|
||||||
type: "array",
|
type: "array",
|
||||||
@@ -293,17 +350,236 @@ describe("utils", function(){
|
|||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( [{index: 0, error: "Value must be a number"}] )
|
expect( result ).toEqual( [{index: 0, error: "Value must be a number"}] )
|
||||||
|
|
||||||
// integers
|
// valid
|
||||||
param = fromJS({
|
param = fromJS({
|
||||||
required: false,
|
required: false,
|
||||||
type: "array",
|
type: "array",
|
||||||
value: ["not", "numbers"],
|
value: ["test"],
|
||||||
items: {
|
items: {
|
||||||
type: "integer"
|
type: "string"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
result = validateParam( param, false )
|
result = validateParam( param, false )
|
||||||
expect( result ).toEqual( [{index: 0, error: "Value must be an integer"}, {index: 1, error: "Value must be an integer"}] )
|
expect( result ).toEqual( [] )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("validates required booleans", function() {
|
||||||
|
// invalid boolean value
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "boolean",
|
||||||
|
value: undefined
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Required field is not provided"] )
|
||||||
|
|
||||||
|
// invalid boolean value (not a boolean)
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "boolean",
|
||||||
|
value: "test string"
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Required field is not provided"] )
|
||||||
|
|
||||||
|
// valid boolean value
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "boolean",
|
||||||
|
value: "true"
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
|
||||||
|
// valid boolean value
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("validates optional booleans", function() {
|
||||||
|
// valid (empty) boolean value
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "boolean",
|
||||||
|
value: undefined
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
|
||||||
|
// invalid boolean value (not a boolean)
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "boolean",
|
||||||
|
value: "test string"
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Value must be a boolean"] )
|
||||||
|
|
||||||
|
// valid boolean value
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "boolean",
|
||||||
|
value: "true"
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
|
||||||
|
// valid boolean value
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("validates required numbers", function() {
|
||||||
|
// invalid number, string instead of a number
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "number",
|
||||||
|
value: "test"
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Required field is not provided"] )
|
||||||
|
|
||||||
|
// invalid number, undefined value
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "number",
|
||||||
|
value: undefined
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Required field is not provided"] )
|
||||||
|
|
||||||
|
// valid number
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "number",
|
||||||
|
value: 10
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("validates optional numbers", function() {
|
||||||
|
// invalid number, string instead of a number
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "number",
|
||||||
|
value: "test"
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Value must be a number"] )
|
||||||
|
|
||||||
|
// valid (empty) number
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "number",
|
||||||
|
value: undefined
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
|
||||||
|
// valid number
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "number",
|
||||||
|
value: 10
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("validates required integers", function() {
|
||||||
|
// invalid integer, string instead of an integer
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "integer",
|
||||||
|
value: "test"
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Required field is not provided"] )
|
||||||
|
|
||||||
|
// invalid integer, undefined value
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "integer",
|
||||||
|
value: undefined
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Required field is not provided"] )
|
||||||
|
|
||||||
|
// valid integer
|
||||||
|
param = fromJS({
|
||||||
|
required: true,
|
||||||
|
type: "integer",
|
||||||
|
value: 10
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("validates optional integers", function() {
|
||||||
|
// invalid integer, string instead of an integer
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "integer",
|
||||||
|
value: "test"
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( ["Value must be an integer"] )
|
||||||
|
|
||||||
|
// valid (empty) integer
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "integer",
|
||||||
|
value: undefined
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
|
|
||||||
|
// integers
|
||||||
|
param = fromJS({
|
||||||
|
required: false,
|
||||||
|
type: "integer",
|
||||||
|
value: 10
|
||||||
|
})
|
||||||
|
result = validateParam( param, false )
|
||||||
|
expect( result ).toEqual( [] )
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("fromJSOrdered", () => {
|
||||||
|
it("should create an OrderedMap from an object", () => {
|
||||||
|
const param = {
|
||||||
|
value: "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = fromJSOrdered(param).toJS()
|
||||||
|
expect( result ).toEqual( { value: "test" } )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should not use an object's length property for Map size", () => {
|
||||||
|
const param = {
|
||||||
|
length: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = fromJSOrdered(param).toJS()
|
||||||
|
expect( result ).toEqual( { length: 5 } )
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should create an OrderedMap from an array", () => {
|
||||||
|
const param = [1, 1, 2, 3, 5, 8]
|
||||||
|
|
||||||
|
const result = fromJSOrdered(param).toJS()
|
||||||
|
expect( result ).toEqual( [1, 1, 2, 3, 5, 8] )
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
130
test/e2e/db.json
Normal file
130
test/e2e/db.json
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
{
|
||||||
|
"pet": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"category": {
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
},
|
||||||
|
"name": "doggie",
|
||||||
|
"photoUrls": [
|
||||||
|
"string"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "available"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"category": {
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
},
|
||||||
|
"name": "doggie",
|
||||||
|
"photoUrls": [
|
||||||
|
"string"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "available"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"category": {
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
},
|
||||||
|
"name": "doggie",
|
||||||
|
"photoUrls": [
|
||||||
|
"string"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "available"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"category": {
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
},
|
||||||
|
"name": "doggie",
|
||||||
|
"photoUrls": [
|
||||||
|
"string"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "available"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"category": {
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
},
|
||||||
|
"name": "doggie",
|
||||||
|
"photoUrls": [
|
||||||
|
"string"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "available"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"category": {
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
},
|
||||||
|
"name": "doggie",
|
||||||
|
"photoUrls": [
|
||||||
|
"string"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "available"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"category": {
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
},
|
||||||
|
"name": "doggie",
|
||||||
|
"photoUrls": [
|
||||||
|
"string"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "available"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
63
test/e2e/nightwatch.json
Normal file
63
test/e2e/nightwatch.json
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"src_folders" : ["test/e2e/scenarios"],
|
||||||
|
"output_folder" : "reports",
|
||||||
|
"live_output": true,
|
||||||
|
"custom_commands_path" : "",
|
||||||
|
"custom_assertions_path" : "",
|
||||||
|
"page_objects_path" : "test/e2e/pages",
|
||||||
|
"globals_path" : "",
|
||||||
|
"test_workers" : {
|
||||||
|
"enabled" : true,
|
||||||
|
"workers" : "auto"
|
||||||
|
},
|
||||||
|
|
||||||
|
"test_runner" : {
|
||||||
|
"type" : "mocha",
|
||||||
|
"options" : {
|
||||||
|
"ui" : "bdd",
|
||||||
|
"reporter" : "list"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"selenium" : {
|
||||||
|
"start_process" : true,
|
||||||
|
"server_path" : "node_modules/selenium-server-standalone-jar/jar/selenium-server-standalone-3.4.0.jar",
|
||||||
|
"log_path" : "",
|
||||||
|
"host" : "127.0.0.1",
|
||||||
|
"port" : 4444,
|
||||||
|
"cli_args" : {
|
||||||
|
"webdriver.chrome.driver" : "node_modules/chromedriver/bin/chromedriver",
|
||||||
|
"webdriver.firefox.profile" : "",
|
||||||
|
"webdriver.ie.driver" : ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"test_settings" : {
|
||||||
|
"default" : {
|
||||||
|
"launch_url" : "http://localhost",
|
||||||
|
"selenium_port" : 4444,
|
||||||
|
"selenium_host" : "localhost",
|
||||||
|
"silent": true,
|
||||||
|
"screenshots" : {
|
||||||
|
"enabled" : false,
|
||||||
|
"path" : ""
|
||||||
|
},
|
||||||
|
"desiredCapabilities": {
|
||||||
|
"browserName": "chrome",
|
||||||
|
"marionette": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"chrome" : {
|
||||||
|
"desiredCapabilities": {
|
||||||
|
"browserName": "chrome"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"edge" : {
|
||||||
|
"desiredCapabilities": {
|
||||||
|
"browserName": "MicrosoftEdge"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
505
test/e2e/pages/main.js
Normal file
505
test/e2e/pages/main.js
Normal file
@@ -0,0 +1,505 @@
|
|||||||
|
module.exports = {
|
||||||
|
sections: {
|
||||||
|
topbar: {
|
||||||
|
selector: ".topbar",
|
||||||
|
elements: {
|
||||||
|
inputBox: {
|
||||||
|
selector: "input"
|
||||||
|
},
|
||||||
|
btnExplore: {
|
||||||
|
selector: "button"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
informationContainer: {
|
||||||
|
selector: ".information-container.wrapper",
|
||||||
|
elements: {
|
||||||
|
title: {
|
||||||
|
selector: ".title"
|
||||||
|
},
|
||||||
|
version: {
|
||||||
|
selector: ".version"
|
||||||
|
},
|
||||||
|
baseUrl: {
|
||||||
|
selector: ".base-url"
|
||||||
|
},
|
||||||
|
mainUrl: {
|
||||||
|
selector: ".main a"
|
||||||
|
},
|
||||||
|
mainUrlContent: {
|
||||||
|
selector: ".main a span"
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
selector: ".description p"
|
||||||
|
},
|
||||||
|
swaggerUrl: {
|
||||||
|
selector: ".description p a:nth-of-type(1)"
|
||||||
|
},
|
||||||
|
swaggerircUrl: {
|
||||||
|
selector: ".description p a:nth-of-type(2)"
|
||||||
|
},
|
||||||
|
termsLink: {
|
||||||
|
selector: ".info > div:nth-child(3) a"
|
||||||
|
},
|
||||||
|
contactDevLink: {
|
||||||
|
selector: ".info > div:nth-child(4) a"
|
||||||
|
},
|
||||||
|
apacheLink: {
|
||||||
|
selector: ".info > div:nth-child(5) a"
|
||||||
|
},
|
||||||
|
aboutSwaggerLink: {
|
||||||
|
selector: ".info > a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
schemeContainer: {
|
||||||
|
selector: ".scheme-container",
|
||||||
|
elements: {
|
||||||
|
httpOption: {
|
||||||
|
selector: "select option"
|
||||||
|
},
|
||||||
|
btnAuthorize: {
|
||||||
|
selector: "button.authorize"
|
||||||
|
},
|
||||||
|
authorizationModal: {
|
||||||
|
selector: ".dialog-ux"
|
||||||
|
},
|
||||||
|
appName: {
|
||||||
|
selector: ".auth-container h5"
|
||||||
|
},
|
||||||
|
authorizationUrl: {
|
||||||
|
selector: ".auth-container code"
|
||||||
|
},
|
||||||
|
flow: {
|
||||||
|
selector: ".flow code"
|
||||||
|
},
|
||||||
|
inputClientID: {
|
||||||
|
selector: "#client_id"
|
||||||
|
},
|
||||||
|
checkWritePetStoreAuth: {
|
||||||
|
selector: "#write:pets-checkbox-petstore_auth"
|
||||||
|
},
|
||||||
|
checkReadPetStoreAuth: {
|
||||||
|
selector: "#read:pets-checkbox-petstore_auth"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
apiWrapper: {
|
||||||
|
selector: ".swagger-ui .wrapper:nth-child(3)",
|
||||||
|
elements: {
|
||||||
|
petAPIWrapper: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1)"
|
||||||
|
},
|
||||||
|
petAPIWrapperBar: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) .opblock-tag"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Post pet/ api
|
||||||
|
*/
|
||||||
|
petOperationPostContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet"
|
||||||
|
},
|
||||||
|
petOperationPostTitle: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet .opblock-summary-post span.opblock-summary-path span"
|
||||||
|
},
|
||||||
|
petOperationPostCollpase: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet .opblock-summary-post"
|
||||||
|
},
|
||||||
|
petOperationPostCollapseContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet>div:nth-child(2)"
|
||||||
|
},
|
||||||
|
petOperationPostTryBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet button.try-out__btn"
|
||||||
|
},
|
||||||
|
petOperationPostTryText: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet textarea.body-param__text"
|
||||||
|
},
|
||||||
|
petOperationPostExecuteBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet button.execute"
|
||||||
|
},
|
||||||
|
petOperationPostTryTextArea: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet textarea"
|
||||||
|
},
|
||||||
|
petOperationPostResultsBox: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight"
|
||||||
|
},
|
||||||
|
petOperationPostMockCategoryID: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight span:nth-child(17)"
|
||||||
|
},
|
||||||
|
petOperationPostMockCategoryName: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight span:nth-child(23)"
|
||||||
|
},
|
||||||
|
petOperationPostMockName: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight span:nth-child(31)"
|
||||||
|
},
|
||||||
|
petOperationPostTagID: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight span:nth-child(54)"
|
||||||
|
},
|
||||||
|
petOperationPostTagName: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight span:nth-child(60)"
|
||||||
|
},
|
||||||
|
petOperationPostStatus: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-addPet pre.microlight span:nth-child(70)"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Put pet/ api
|
||||||
|
*/
|
||||||
|
petOperationPutContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet"
|
||||||
|
},
|
||||||
|
petOperationPutTitle: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet .opblock-summary-put span.opblock-summary-path span"
|
||||||
|
},
|
||||||
|
petOperationPutCollpase: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet .opblock-summary-put"
|
||||||
|
},
|
||||||
|
petOperationPutCollapseContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet>div:nth-child(2)"
|
||||||
|
},
|
||||||
|
petOperationPutTryBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet button.try-out__btn"
|
||||||
|
},
|
||||||
|
petOperationPutTryText: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet textarea.body-param__text"
|
||||||
|
},
|
||||||
|
petOperationPutExecuteBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet button.execute"
|
||||||
|
},
|
||||||
|
petOperationPutTryTextArea: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet textarea"
|
||||||
|
},
|
||||||
|
petOperationPutResultsBox: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight"
|
||||||
|
},
|
||||||
|
petOperationPutMockCategoryID: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight span:nth-child(17)"
|
||||||
|
},
|
||||||
|
petOperationPutMockCategoryName: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight span:nth-child(23)"
|
||||||
|
},
|
||||||
|
petOperationPutMockName: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight span:nth-child(31)"
|
||||||
|
},
|
||||||
|
petOperationPutTagID: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight span:nth-child(54)"
|
||||||
|
},
|
||||||
|
petOperationPutTagName: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight span:nth-child(60)"
|
||||||
|
},
|
||||||
|
petOperationPutStatus: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-updatePet pre.microlight span:nth-child(70)"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Get pet/
|
||||||
|
*/
|
||||||
|
petOperationGetByTagContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags"
|
||||||
|
},
|
||||||
|
petOperationGetByTagTitle: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags .opblock-summary-get span.opblock-summary-path__deprecated span"
|
||||||
|
},
|
||||||
|
petOperationGetByTagCollpase: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags .opblock-summary-get"
|
||||||
|
},
|
||||||
|
petOperationGetByTagCollapseContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags .ReactCollapse--collapse"
|
||||||
|
},
|
||||||
|
petOperationGetByTagTryBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags button.try-out__btn"
|
||||||
|
},
|
||||||
|
petOperationGetByTagTryAdded: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags button.json-schema-form-item-add"
|
||||||
|
},
|
||||||
|
petOperationGetByTagExecuteBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags button.execute"
|
||||||
|
},
|
||||||
|
petOperationGetByTagTryTextArea: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags textarea"
|
||||||
|
},
|
||||||
|
petOperationGetByTagResultsBox: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight"
|
||||||
|
},
|
||||||
|
petOperationGetByTagMockCategoryID: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight span:nth-child(17)"
|
||||||
|
},
|
||||||
|
petOperationGetByTagMockCategoryName: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight span:nth-child(23)"
|
||||||
|
},
|
||||||
|
petOperationGetByTagMockName: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight span:nth-child(31)"
|
||||||
|
},
|
||||||
|
petOperationGetByTagTagID: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight span:nth-child(54)"
|
||||||
|
},
|
||||||
|
petOperationGetByTagTagName: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight span:nth-child(60)"
|
||||||
|
},
|
||||||
|
petOperationGetByTagStatus: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-findPetsByTags pre.microlight span:nth-child(70)"
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete pet/
|
||||||
|
*/
|
||||||
|
petOperationDeleteContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet"
|
||||||
|
},
|
||||||
|
petOperationDeleteTitle: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet .opblock-summary-delete span.opblock-summary-path span"
|
||||||
|
},
|
||||||
|
petOperationDeleteCollpase: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet .opblock-summary-delete"
|
||||||
|
},
|
||||||
|
petOperationDeleteCollapseContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet>div:nth-child(2)"
|
||||||
|
},
|
||||||
|
petOperationDeleteTryBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet button.try-out__btn"
|
||||||
|
},
|
||||||
|
petOperationDeleteExecuteBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet button.execute"
|
||||||
|
},
|
||||||
|
petOperationDeleteTryTextArea: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet textarea"
|
||||||
|
},
|
||||||
|
petOperationDeleteResultsBox: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight"
|
||||||
|
},
|
||||||
|
petOperationDeleteMockCategoryID: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight span:nth-child(17)"
|
||||||
|
},
|
||||||
|
petOperationDeleteMockCategoryName: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight span:nth-child(23)"
|
||||||
|
},
|
||||||
|
petOperationDeleteMockName: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight span:nth-child(31)"
|
||||||
|
},
|
||||||
|
petOperationDeleteTagID: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight span:nth-child(54)"
|
||||||
|
},
|
||||||
|
petOperationDeleteTagName: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight span:nth-child(60)"
|
||||||
|
},
|
||||||
|
petOperationDeleteStatus: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(1) div#operations-pet-deletePet pre.microlight span:nth-child(70)"
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ***********Store************
|
||||||
|
*/
|
||||||
|
storeAPIWrapper: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2)"
|
||||||
|
},
|
||||||
|
storeAPIWrapperBar: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) .opblock-tag"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Get /store/inventory
|
||||||
|
*/
|
||||||
|
storeOperationGetContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory"
|
||||||
|
},
|
||||||
|
storeOperationGetTitle: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory .opblock-summary-get span.opblock-summary-path span"
|
||||||
|
},
|
||||||
|
storeOperationGetCollpase: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory .opblock-summary-get"
|
||||||
|
},
|
||||||
|
storeOperationGetCollapseContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory>div:nth-child(2)"
|
||||||
|
},
|
||||||
|
storeOperationGetTryBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory button.try-out__btn"
|
||||||
|
},
|
||||||
|
storeOperationGetExecuteBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory button.execute"
|
||||||
|
},
|
||||||
|
storeOperationResponseProps1: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory pre.example.microlight span:nth-child(6)"
|
||||||
|
},
|
||||||
|
storeOperationResponseProps2: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory pre.example.microlight span:nth-child(12)"
|
||||||
|
},
|
||||||
|
storeOperationResponseProps3: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-getInventory pre.example.microlight span:nth-child(18)"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Post /store/order
|
||||||
|
*/
|
||||||
|
storeOperationPostContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder"
|
||||||
|
},
|
||||||
|
storeOperationPostTitle: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder .opblock-summary-post span.opblock-summary-path span"
|
||||||
|
},
|
||||||
|
storeOperationPostCollpase: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder .opblock-summary-post"
|
||||||
|
},
|
||||||
|
storeOperationPostCollapseContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder>div:nth-child(2)"
|
||||||
|
},
|
||||||
|
storeOperationPostTryBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder button.try-out__btn"
|
||||||
|
},
|
||||||
|
storeOperationPostExecuteBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder button.execute"
|
||||||
|
},
|
||||||
|
storeOperationPostResponseId: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder pre.example.microlight span:nth-child(22)"
|
||||||
|
},
|
||||||
|
storeOperationPostResponsePetId: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder pre.example.microlight span:nth-child(31)"
|
||||||
|
},
|
||||||
|
storeOperationPostResponseQuantity: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder pre.example.microlight span:nth-child(40)"
|
||||||
|
},
|
||||||
|
storeOperationPostResponseStatus: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder pre.example.microlight span:nth-child(66)"
|
||||||
|
},
|
||||||
|
storeOperationPostResponseComplete: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-placeOrder pre.example.microlight span:nth-child(75)"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Delete /store/order/{orderId}
|
||||||
|
*/
|
||||||
|
storeOperationDeleteContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder"
|
||||||
|
},
|
||||||
|
storeOperationDeleteTitle: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder .opblock-summary-delete span.opblock-summary-path span"
|
||||||
|
},
|
||||||
|
storeOperationDeleteCollpase: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder .opblock-summary-delete"
|
||||||
|
},
|
||||||
|
storeOperationDeleteCollapseContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder>div:nth-child(2)"
|
||||||
|
},
|
||||||
|
storeOperationDeleteTryBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder button.try-out__btn"
|
||||||
|
},
|
||||||
|
storeOperationDeleteExecuteBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder button.execute"
|
||||||
|
},
|
||||||
|
storeOperationGetResponseHeaders: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(2) div#operations-store-deleteOrder pre span"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* *********User**************
|
||||||
|
*/
|
||||||
|
userAPIWrapper: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3)"
|
||||||
|
},
|
||||||
|
userAPIWrapperBar: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) .opblock-tag"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Put /user/login
|
||||||
|
*/
|
||||||
|
userOperationPutContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser"
|
||||||
|
},
|
||||||
|
userOperationPutTitle: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser .opblock-summary-put span.opblock-summary-path span"
|
||||||
|
},
|
||||||
|
userOperationPutCollpase: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser .opblock-summary-put"
|
||||||
|
},
|
||||||
|
userOperationPutCollapseContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser>div:nth-child(2)"
|
||||||
|
},
|
||||||
|
userOperationPutTryBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser button.try-out__btn"
|
||||||
|
},
|
||||||
|
userOperationPutExecuteBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser button.execute"
|
||||||
|
},
|
||||||
|
userOperationPutParameter: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser div.parameters-col_description input"
|
||||||
|
},
|
||||||
|
userOperationPutResponseHeader: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-updateUser div.parameters-col_description input"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Delete /user
|
||||||
|
*/
|
||||||
|
userOperationDeleteContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser"
|
||||||
|
},
|
||||||
|
userOperationDeleteTitle: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser .opblock-summary-delete span.opblock-summary-path span"
|
||||||
|
},
|
||||||
|
userOperationDeleteCollpase: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser .opblock-summary-delete"
|
||||||
|
},
|
||||||
|
userOperationDeleteCollapseContainer: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser>div:nth-child(2)"
|
||||||
|
},
|
||||||
|
userOperationDeleteTryBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser button.try-out__btn"
|
||||||
|
},
|
||||||
|
userOperationDeleteExecuteBtn: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser button.execute"
|
||||||
|
},
|
||||||
|
userOperationDeleteParameter: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) div#operations-user-deleteUser div.parameters-col_description input"
|
||||||
|
},
|
||||||
|
userOperationDeleteResponseHeader: {
|
||||||
|
selector: ".swagger-ui .opblock-tag-section:nth-child(3) .opblock-delete div.parameters-col_description input"
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* Model Container */
|
||||||
|
modelWrapper: {
|
||||||
|
selector: ".swagger-ui .wrapper:nth-child(4)",
|
||||||
|
elements: {
|
||||||
|
modelContainer: {
|
||||||
|
selector: ".swagger-ui .models"
|
||||||
|
},
|
||||||
|
modelCollapse: {
|
||||||
|
selector: ".swagger-ui .models h4"
|
||||||
|
},
|
||||||
|
orderModel: {
|
||||||
|
selector: "section.models div.model-container:nth-child(1)"
|
||||||
|
},
|
||||||
|
orderModelCallapse: {
|
||||||
|
selector: "section.models div.model-container:nth-child(1) span.model-toggle"
|
||||||
|
},
|
||||||
|
categoryModel: {
|
||||||
|
selector: "section.models div.model-container:nth-child(2)"
|
||||||
|
},
|
||||||
|
categoryModelCallapse: {
|
||||||
|
selector: "section.models div.model-container:nth-child(2) span.model-toggle"
|
||||||
|
},
|
||||||
|
userModel: {
|
||||||
|
selector: "section.models div.model-container:nth-child(3)"
|
||||||
|
},
|
||||||
|
userModelCallapse: {
|
||||||
|
selector: "section.models div.model-container:nth-child(3) span.model-toggle"
|
||||||
|
},
|
||||||
|
tagModel: {
|
||||||
|
selector: "section.models div.model-container:nth-child(4)"
|
||||||
|
},
|
||||||
|
tagModelCallapse: {
|
||||||
|
selector: "section.models div.model-container:nth-child(4) span.model-toggle"
|
||||||
|
},
|
||||||
|
petModel: {
|
||||||
|
selector: "section.models div.model-container:nth-child(5)"
|
||||||
|
},
|
||||||
|
petModelCallapse: {
|
||||||
|
selector: "section.models div.model-container:nth-child(5) span.model-toggle"
|
||||||
|
},
|
||||||
|
apiResponseModel: {
|
||||||
|
selector: "section.models div.model-container:nth-child(6)"
|
||||||
|
},
|
||||||
|
apiResponseModelCallapse: {
|
||||||
|
selector: "section.models div.model-container:nth-child(6) span.model-toggle"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
48
test/e2e/scenarios/informationContainer.js
Normal file
48
test/e2e/scenarios/informationContainer.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
describe("render informationContainer", function () {
|
||||||
|
let mainPage
|
||||||
|
let informationContainer
|
||||||
|
beforeEach(function (client, done) {
|
||||||
|
|
||||||
|
mainPage = client
|
||||||
|
.url("localhost:3200")
|
||||||
|
.page.main()
|
||||||
|
client.waitForElementVisible(".download-url-input", 5000)
|
||||||
|
.pause(5000)
|
||||||
|
.clearValue(".download-url-input")
|
||||||
|
.setValue(".download-url-input", "http://localhost:3200/test-specs/petstore.json")
|
||||||
|
.click("button.download-url-button")
|
||||||
|
.pause(1000)
|
||||||
|
|
||||||
|
informationContainer = mainPage.section.informationContainer
|
||||||
|
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders section", function (client) {
|
||||||
|
mainPage.expect.section("@informationContainer").to.be.visible.before(5000)
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders content", function (client) {
|
||||||
|
informationContainer.waitForElementVisible("@title", 5000)
|
||||||
|
.assert.containsText("@title", "Swagger Petstore")
|
||||||
|
.assert.containsText("@version", "1.0.0")
|
||||||
|
.assert.containsText("@baseUrl", "[ Base URL: localhost:3204/ ]")
|
||||||
|
.assert.attributeEquals("@mainUrl", "href", "http://localhost:3200/test-specs/petstore.json")
|
||||||
|
.assert.containsText("@mainUrlContent", "http://localhost:3200/test-specs/petstore.json")
|
||||||
|
.assert.containsText("@description", "This is a sample server Petstore server. You can find out more about Swagger at http://swagger.io or on irc.freenode.net, #swagger. For this sample, you can use the api key special-key to test the authorization filters.")
|
||||||
|
.assert.attributeEquals("@swaggerUrl", "href", "http://swagger.io/")
|
||||||
|
.assert.attributeEquals("@swaggerircUrl", "href", "http://swagger.io/irc/")
|
||||||
|
.assert.attributeEquals("@termsLink", "href", "http://swagger.io/terms/")
|
||||||
|
.assert.containsText("@termsLink", "Terms of service")
|
||||||
|
.assert.attributeEquals("@contactDevLink", "href", "mailto:apiteam@swagger.io")
|
||||||
|
.assert.containsText("@contactDevLink", "Contact the developer")
|
||||||
|
.assert.attributeEquals("@contactDevLink", "href", "mailto:apiteam@swagger.io")
|
||||||
|
.assert.containsText("@contactDevLink", "Contact the developer")
|
||||||
|
.assert.attributeEquals("@aboutSwaggerLink", "href", "http://swagger.io/")
|
||||||
|
.assert.containsText("@aboutSwaggerLink", "Find out more about Swagger")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
})
|
||||||
79
test/e2e/scenarios/models.js
Normal file
79
test/e2e/scenarios/models.js
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
describe("Render Model Wrapper", function () {
|
||||||
|
let modelWrapper, mainPage
|
||||||
|
|
||||||
|
beforeEach(function (client, done) {
|
||||||
|
mainPage = client
|
||||||
|
.url("localhost:3200")
|
||||||
|
.page.main()
|
||||||
|
client.waitForElementVisible(".download-url-input", 5000)
|
||||||
|
.pause(5000)
|
||||||
|
.clearValue(".download-url-input")
|
||||||
|
.setValue(".download-url-input", "http://localhost:3200/test-specs/petstore.json")
|
||||||
|
.click("button.download-url-button")
|
||||||
|
.pause(1000)
|
||||||
|
|
||||||
|
modelWrapper = mainPage.section.modelWrapper
|
||||||
|
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
afterEach(function (client, done){
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
it("Render model wrapper", function(client){
|
||||||
|
mainPage.expect.section("@modelWrapper").to.be.visible.before(5000)
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Render model wrapper collapse", function(client){
|
||||||
|
modelWrapper.waitForElementVisible("@modelContainer", 5000)
|
||||||
|
.click("@modelCollapse")
|
||||||
|
.assert.cssClassNotPresent("@modelContainer", "is-open")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Testing order model", function(client){
|
||||||
|
modelWrapper.waitForElementVisible("@orderModel")
|
||||||
|
.click("@orderModelCallapse")
|
||||||
|
.assert.cssClassNotPresent("@orderModelCallapse", "callapsed")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Testing category model", function(client){
|
||||||
|
modelWrapper.waitForElementVisible("@categoryModel")
|
||||||
|
.click("@categoryModelCallapse")
|
||||||
|
.assert.cssClassNotPresent("@categoryModelCallapse", "callapsed")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("Testing user model", function(client){
|
||||||
|
modelWrapper.waitForElementVisible("@userModel")
|
||||||
|
.click("@userModelCallapse")
|
||||||
|
.assert.cssClassNotPresent("@userModelCallapse", "callapsed")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("Testing tag model", function(client){
|
||||||
|
modelWrapper.waitForElementVisible("@tagModel")
|
||||||
|
.click("@tagModelCallapse")
|
||||||
|
.assert.cssClassNotPresent("@tagModelCallapse", "callapsed")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("Testing pet model", function(client){
|
||||||
|
modelWrapper.waitForElementVisible("@petModel")
|
||||||
|
.click("@petModelCallapse")
|
||||||
|
.assert.cssClassNotPresent("@petModelCallapse", "callapsed")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("Testing apiResponse model", function(client){
|
||||||
|
modelWrapper.waitForElementVisible("@apiResponseModel")
|
||||||
|
.click("@apiResponseModelCallapse")
|
||||||
|
.assert.cssClassNotPresent("@apiResponseModelCallapse", "callapsed")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
})
|
||||||
172
test/e2e/scenarios/operations/pet.js
Normal file
172
test/e2e/scenarios/operations/pet.js
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
describe("render pet api container", function () {
|
||||||
|
let mainPage
|
||||||
|
let apiWrapper
|
||||||
|
beforeEach(function (client, done) {
|
||||||
|
mainPage = client
|
||||||
|
.url("localhost:3200")
|
||||||
|
.page.main()
|
||||||
|
|
||||||
|
client.waitForElementVisible(".download-url-input", 5000)
|
||||||
|
.pause(5000)
|
||||||
|
.clearValue(".download-url-input")
|
||||||
|
.setValue(".download-url-input", "http://localhost:3200/test-specs/petstore.json")
|
||||||
|
.click("button.download-url-button")
|
||||||
|
.pause(1000)
|
||||||
|
|
||||||
|
apiWrapper = mainPage.section.apiWrapper
|
||||||
|
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
afterEach(function (client, done) {
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
it("render section", function (client) {
|
||||||
|
mainPage.expect.section("@apiWrapper").to.be.visible.before(10000)
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("test rendered pet container", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@petAPIWrapper", 5000)
|
||||||
|
.expect.element("@petAPIWrapper").to.be.visible
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("collapse pet wrapper", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@petAPIWrapper", 5000)
|
||||||
|
.click("@petAPIWrapperBar")
|
||||||
|
.assert.cssClassNotPresent("@petAPIWrapper", "is-open")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("render post /pet api container", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@petOperationPostContainer", 10000)
|
||||||
|
.assert.containsText("@petOperationPostTitle", "/pet")
|
||||||
|
.click("@petOperationPostCollpase")
|
||||||
|
.waitForElementVisible("@petOperationPostCollapseContainer", 5000)
|
||||||
|
.click("@petOperationPostTryBtn")
|
||||||
|
.waitForElementVisible("@petOperationPostTryText", 1000)
|
||||||
|
.waitForElementVisible("@petOperationPostExecuteBtn", 1000)
|
||||||
|
.click("@petOperationPostTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@petOperationPostTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Testing post /pet api Mock data", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@petOperationPostContainer", 5000)
|
||||||
|
.click("@petOperationPostCollpase")
|
||||||
|
.waitForElementVisible("@petOperationPostCollapseContainer", 5000)
|
||||||
|
.click("@petOperationPostTryBtn")
|
||||||
|
.waitForElementVisible("@petOperationPostExecuteBtn", 1000)
|
||||||
|
.click("@petOperationPostExecuteBtn")
|
||||||
|
.waitForElementVisible("@petOperationPostMockCategoryID", 2000)
|
||||||
|
.assert.containsText("@petOperationPostMockCategoryID", "0")
|
||||||
|
.assert.containsText("@petOperationPostMockCategoryName", "\"string\"")
|
||||||
|
.assert.containsText("@petOperationPostMockName", "\"doggie\"")
|
||||||
|
.assert.containsText("@petOperationPostTagID", "0")
|
||||||
|
.assert.containsText("@petOperationPostTagName", "\"string\"")
|
||||||
|
.assert.containsText("@petOperationPostStatus", "\"available\"")
|
||||||
|
.click("@petOperationPostTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@petOperationPostTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("render put /pet api container", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@petOperationPutContainer", 5000)
|
||||||
|
.assert.containsText("@petOperationPutTitle", "/pet")
|
||||||
|
.click("@petOperationPutCollpase")
|
||||||
|
.waitForElementVisible("@petOperationPutCollapseContainer", 3000)
|
||||||
|
.click("@petOperationPutTryBtn")
|
||||||
|
.waitForElementVisible("@petOperationPutTryText", 1000)
|
||||||
|
.waitForElementVisible("@petOperationPutExecuteBtn", 1000)
|
||||||
|
.click("@petOperationPutTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@petOperationPutTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("Testing put /pet api Mock data", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@petOperationPutContainer", 5000)
|
||||||
|
.click("@petOperationPutCollpase")
|
||||||
|
.waitForElementVisible("@petOperationPutCollapseContainer", 3000)
|
||||||
|
.click("@petOperationPutTryBtn")
|
||||||
|
.waitForElementVisible("@petOperationPutExecuteBtn", 1000)
|
||||||
|
.click("@petOperationPutExecuteBtn")
|
||||||
|
.waitForElementVisible("@petOperationPutMockCategoryID")
|
||||||
|
.assert.containsText("@petOperationPutMockCategoryID", "0")
|
||||||
|
.assert.containsText("@petOperationPutMockCategoryName", "\"string\"")
|
||||||
|
.assert.containsText("@petOperationPutMockName", "\"doggie\"")
|
||||||
|
.assert.containsText("@petOperationPutTagID", "0")
|
||||||
|
.assert.containsText("@petOperationPutTagName", "\"string\"")
|
||||||
|
.assert.containsText("@petOperationPutStatus", "\"available\"")
|
||||||
|
.click("@petOperationPutTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@petOperationPutTryBtn", "Cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("render get by tag /pet api container", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@petOperationGetByTagContainer", 5000)
|
||||||
|
.assert.containsText("@petOperationGetByTagTitle", "/pet/findByTags")
|
||||||
|
.click("@petOperationGetByTagCollpase")
|
||||||
|
.waitForElementVisible("@petOperationGetByTagCollapseContainer", 3000)
|
||||||
|
.click("@petOperationGetByTagTryBtn")
|
||||||
|
.waitForElementVisible("@petOperationGetByTagTryAdded", 1000)
|
||||||
|
.waitForElementVisible("@petOperationGetByTagExecuteBtn", 1000)
|
||||||
|
.click("@petOperationGetByTagTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@petOperationGetByTagTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Testing get by tag /pet api Mock data", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@petOperationGetByTagContainer", 5000)
|
||||||
|
.click("@petOperationGetByTagCollpase")
|
||||||
|
.waitForElementVisible("@petOperationGetByTagCollapseContainer", 3000)
|
||||||
|
.click("@petOperationGetByTagTryBtn")
|
||||||
|
.waitForElementVisible("@petOperationGetByTagExecuteBtn", 1000)
|
||||||
|
.click("@petOperationGetByTagExecuteBtn")
|
||||||
|
.waitForElementVisible("@petOperationGetByTagMockCategoryID")
|
||||||
|
.assert.containsText("@petOperationGetByTagMockCategoryID", "0")
|
||||||
|
.assert.containsText("@petOperationGetByTagMockCategoryName", "\"string\"")
|
||||||
|
.assert.containsText("@petOperationGetByTagMockName", "\"doggie\"")
|
||||||
|
.assert.containsText("@petOperationGetByTagTagID", "0")
|
||||||
|
.assert.containsText("@petOperationGetByTagTagName", "\"string\"")
|
||||||
|
.assert.containsText("@petOperationGetByTagStatus", "\"available\"")
|
||||||
|
.click("@petOperationGetByTagTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@petOperationGetByTagTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("render delete /pet api container", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@petOperationDeleteContainer")
|
||||||
|
.assert.containsText("@petOperationDeleteTitle", "/pet/{petId}")
|
||||||
|
.click("@petOperationDeleteCollpase")
|
||||||
|
.waitForElementVisible("@petOperationDeleteCollapseContainer", 3000)
|
||||||
|
.click("@petOperationDeleteTryBtn")
|
||||||
|
.waitForElementVisible("@petOperationDeleteExecuteBtn", 1000)
|
||||||
|
.click("@petOperationDeleteTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@petOperationDeleteTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("Testing delete /pet api Mock data", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@petOperationDeleteContainer", 3000)
|
||||||
|
.click("@petOperationDeleteCollpase")
|
||||||
|
.waitForElementVisible("@petOperationDeleteCollapseContainer", 3000)
|
||||||
|
.click("@petOperationDeleteTryBtn")
|
||||||
|
.waitForElementVisible("@petOperationDeleteExecuteBtn", 1000)
|
||||||
|
.click("@petOperationDeleteExecuteBtn")
|
||||||
|
.waitForElementVisible("@petOperationDeleteMockCategoryID")
|
||||||
|
.assert.containsText("@petOperationDeleteMockCategoryID", "0")
|
||||||
|
.assert.containsText("@petOperationDeleteMockCategoryName", "\"string\"")
|
||||||
|
.assert.containsText("@petOperationDeleteMockName", "\"doggie\"")
|
||||||
|
.assert.containsText("@petOperationDeleteTagID", "0")
|
||||||
|
.assert.containsText("@petOperationDeleteTagName", "\"string\"")
|
||||||
|
.assert.containsText("@petOperationDeleteStatus", "\"available\"")
|
||||||
|
.click("@petOperationDeleteTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@petOperationDeleteTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
})
|
||||||
113
test/e2e/scenarios/operations/store.js
Normal file
113
test/e2e/scenarios/operations/store.js
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
describe("render store api container", function(){
|
||||||
|
let mainPage
|
||||||
|
let apiWrapper
|
||||||
|
beforeEach( function(client, done){
|
||||||
|
mainPage = client
|
||||||
|
.url("localhost:3200")
|
||||||
|
.page.main()
|
||||||
|
|
||||||
|
client.waitForElementVisible(".download-url-input", 5000)
|
||||||
|
.pause(3000)
|
||||||
|
.clearValue(".download-url-input")
|
||||||
|
.setValue(".download-url-input", "http://localhost:3200/test-specs/petstore.json")
|
||||||
|
.click("button.download-url-button")
|
||||||
|
.pause(1000)
|
||||||
|
|
||||||
|
apiWrapper = mainPage.section.apiWrapper
|
||||||
|
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
afterEach(function (client, done) {
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
it("test rendered store container", function(client){
|
||||||
|
apiWrapper.waitForElementVisible("@storeAPIWrapper", 5000)
|
||||||
|
.expect.element("@storeAPIWrapper").to.be.visible
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("callapse store wrapper", function(client){
|
||||||
|
apiWrapper.waitForElementVisible("@storeAPIWrapper", 5000)
|
||||||
|
.click("@storeAPIWrapperBar")
|
||||||
|
.assert.cssClassNotPresent("@storeAPIWrapper", "is-open")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("render get /store/inventory api container", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@storeOperationGetContainer", 5000)
|
||||||
|
.assert.containsText("@storeOperationGetTitle", "/store/inventory")
|
||||||
|
.click("@storeOperationGetCollpase")
|
||||||
|
.waitForElementVisible("@storeOperationGetCollapseContainer", 5000)
|
||||||
|
.click("@storeOperationGetTryBtn")
|
||||||
|
.waitForElementVisible("@storeOperationGetExecuteBtn", 1000)
|
||||||
|
.click("@storeOperationGetTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@storeOperationGetTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Testing get /store/inventory api Mock data ", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@storeOperationGetContainer", 5000)
|
||||||
|
.assert.containsText("@storeOperationGetTitle", "/store/inventory")
|
||||||
|
.click("@storeOperationGetCollpase")
|
||||||
|
.waitForElementVisible("@storeOperationGetCollapseContainer", 3000)
|
||||||
|
.click("@storeOperationGetTryBtn")
|
||||||
|
.waitForElementVisible("@storeOperationGetExecuteBtn", 1000)
|
||||||
|
.click("@storeOperationGetExecuteBtn")
|
||||||
|
.waitForElementVisible("@storeOperationResponseProps1")
|
||||||
|
.assert.containsText("@storeOperationResponseProps1", "0")
|
||||||
|
.assert.containsText("@storeOperationResponseProps2", "0")
|
||||||
|
.assert.containsText("@storeOperationResponseProps3", "0")
|
||||||
|
.click("@storeOperationGetTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@storeOperationGetTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("render post /store/order api container", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@storeOperationPostContainer")
|
||||||
|
.assert.containsText("@storeOperationPostTitle", "/store/order")
|
||||||
|
.click("@storeOperationPostCollpase")
|
||||||
|
.waitForElementVisible("@storeOperationPostCollapseContainer", 3000)
|
||||||
|
.click("@storeOperationPostTryBtn")
|
||||||
|
.waitForElementVisible("@storeOperationPostExecuteBtn", 1000)
|
||||||
|
.click("@storeOperationPostTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@storeOperationPostTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Testing post /store/order api Mock Data", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@storeOperationPostContainer")
|
||||||
|
.assert.containsText("@storeOperationPostTitle", "/store/order")
|
||||||
|
.click("@storeOperationPostCollpase")
|
||||||
|
.waitForElementVisible("@storeOperationPostCollapseContainer", 3000)
|
||||||
|
.click("@storeOperationPostTryBtn")
|
||||||
|
.waitForElementVisible("@storeOperationPostExecuteBtn", 1000)
|
||||||
|
.click("@storeOperationPostExecuteBtn")
|
||||||
|
.waitForElementVisible("@storeOperationPostResponseId")
|
||||||
|
.assert.containsText("@storeOperationPostResponseId", "0")
|
||||||
|
.assert.containsText("@storeOperationPostResponsePetId", "0")
|
||||||
|
.assert.containsText("@storeOperationPostResponseQuantity", "0")
|
||||||
|
.assert.containsText("@storeOperationPostResponseStatus", "placed")
|
||||||
|
.assert.containsText("@storeOperationPostResponseComplete", "false")
|
||||||
|
.click("@storeOperationPostTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@storeOperationPostTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("render delete /store/order/{orderId} api container", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@storeOperationDeleteContainer")
|
||||||
|
.assert.containsText("@storeOperationDeleteTitle", "/store/order/{orderId}")
|
||||||
|
.click("@storeOperationDeleteCollpase")
|
||||||
|
.waitForElementVisible("@storeOperationDeleteCollapseContainer", 3000)
|
||||||
|
.click("@storeOperationDeleteTryBtn")
|
||||||
|
.waitForElementVisible("@storeOperationDeleteExecuteBtn", 1000)
|
||||||
|
.click("@storeOperationDeleteExecuteBtn")
|
||||||
|
.waitForElementVisible("@storeOperationGetResponseHeaders", "content-type: application/xml")
|
||||||
|
.click("@storeOperationDeleteTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@storeOperationDeleteTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
})
|
||||||
94
test/e2e/scenarios/operations/user.js
Normal file
94
test/e2e/scenarios/operations/user.js
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
describe("render user api container", function(){
|
||||||
|
let mainPage
|
||||||
|
let apiWrapper
|
||||||
|
beforeEach( function(client, done){
|
||||||
|
mainPage = client
|
||||||
|
.url("localhost:3200")
|
||||||
|
.page.main()
|
||||||
|
|
||||||
|
client.waitForElementVisible(".download-url-input", 5000)
|
||||||
|
.pause(5000)
|
||||||
|
.clearValue(".download-url-input")
|
||||||
|
.setValue(".download-url-input", "http://localhost:3200/test-specs/petstore.json")
|
||||||
|
.click("button.download-url-button")
|
||||||
|
.pause(1000)
|
||||||
|
|
||||||
|
apiWrapper = mainPage.section.apiWrapper
|
||||||
|
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
afterEach(function (client, done) {
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
it("test rendered user container", function(client){
|
||||||
|
apiWrapper.waitForElementVisible("@userAPIWrapper", 5000)
|
||||||
|
.expect.element("@userAPIWrapper").to.be.visible
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("callapse user wrapper", function(client){
|
||||||
|
apiWrapper.waitForElementVisible("@userAPIWrapper", 5000)
|
||||||
|
.click("@userAPIWrapperBar")
|
||||||
|
.assert.cssClassNotPresent("@userAPIWrapper", "is-open")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("render put /user/{username} api container", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@userOperationPutContainer", 5000)
|
||||||
|
.assert.containsText("@userOperationPutTitle", "/user/{username}")
|
||||||
|
.click("@userOperationPutCollpase")
|
||||||
|
.waitForElementVisible("@userOperationPutCollapseContainer", 3000)
|
||||||
|
.click("@userOperationPutTryBtn")
|
||||||
|
.waitForElementVisible("@userOperationPutExecuteBtn", 1000)
|
||||||
|
.click("@userOperationPutTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@userOperationPutTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("Test put /user/{username} api Mock data", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@userOperationPutContainer", 5000)
|
||||||
|
.assert.containsText("@userOperationPutTitle", "/user/{username}")
|
||||||
|
.click("@userOperationPutCollpase")
|
||||||
|
.waitForElementVisible("@userOperationPutCollapseContainer", 3000)
|
||||||
|
.click("@userOperationPutTryBtn")
|
||||||
|
.waitForElementVisible("@userOperationPutParameter")
|
||||||
|
.setValue("@userOperationPutParameter", "123")
|
||||||
|
.waitForElementVisible("@userOperationPutExecuteBtn", 1000)
|
||||||
|
.click("userOperationPutExecuteBtn")
|
||||||
|
.waitForElementVisible("@userOperationPutResponseHeader")
|
||||||
|
.assert.containsText("@userOperationPutResponseHeader", "content-type: application/xml")
|
||||||
|
.click("@userOperationPutTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@userOperationPutTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("render delete /user/{username} api container", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@userOperationDeleteContainer", 5000)
|
||||||
|
.assert.containsText("@userOperationDeleteTitle", "/user/{username}")
|
||||||
|
.click("@userOperationDeleteCollpase")
|
||||||
|
.waitForElementVisible("@userOperationDeleteCollapseContainer", 3000)
|
||||||
|
.click("@userOperationDeleteTryBtn")
|
||||||
|
.waitForElementVisible("@userOperationDeleteExecuteBtn", 1000)
|
||||||
|
.click("@userOperationDeleteTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@userOperationDeleteTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("Test delete /user/{username} api Mock data", function (client) {
|
||||||
|
apiWrapper.waitForElementVisible("@userOperationDeleteContainer", 5000)
|
||||||
|
.assert.containsText("@userOperationDeleteTitle", "/user/{username}")
|
||||||
|
.click("@userOperationDeleteCollpase")
|
||||||
|
.waitForElementVisible("@userOperationDeleteCollapseContainer", 3000)
|
||||||
|
.click("@userOperationDeleteTryBtn")
|
||||||
|
.waitForElementVisible("@userOperationDeleteParameter")
|
||||||
|
.setValue("@userOperationDeleteParameter", "123")
|
||||||
|
.waitForElementVisible("@userOperationDeleteExecuteBtn", 1000)
|
||||||
|
.click("userOperationDeleteExecuteBtn")
|
||||||
|
.waitForElementVisible("@userOperationDeleteResponseHeader")
|
||||||
|
.assert.containsText("@userOperationDeleteResponseHeader", "content-type: application/xml")
|
||||||
|
.click("@userOperationDeleteTryBtn")
|
||||||
|
.assert.cssClassNotPresent("@userOperationDeleteTryBtn", "cancel")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
})
|
||||||
52
test/e2e/scenarios/schemeContainer.js
Normal file
52
test/e2e/scenarios/schemeContainer.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
describe("Render scheme", function () {
|
||||||
|
let mainPage
|
||||||
|
let schemeContainer
|
||||||
|
beforeEach(function (client, done) {
|
||||||
|
|
||||||
|
mainPage = client
|
||||||
|
.url("localhost:3200")
|
||||||
|
.page.main()
|
||||||
|
|
||||||
|
schemeContainer = mainPage.section.schemeContainer
|
||||||
|
|
||||||
|
client.waitForElementVisible(".download-url-input", 5000)
|
||||||
|
.pause(5000)
|
||||||
|
.clearValue(".download-url-input")
|
||||||
|
.setValue(".download-url-input", "http://localhost:3200/test-specs/petstore.json")
|
||||||
|
.click("button.download-url-button")
|
||||||
|
.pause(1000)
|
||||||
|
|
||||||
|
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("render section", function (client) {
|
||||||
|
mainPage.expect.section("@schemeContainer").to.be.visible.before(5000)
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("render scheme option", function (client) {
|
||||||
|
schemeContainer.waitForElementVisible("@httpOption", 5000)
|
||||||
|
.expect.element("@httpOption").to.be.selected
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("render authorized button", function (client) {
|
||||||
|
schemeContainer.waitForElementVisible("@btnAuthorize", 5000)
|
||||||
|
.expect.element("@btnAuthorize").to.be.visible
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
it("render click event", function(client) {
|
||||||
|
schemeContainer.waitForElementVisible("@btnAuthorize", 5000)
|
||||||
|
.click("@btnAuthorize")
|
||||||
|
.assert.visible("@authorizationModal")
|
||||||
|
.assert.containsText("@appName", "Application: your-app-name")
|
||||||
|
.assert.containsText("@authorizationUrl", "http://petstore.swagger.io/oauth/dialog")
|
||||||
|
.assert.containsText("@flow", "implicit")
|
||||||
|
.assert.value("@inputClientID", "your-client-id")
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
})
|
||||||
52
test/e2e/scenarios/topbar.js
Normal file
52
test/e2e/scenarios/topbar.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
describe("initial render", function () {
|
||||||
|
let mainPage
|
||||||
|
describe("for topbar", function () {
|
||||||
|
let topbar
|
||||||
|
before(function (client, done) {
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
after(function (client, done) {
|
||||||
|
client.end(function () {
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(function (client, done) {
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(function (client, done) {
|
||||||
|
mainPage = client
|
||||||
|
.url("localhost:3200")
|
||||||
|
.page.main()
|
||||||
|
|
||||||
|
topbar = mainPage.section.topbar
|
||||||
|
|
||||||
|
client.waitForElementVisible(".download-url-input", 10000)
|
||||||
|
.pause(5000)
|
||||||
|
.clearValue(".download-url-input")
|
||||||
|
.setValue(".download-url-input", "http://localhost:3200/test-specs/petstore.json")
|
||||||
|
.click("button.download-url-button")
|
||||||
|
.pause(1000)
|
||||||
|
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders section", function (client) {
|
||||||
|
mainPage.expect.section("@topbar").to.be.visible
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders input box", function (client) {
|
||||||
|
topbar.expect.element("@inputBox").to.be.visible
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders explore button", function (client) {
|
||||||
|
topbar.expect.element("@btnExplore").to.be.visible
|
||||||
|
|
||||||
|
client.end()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
1043
test/e2e/specs/petstore.json
Normal file
1043
test/e2e/specs/petstore.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,8 @@
|
|||||||
const config = require("./webpack-dist.config.js")
|
const config = require("./webpack-dist.config.js")
|
||||||
|
|
||||||
|
config.plugins = config.plugins.filter(plugin => {
|
||||||
|
// Disable minification
|
||||||
|
return plugin.constructor.name !== "UglifyJsPlugin"
|
||||||
|
})
|
||||||
|
|
||||||
module.exports = config
|
module.exports = config
|
||||||
|
|||||||
Reference in New Issue
Block a user