From 8777d8b9ff2b3de8ebe4a7d6a331ea0f0cae9e1e Mon Sep 17 00:00:00 2001 From: kyle Date: Wed, 28 Feb 2018 17:50:08 -0800 Subject: [PATCH] fix: use `specPath` prop to resolve operations in OperationContainer (#4272) * Use `parameterWithMeta` to get parameter data in * Prefer specPath when fetching resolved subtrees in OperationContainer * Add test for OAS3 callback rendering * Remove debugger statement --- src/core/components/operation.jsx | 2 +- src/core/containers/OperationContainer.jsx | 43 ++++++++++++++++--- .../plugins/oas3/components/callbacks.jsx | 7 +-- .../oas3/wrap-components/parameters.jsx | 5 ++- test/e2e/scenarios/oas3/callbacks.js | 41 ++++++++++++++++++ test/e2e/specs/callbacks.openapi.yaml | 41 ++++++++++++++++++ 6 files changed, 128 insertions(+), 11 deletions(-) create mode 100644 test/e2e/scenarios/oas3/callbacks.js create mode 100644 test/e2e/specs/callbacks.openapi.yaml diff --git a/src/core/components/operation.jsx b/src/core/components/operation.jsx index e47b19c5..f04c070e 100644 --- a/src/core/components/operation.jsx +++ b/src/core/components/operation.jsx @@ -156,7 +156,7 @@ export default class Operation extends PureComponent {
- { operation && operation.size ? null : + { (operation && operation.size) || operation === null ? null : } { deprecated &&

Warning: Deprecated

} diff --git a/src/core/containers/OperationContainer.jsx b/src/core/containers/OperationContainer.jsx index ac382553..8a2d1675 100644 --- a/src/core/containers/OperationContainer.jsx +++ b/src/core/containers/OperationContainer.jsx @@ -82,23 +82,23 @@ export default class OperationContainer extends PureComponent { } componentWillReceiveProps(nextProps) { - const { path, method, specActions, specSelectors, response, isShown } = nextProps - const resolvedSubtree = specSelectors.specResolvedSubtree(["paths", path, method]) + const { response, isShown } = nextProps + const resolvedSubtree = this.getResolvedSubtree() if(response !== this.props.response) { this.setState({ executeInProgress: false }) } if(isShown && resolvedSubtree === undefined) { - specActions.requestResolvedSubtree(["paths", path, method]) + this.requestResolvedSubtree() } } toggleShown =() => { - let { layoutActions, specActions, tag, operationId, path, method, isShown } = this.props + let { layoutActions, tag, operationId, isShown } = this.props if(!isShown) { // transitioning from collapsed to expanded - specActions.requestResolvedSubtree(["paths", path, method]) + this.requestResolvedSubtree() } layoutActions.show(["operations", tag, operationId], !isShown) } @@ -117,6 +117,37 @@ export default class OperationContainer extends PureComponent { this.setState({ executeInProgress: true }) } + getResolvedSubtree = () => { + const { + specSelectors, + path, + method, + specPath + } = this.props + + if(specPath) { + return specSelectors.specResolvedSubtree(specPath.toJS()) || Map() + } + + return specSelectors.specResolvedSubtree(["paths", path, method]) || Map() + } + + requestResolvedSubtree = () => { + const { + specActions, + path, + method, + specPath + } = this.props + + + if(specPath) { + return specActions.requestResolvedSubtree(specPath.toJS()) + } + + return specActions.requestResolvedSubtree(["paths", path, method]) + } + render() { let { op: unresolvedOp, @@ -151,7 +182,7 @@ export default class OperationContainer extends PureComponent { const Operation = getComponent( "operation" ) - const resolvedSubtree = specSelectors.specResolvedSubtree(["paths", path, method]) || Map() + const resolvedSubtree = this.getResolvedSubtree() const operationProps = fromJS({ op: resolvedSubtree || Map(), diff --git a/src/core/plugins/oas3/components/callbacks.jsx b/src/core/plugins/oas3/components/callbacks.jsx index 43437375..51d74f80 100644 --- a/src/core/plugins/oas3/components/callbacks.jsx +++ b/src/core/plugins/oas3/components/callbacks.jsx @@ -4,7 +4,7 @@ import ImPropTypes from "react-immutable-proptypes" import { fromJS } from "immutable" const Callbacks = (props) => { - let { callbacks, getComponent } = props + let { callbacks, getComponent, specPath } = props // const Markdown = getComponent("Markdown") const OperationContainer = getComponent("OperationContainer", true) @@ -28,6 +28,7 @@ const Callbacks = (props) => { tag={""} method={method} path={pathItemName} + specPath={specPath.push(callbackName, pathItemName, method)} allowTryItOut={false} /> }) } @@ -42,8 +43,8 @@ const Callbacks = (props) => { Callbacks.propTypes = { getComponent: PropTypes.func.isRequired, - callbacks: ImPropTypes.iterable.isRequired - + callbacks: ImPropTypes.iterable.isRequired, + specPath: ImPropTypes.list.isRequired, } export default Callbacks diff --git a/src/core/plugins/oas3/wrap-components/parameters.jsx b/src/core/plugins/oas3/wrap-components/parameters.jsx index 04671cfd..b1457086 100644 --- a/src/core/plugins/oas3/wrap-components/parameters.jsx +++ b/src/core/plugins/oas3/wrap-components/parameters.jsx @@ -161,7 +161,10 @@ class Parameters extends Component {
: "" } {this.state.callbackVisible ?
- +
: "" } { isOAS3() && requestBody && this.state.parametersVisible && diff --git a/test/e2e/scenarios/oas3/callbacks.js b/test/e2e/scenarios/oas3/callbacks.js new file mode 100644 index 00000000..4f06d3f0 --- /dev/null +++ b/test/e2e/scenarios/oas3/callbacks.js @@ -0,0 +1,41 @@ +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/callbacks.openapi.yaml") + .click("button.download-url-button") + .pause(1000) + + apiWrapper = mainPage.section.apiWrapper + + done() + }) + afterEach(function (client, done) { + done() + }) + describe("POST /pet", () => { + it("should render a callback correctly", function (client) { + apiWrapper.waitForElementVisible("#operations-pet-addPet", 10000) + // Expand the operation + .click("#operations-pet-addPet") + .waitForElementVisible("#operations-pet-addPet > div:nth-child(2) > div", 5000) + // Switch to Callbacks tab + .click("#operations-pet-addPet div.tab-header > div.tab-item.false > h4 > span") + .waitForElementVisible("#operations-pet-addPet div.callbacks-container", 5000) + .assert.containsText("#operations--post_request_body__url > div > span.opblock-summary-path", "$request.body#/url") + .click("#operations--post_request_body__url") + .waitForElementVisible("#operations--post_request_body__url div.response-col_description__inner > div > div > p", 5000) + .assert.containsText("#operations--post_request_body__url div.response-col_description__inner > div > div > p", "webhook successfully processed and no retries will be performed") + + + client.end() + }) + }) +}) diff --git a/test/e2e/specs/callbacks.openapi.yaml b/test/e2e/specs/callbacks.openapi.yaml new file mode 100644 index 00000000..7950d418 --- /dev/null +++ b/test/e2e/specs/callbacks.openapi.yaml @@ -0,0 +1,41 @@ +openapi: 3.0.0 +servers: +- url: http://petstore.swagger.io/v2 +info: + version: 1.0.0 + title: Swagger Petstore + termsOfService: http://swagger.io/terms/ + contact: + email: apiteam@swagger.io + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html +paths: + "/pet": + post: + tags: + - pet + summary: Add a new pet to the store + description: '' + operationId: addPet + parameters: [] + responses: + '405': + description: Invalid input + security: + - petstore_auth: + - write:pets + - read:pets + callbacks: + myWebhook: + '$request.body#/url': + post: + requestBody: + description: Callback payload + content: + 'application/json': + schema: + type: string + responses: + '200': + description: webhook successfully processed and no retries will be performed