diff --git a/.babelrc b/.babelrc
index 2b14751a..57276240 100644
--- a/.babelrc
+++ b/.babelrc
@@ -18,6 +18,10 @@
"expose": "components",
"src": "src/core/components"
},
+ {
+ "expose": "containers",
+ "src": "src/core/containers"
+ },
{
"expose": "core",
"src": "src/core"
diff --git a/src/core/components/layouts/base.jsx b/src/core/components/layouts/base.jsx
index d0d56b37..f1d09b89 100644
--- a/src/core/components/layouts/base.jsx
+++ b/src/core/components/layouts/base.jsx
@@ -6,67 +6,35 @@ export default class BaseLayout extends React.Component {
static propTypes = {
errSelectors: PropTypes.object.isRequired,
errActions: PropTypes.object.isRequired,
- specActions: PropTypes.object.isRequired,
specSelectors: PropTypes.object.isRequired,
oas3Selectors: PropTypes.object.isRequired,
oas3Actions: PropTypes.object.isRequired,
- layoutSelectors: PropTypes.object.isRequired,
- layoutActions: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired
}
- onFilterChange =(e) => {
- let {target: {value}} = e
- this.props.layoutActions.updateFilter(value)
- }
-
render() {
- let {
- specSelectors,
- specActions,
- getComponent,
- layoutSelectors,
- oas3Selectors,
- oas3Actions
- } = this.props
-
- let info = specSelectors.info()
- let url = specSelectors.url()
- let basePath = specSelectors.basePath()
- let host = specSelectors.host()
- let securityDefinitions = specSelectors.securityDefinitions()
- let externalDocs = specSelectors.externalDocs()
- let schemes = specSelectors.schemes()
- let servers = specSelectors.servers()
+ let {specSelectors, getComponent} = this.props
let SvgAssets = getComponent("SvgAssets")
+ let InfoContainer = getComponent("InfoContainer", true)
let VersionPragmaFilter = getComponent("VersionPragmaFilter")
- let Info = getComponent("info")
let Operations = getComponent("operations", true)
let Models = getComponent("Models", true)
- let AuthorizeBtn = getComponent("authorizeBtn", true)
let Row = getComponent("Row")
let Col = getComponent("Col")
- let Servers = getComponent("Servers")
+ let ServersContainer = getComponent("ServersContainer", true)
let Errors = getComponent("errors", true)
+ const SchemesContainer = getComponent("SchemesContainer", true)
+ const FilterContainer = getComponent("FilterContainer", true)
let isSwagger2 = specSelectors.isSwagger2()
let isOAS3 = specSelectors.isOAS3()
- let isLoading = specSelectors.loadingStatus() === "loading"
- let isFailed = specSelectors.loadingStatus() === "failed"
- let filter = layoutSelectors.currentFilter()
-
- let inputStyle = {}
- if(isFailed) inputStyle.color = "red"
- if(isLoading) inputStyle.color = "#aaa"
-
- const Schemes = getComponent("schemes")
-
const isSpecEmpty = !specSelectors.specStr()
if(isSpecEmpty) {
let loadingMessage
+ let isLoading = specSelectors.loadingStatus() === "loading"
if(isLoading) {
loadingMessage =
} else {
@@ -88,53 +56,15 @@ export default class BaseLayout extends React.Component {
- { info.count() ? (
-
- ) : null }
+
- { schemes && schemes.size || securityDefinitions ? (
-
-
- { schemes && schemes.size ? (
-
- ) : null }
- { securityDefinitions ? (
-
- ) : null }
-
-
- ) : null }
+
- { servers && servers.size ? (
-
-
- Server
-
-
-
+
- ) : null}
-
- {
- filter === null || filter === false ? null :
-
-
-
-
-
- }
+
diff --git a/src/core/containers/filter.jsx b/src/core/containers/filter.jsx
new file mode 100644
index 00000000..8cfdcff9
--- /dev/null
+++ b/src/core/containers/filter.jsx
@@ -0,0 +1,44 @@
+import React from "react"
+import PropTypes from "prop-types"
+
+export default class FilterContainer extends React.Component {
+
+ static propTypes = {
+ specSelectors: PropTypes.object.isRequired,
+ layoutSelectors: PropTypes.object.isRequired,
+ layoutActions: PropTypes.object.isRequired,
+ getComponent: PropTypes.func.isRequired,
+ }
+
+ onFilterChange = (e) => {
+ const {target: {value}} = e
+ this.props.layoutActions.updateFilter(value)
+ }
+
+ render () {
+ const {specSelectors, layoutSelectors, getComponent} = this.props
+ const Col = getComponent("Col")
+
+ const isLoading = specSelectors.loadingStatus() === "loading"
+ const isFailed = specSelectors.loadingStatus() === "failed"
+ const filter = layoutSelectors.currentFilter()
+
+ const inputStyle = {}
+ if (isFailed) inputStyle.color = "red"
+ if (isLoading) inputStyle.color = "#aaa"
+
+ return (
+
+ {filter === null || filter === false ? null :
+
+
+
+
+
+ }
+
+ )
+ }
+}
diff --git a/src/core/containers/info.jsx b/src/core/containers/info.jsx
new file mode 100644
index 00000000..4ae558c7
--- /dev/null
+++ b/src/core/containers/info.jsx
@@ -0,0 +1,32 @@
+import React from "react"
+import PropTypes from "prop-types"
+
+export default class InfoContainer extends React.Component {
+
+ static propTypes = {
+ specActions: PropTypes.object.isRequired,
+ specSelectors: PropTypes.object.isRequired,
+ getComponent: PropTypes.func.isRequired,
+ }
+
+ render () {
+ const {specSelectors, getComponent} = this.props
+
+ const info = specSelectors.info()
+ const url = specSelectors.url()
+ const basePath = specSelectors.basePath()
+ const host = specSelectors.host()
+ const externalDocs = specSelectors.externalDocs()
+
+ const Info = getComponent("info")
+
+ return (
+
+ {info && info.count() ? (
+
+ ) : null}
+
+ )
+ }
+}
diff --git a/src/core/containers/schemes.jsx b/src/core/containers/schemes.jsx
new file mode 100644
index 00000000..8d64c283
--- /dev/null
+++ b/src/core/containers/schemes.jsx
@@ -0,0 +1,43 @@
+import React from "react"
+import PropTypes from "prop-types"
+
+export default class SchemesContainer extends React.Component {
+
+ static propTypes = {
+ specActions: PropTypes.object.isRequired,
+ specSelectors: PropTypes.object.isRequired,
+ getComponent: PropTypes.func.isRequired,
+ }
+
+ render () {
+ const {specActions, specSelectors, getComponent} = this.props
+ const currentScheme = specSelectors.operationScheme()
+ const schemes = specSelectors.schemes()
+ const securityDefinitions = specSelectors.securityDefinitions()
+
+ const Col = getComponent("Col")
+ const AuthorizeBtn = getComponent("authorizeBtn", true)
+ const Schemes = getComponent("schemes")
+
+ return (
+
+ {schemes && schemes.size || securityDefinitions ? (
+
+
+ {schemes && schemes.size ? (
+
+ ) : null}
+ {securityDefinitions ? (
+
+ ) : null}
+
+
+ ) : null}
+
+ )
+ }
+}
diff --git a/src/core/plugins/oas3/components/index.js b/src/core/plugins/oas3/components/index.js
index b37817a8..d5f58c8e 100644
--- a/src/core/plugins/oas3/components/index.js
+++ b/src/core/plugins/oas3/components/index.js
@@ -2,6 +2,7 @@ import Callbacks from "./callbacks"
import RequestBody from "./request-body"
import OperationLink from "./operation-link.jsx"
import Servers from "./servers"
+import ServersContainer from "./servers-container"
import RequestBodyEditor from "./request-body-editor"
import HttpAuth from "./http-auth"
import OperationServers from "./operation-servers"
@@ -11,6 +12,7 @@ export default {
HttpAuth,
RequestBody,
Servers,
+ ServersContainer,
RequestBodyEditor,
OperationServers,
operationLink: OperationLink
diff --git a/src/core/plugins/oas3/components/servers-container.jsx b/src/core/plugins/oas3/components/servers-container.jsx
new file mode 100644
index 00000000..8476496a
--- /dev/null
+++ b/src/core/plugins/oas3/components/servers-container.jsx
@@ -0,0 +1,42 @@
+import React from "react"
+import PropTypes from "prop-types"
+
+export default class ServersContainer extends React.Component {
+
+ static propTypes = {
+ specSelectors: PropTypes.object.isRequired,
+ oas3Selectors: PropTypes.object.isRequired,
+ oas3Actions: PropTypes.object.isRequired,
+ getComponent: PropTypes.func.isRequired,
+ }
+
+ render () {
+ const {specSelectors, oas3Selectors, oas3Actions, getComponent} = this.props
+
+ const servers = specSelectors.servers()
+
+ const Col = getComponent("Col")
+ const Servers = getComponent("Servers")
+
+ return (
+
+ {servers && servers.size ? (
+
+
+ Server
+
+
+
+
+ ) : null}
+
+ )
+ }
+}
diff --git a/src/core/presets/base.js b/src/core/presets/base.js
index 8a7812d7..77cabf59 100644
--- a/src/core/presets/base.js
+++ b/src/core/presets/base.js
@@ -51,10 +51,13 @@ import Info, {
InfoUrl,
InfoBasePath
} from "core/components/info"
+import InfoContainer from "core/containers/info"
import Footer from "core/components/footer"
+import FilterContainer from "core/containers/filter"
import ParamBody from "core/components/param-body"
import Curl from "core/components/curl"
import Schemes from "core/components/schemes"
+import SchemesContainer from "core/containers/schemes"
import ModelCollapse from "core/components/model-collapse"
import ModelExample from "core/components/model-example"
import ModelWrapper from "core/components/model-wrapper"
@@ -95,6 +98,7 @@ export default function() {
clear: Clear,
liveResponse: LiveResponse,
info: Info,
+ InfoContainer,
onlineValidatorBadge: OnlineValidatorBadge,
operations: Operations,
operation: Operation,
@@ -110,9 +114,11 @@ export default function() {
contentType: ContentType,
overview: Overview,
footer: Footer,
+ FilterContainer,
ParamBody: ParamBody,
curl: Curl,
schemes: Schemes,
+ SchemesContainer,
modelExample: ModelExample,
ModelWrapper,
ModelCollapse,
diff --git a/test/components/filter.js b/test/components/filter.js
new file mode 100644
index 00000000..6a7ef1ac
--- /dev/null
+++ b/test/components/filter.js
@@ -0,0 +1,65 @@
+
+/* eslint-env mocha */
+import React from "react"
+import expect from "expect"
+import { mount } from "enzyme"
+import FilterContainer from "containers/filter"
+import { Col } from "components/layout-utils"
+
+describe("", function(){
+
+ const mockedProps = {
+ specSelectors: {
+ loadingStatus() {}
+ },
+ layoutSelectors: {
+ currentFilter() {}
+ },
+ getComponent: () => {return Col}
+ }
+
+ it("renders FilterContainer if filter is provided", function(){
+
+ // Given
+ let props = {...mockedProps}
+ props.layoutSelectors = {...mockedProps.specSelectors}
+ props.layoutSelectors.currentFilter = function() {return true}
+
+ // When
+ let wrapper = mount()
+
+ // Then
+ const renderedColInsideFilter = wrapper.find(Col)
+ expect(renderedColInsideFilter.length).toEqual(1)
+ })
+
+ it("does not render FilterContainer if filter is null", function(){
+
+ // Given
+ let props = {...mockedProps}
+ props.layoutSelectors = {...mockedProps.specSelectors}
+ props.layoutSelectors.currentFilter = function() {return null}
+
+ // When
+ let wrapper = mount()
+
+ // Then
+ const renderedColInsideFilter = wrapper.find(Col)
+ expect(renderedColInsideFilter.length).toEqual(0)
+ })
+
+ it("does not render FilterContainer if filter is false", function(){
+
+ // Given
+ let props = {...mockedProps}
+ props.layoutSelectors = {...mockedProps.specSelectors}
+ props.layoutSelectors.currentFilter = function() {return false}
+
+ // When
+ let wrapper = mount()
+
+ // Then
+ const renderedColInsideFilter = wrapper.find(Col)
+ expect(renderedColInsideFilter.length).toEqual(0)
+ })
+})
diff --git a/test/components/info-wrapper.js b/test/components/info-wrapper.js
new file mode 100644
index 00000000..fcb98d6f
--- /dev/null
+++ b/test/components/info-wrapper.js
@@ -0,0 +1,67 @@
+
+/* eslint-env mocha */
+import React from "react"
+import expect from "expect"
+import { mount } from "enzyme"
+import { fromJS } from "immutable"
+import InfoContainer from "containers/info"
+
+describe("", function () {
+
+ const components = {
+ info: () =>
+ }
+ const mockedProps = {
+ specSelectors: {
+ info () {},
+ url () {},
+ basePath () {},
+ host () {},
+ externalDocs () {}
+ },
+ getComponent: c => components[c]
+ }
+
+ it("renders Info inside InfoContainer if info is provided", function () {
+
+ // Given
+ let props = {...mockedProps}
+ props.specSelectors = {...mockedProps.specSelectors}
+ props.specSelectors.info = function () {return fromJS(["info1", "info2"])}
+
+ // When
+ let wrapper = mount()
+
+ // Then
+ const renderedInfo = wrapper.find("span.mocked-info")
+ expect(renderedInfo.length).toEqual(1)
+ })
+
+ it("does not render Info inside InfoContainer if no info is provided", function () {
+
+ // Given
+ let props = {...mockedProps}
+ props.specSelectors = {...mockedProps.specSelectors}
+ props.specSelectors.info = function () {return fromJS([])}
+
+ // When
+ let wrapper = mount()
+
+ // Then
+ const renderedInfo = wrapper.find("span.mocked-info")
+ expect(renderedInfo.length).toEqual(0)
+ })
+
+ it("does not render Info inside InfoContainer if info is undefined", function () {
+
+ // Given
+ let props = {...mockedProps}
+
+ // When
+ let wrapper = mount()
+
+ // Then
+ const renderedInfo = wrapper.find("span.mocked-info")
+ expect(renderedInfo.length).toEqual(0)
+ })
+})
diff --git a/test/components/schemes-wrapper.js b/test/components/schemes-wrapper.js
new file mode 100644
index 00000000..bc2692a5
--- /dev/null
+++ b/test/components/schemes-wrapper.js
@@ -0,0 +1,119 @@
+
+/* eslint-env mocha */
+import React from "react"
+import expect from "expect"
+import { mount, render } from "enzyme"
+import { fromJS } from "immutable"
+import SchemesContainer from "containers/schemes"
+import Schemes from "components/schemes"
+import { Col } from "components/layout-utils"
+
+describe("", function(){
+
+ const components = {
+ schemes: Schemes,
+ Col,
+ authorizeBtn: () =>
+ }
+ const mockedProps = {
+ specSelectors: {
+ securityDefinitions() {},
+ operationScheme() {},
+ schemes() {}
+ },
+ specActions: {
+ setScheme() {}
+ },
+ getComponent: c => components[c]
+ }
+ const twoSecurityDefinitions = {
+ "petstore_auth": {
+ "type": "oauth2",
+ "authorizationUrl": "http://petstore.swagger.io/oauth/dialog",
+ "flow": "implicit",
+ "scopes": {
+ "write:pets": "modify pets in your account",
+ "read:pets": "read your pets"
+ }
+ },
+ "api_key": {
+ "type": "apiKey",
+ "name": "api_key",
+ "in": "header"
+ }
+ }
+
+ it("renders Schemes inside SchemesContainer if schemes are provided", function(){
+
+ // Given
+ let props = {...mockedProps}
+ props.specSelectors = {...mockedProps.specSelectors}
+ props.specSelectors.operationScheme = function() {return "http"}
+ props.specSelectors.schemes = function() {return fromJS(["http", "https"])}
+
+ // When
+ let wrapper = mount()
+
+ // Then
+ const renderedSchemes = wrapper.find(Schemes)
+ expect(renderedSchemes.length).toEqual(1)
+ })
+
+ it("does not render Schemes inside SchemeWrapper if empty array of schemes is provided", function(){
+
+ // Given
+ let props = {...mockedProps}
+ props.specSelectors = {...mockedProps.specSelectors}
+ props.specSelectors.schemes = function() {return fromJS([])}
+
+ // When
+ let wrapper = mount()
+
+ // Then
+ const renderedSchemes = wrapper.find(Schemes)
+ expect(renderedSchemes.length).toEqual(0)
+ })
+
+ it("does not render Schemes inside SchemeWrapper if provided schemes are undefined", function(){
+
+ // Given
+ let props = {...mockedProps}
+ props.specSelectors = {...mockedProps.specSelectors}
+ props.specSelectors.schemes = function() {return undefined}
+
+ // When
+ let wrapper = mount()
+
+ // Then
+ const renderedSchemes = wrapper.find(Schemes)
+ expect(renderedSchemes.length).toEqual(0)
+ })
+
+ it("renders AuthorizeBtn inside SchemesContainer if security definition is provided", function(){
+
+ // Given
+ let props = {...mockedProps}
+ props.specSelectors = {...mockedProps.specSelectors}
+ props.specSelectors.securityDefinitions = function () {return fromJS(twoSecurityDefinitions)}
+
+ // When
+ let wrapper = render()
+
+ // Then
+ const renderedAuthorizeBtn = wrapper.find("span.mocked-button")
+ expect(renderedAuthorizeBtn.length).toEqual(1)
+ })
+
+ it("does not render AuthorizeBtn if security definition is not provided", function(){
+
+ // Given
+ let props = {...mockedProps}
+
+ // When
+ let wrapper = render()
+
+ // Then
+ const renderedAuthorizeBtn = wrapper.find("span.mocked-button")
+ expect(renderedAuthorizeBtn.length).toEqual(0)
+ })
+})
diff --git a/test/core/plugins/oas3/servers-wrapper.js b/test/core/plugins/oas3/servers-wrapper.js
new file mode 100644
index 00000000..aeece8c1
--- /dev/null
+++ b/test/core/plugins/oas3/servers-wrapper.js
@@ -0,0 +1,77 @@
+
+/* eslint-env mocha */
+import React from "react"
+import expect from "expect"
+import { mount } from "enzyme"
+import { fromJS } from "immutable"
+import ServersContainer from "core/plugins/oas3/components/servers-container"
+import Servers from "core/plugins/oas3/components/servers"
+import { Col } from "components/layout-utils"
+
+describe("", function(){
+
+ const components = {
+ Servers,
+ Col
+ }
+ const mockedProps = {
+ specSelectors: {
+ servers() {}
+ },
+ oas3Selectors: {
+ selectedServer() {},
+ serverVariableValue() {},
+ serverEffectiveValue() {}
+ },
+ oas3Actions: {
+ setSelectedServer() {},
+ setServerVariableValue() {}
+ },
+ getComponent: c => components[c]
+ }
+
+ it("renders Servers inside ServersContainer if servers are provided", function(){
+
+ // Given
+ let props = {...mockedProps}
+ props.specSelectors = {...mockedProps.specSelectors}
+ props.specSelectors.servers = function() {return fromJS([{url: "http://server1.com"}])}
+ props.oas3Selectors = {...mockedProps.oas3Selectors}
+ props.oas3Selectors.selectedServer = function() {return "http://server1.com"}
+
+ // When
+ let wrapper = mount()
+
+ // Then
+ const renderedServers = wrapper.find(Servers)
+ expect(renderedServers.length).toEqual(1)
+ })
+
+ it("does not render Servers inside ServersContainer if servers are empty", function(){
+
+ // Given
+ let props = {...mockedProps}
+ props.specSelectors = {...mockedProps.specSelectors}
+ props.specSelectors.servers = function() {return fromJS([])}
+
+ // When
+ let wrapper = mount()
+
+ // Then
+ const renderedServers = wrapper.find(Servers)
+ expect(renderedServers.length).toEqual(0)
+ })
+
+ it("does not render Servers inside ServersContainer if servers are undefined", function(){
+
+ // Given
+ let props = {...mockedProps}
+
+ // When
+ let wrapper = mount()
+
+ // Then
+ const renderedServers = wrapper.find(Servers)
+ expect(renderedServers.length).toEqual(0)
+ })
+})