Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/core/components/param-body.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,40 @@ export default class ParamBody extends PureComponent {
this.setState({ value: val })
this.onChange(val, {isXml: isXml, isEditBox: isExecute})
} else {
if (isXml) {
let xExampleValue = this.xExampleValue()
if (xExampleValue !== undefined) {
this.onChange(xExampleValue, {isXml: isXml, isEditBox: isExecute})
} else if (isXml) {
this.onChange(this.sample("xml"), {isXml: isXml, isEditBox: isExecute})
} else {
this.onChange(this.sample(), {isEditBox: isExecute})
}
}
}

xExampleValue = () => {
const { param } = this.props
const xExamples = param.get("x-examples")
if (!xExamples || typeof xExamples.get !== "function" || xExamples.size === 0) {
return undefined
}
const defaultExample = xExamples.get("default")
const example = defaultExample !== undefined ? defaultExample : xExamples.first()
if (example === undefined) {
return undefined
}
if (typeof example === "string") {
return example
}
if (typeof example.toJS === "function") {
return JSON.stringify(example.toJS(), null, 2)
}
if (typeof example === "object") {
return JSON.stringify(example, null, 2)
}
return String(example)
}

sample = (xml) => {
let { param, fn} = this.props
let schema = fn.inferSchema(param.toJS())
Expand Down
25 changes: 25 additions & 0 deletions test/e2e-cypress/e2e/bugs/3233.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
describe("#3233: x-examples should populate the body parameter example for OAS 2.0", () => {
it("renders the x-examples 'default' value as the request body example", () => {
cy.visit("?url=/documents/bugs/3233.yaml")
.get("#operations-default-dataTargets")
.click()
.get(".opblock-section")
.within(() => {
cy.get(".body-param__example")
.should("be.visible")
.should("include.text", "targets")
.should("include.text", "1")
.should("include.text", "4")
})
})

it("populates the request body textarea with x-examples when 'Try it out' is enabled", () => {
cy.visit("?url=/documents/bugs/3233.yaml")
.get("#operations-default-dataTargets")
.click()
.get(".try-out__btn")
.click()
.get("textarea.body-param__text")
.should("contain.value", "targets")
})
})
28 changes: 28 additions & 0 deletions test/e2e-cypress/static/documents/bugs/3233.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
swagger: "2.0"
info:
description: "OAS 2.0 sample with x-examples in body parameter (issue #3233)"
version: "0.0.1"
title: "Swagger Sample"
paths:
/data/targets:
post:
summary: "Returns validation results of given list of targets."
description: ""
operationId: "dataTargets"
consumes:
- application/json
produces:
- application/json
parameters:
- in: body
name: body
description: Targets list in JSON format.
required: true
schema:
type: object
x-examples:
default:
targets: [1, 2, 3, 4]
responses:
"200":
description: OK
150 changes: 150 additions & 0 deletions test/unit/components/param-body.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import React from "react"
import expect from "expect"
import { mount } from "enzyme"
import { fromJS } from "immutable"
import ParamBody from "core/components/param-body"

describe("<ParamBody/>", () => {
const baseFn = {
inferSchema: () => ({}),
getSampleSchema: () => "GENERATED_SAMPLE",
}

const baseSpecSelectors = {
parameterWithMetaByIdentity: (pathMethod, param) => param,
contentTypeValues: () => fromJS({ requestContentType: "application/json" }),
}

const fakeGetComponent = () => () => null

const createProps = (overrides = {}) => ({
fn: baseFn,
getComponent: fakeGetComponent,
specSelectors: baseSpecSelectors,
pathMethod: ["/foo", "post"],
consumes: fromJS(["application/json"]),
consumesValue: "application/json",
isExecute: false,
onChange: jest.fn(),
onChangeConsumes: jest.fn(),
...overrides,
})

it("emits the user-provided value when one is set", () => {
const onChange = jest.fn()
const props = createProps({
param: fromJS({
name: "body",
in: "body",
value: "{\"hello\":\"world\"}",
}),
onChange,
})

mount(<ParamBody {...props} />)

expect(onChange).toHaveBeenCalledWith("{\"hello\":\"world\"}", false)
})

it("emits the generated sample when no value and no x-examples are present", () => {
const onChange = jest.fn()
const props = createProps({
param: fromJS({
name: "body",
in: "body",
schema: { type: "string" },
}),
onChange,
})

mount(<ParamBody {...props} />)

expect(onChange).toHaveBeenCalledWith("GENERATED_SAMPLE", undefined)
})

it("prefers the x-examples 'default' value over the generated sample", () => {
const onChange = jest.fn()
const props = createProps({
param: fromJS({
name: "body",
in: "body",
schema: { type: "object" },
"x-examples": {
default: { targets: [1, 2, 3, 4] },
},
}),
onChange,
})

mount(<ParamBody {...props} />)

expect(onChange).toHaveBeenCalledTimes(1)
expect(onChange).toHaveBeenCalledWith(
JSON.stringify({ targets: [1, 2, 3, 4] }, null, 2),
false
)
})

it("falls back to the first x-examples entry when 'default' is missing", () => {
const onChange = jest.fn()
const props = createProps({
param: fromJS({
name: "body",
in: "body",
schema: { type: "object" },
"x-examples": {
first: { foo: "bar" },
second: { baz: "qux" },
},
}),
onChange,
})

mount(<ParamBody {...props} />)

expect(onChange).toHaveBeenCalledTimes(1)
expect(onChange).toHaveBeenCalledWith(
JSON.stringify({ foo: "bar" }, null, 2),
false
)
})

it("uses string x-examples values verbatim", () => {
const onChange = jest.fn()
const props = createProps({
param: fromJS({
name: "body",
in: "body",
schema: { type: "string" },
"x-examples": {
default: "{\"targets\": \"[1, 2, 3, 4]\"}",
},
}),
onChange,
})

mount(<ParamBody {...props} />)

expect(onChange).toHaveBeenCalledWith(
"{\"targets\": \"[1, 2, 3, 4]\"}",
false
)
})

it("ignores empty x-examples and falls back to the generated sample", () => {
const onChange = jest.fn()
const props = createProps({
param: fromJS({
name: "body",
in: "body",
schema: { type: "object" },
"x-examples": {},
}),
onChange,
})

mount(<ParamBody {...props} />)

expect(onChange).toHaveBeenCalledWith("GENERATED_SAMPLE", undefined)
})
})