Files
swagger-ui/test/e2e-cypress/helpers/multiple-examples.js
kyle 23d7260f92 feat: Multiple Examples for OpenAPI 3 Parameters, Request Bodies, and Responses (via #5427)
* add opt-in Prettier config

* remove legacy `examples` implementation

* create ExamplesSelect

* support `Response.examples` in OpenAPI 3

* create response controls group

* prettier reformat

* prepare to break up Parameters

* reunify Parameters and OAS3 Parameters

* Parameter Examples

* Example component

* handle parameter value stringification correctly

* FOR REVIEW: add prop for controlling Select

* use regular header for param examples in Try-It-Out

* manage active examples member via Redux

* Request Body Try-It-Out examples

* remove special Response description styling

* omit Example value display in Try-It-Out

* support disabled text inputs in JsonSchemaForm

* Example.omitValue => Example.showValue

* ExamplesSelectValueRetainer

* styling for disabled inputs

* remove console.log

* support "Modified Values" in ExamplesSelect

* remove Examples component
(wasn't used anywhere)

* use ParameterRow.getParamKey for active examples member keying

* split-rendering of examples in ParameterRow

* send disabled prop to JsonSchemaForm

* use content type to key request body active examples members

* remove debugger

* rewire RequestBodyEditor to be a controlled component

REVIEW: does this have perf implications?

* trigger synthetic onSelect events in ExamplesSelect

* prettier updates

* remove outdated Examples usage in RequestBody

* don't handle examples changes in ESVR

* make RequestBodyEditor semi-controlled

* don't default to an empty Map for request bodies

* add namespaceKey to ESVR for state mgmt

* don't key RequestBody activeExampleKeys on media type

* tweak ESVR isModifiedValueSelected calculation

* add trace class to ExamplesSelect

* remove usage of ESVR.currentNamespace

* reset to first example if currentExampleKey is invalid

* add default values to RequestBody rendering

* stringify things in ESVR

* avoid null select value (silences React warning)

* detect user inputs that match any examples member's value

* add trace class for json-schema-array

* shallowly convert namespace state, to preserve Immutable stucts in state

* stringify RBE values; don't trim JSON in editor

* match user input to an example when non-primitives are expressed in state as strings

* update Cypress

* don't apply sample values in JsonSchema_Object

* support disabling all JsonSchemaForm subcomponents

* Core tests

* style changes to accomodate Examples

* fix version-checking error in Response

* disable SCU for Responses

* don't stringify Select values

* ModelExample: default to Model tab if no example is available; provide a default no example message

* don't trim JSON ParamBody inputs

* read directly from 2.0 Response.schema instead of inferring a value

* show current Example information in RequestBody

* show label for Examples dropdown by default

* rework Response content ordering

* style disabled textareas like other read-only blocks

* meta: fix sourcemaps

* refactor ESVR setNameForNamespace

* protect second half of ternary expession

* cypress: `select.examples-select` => `.examples-select > select`

* clarify ModelExample.componentWillReceiveProps

* add gates/defaults to prevent issues in very bare-boned documents

* fix test block organization problem

* simplify RequestBodyEditor interface

* linter fixes

* prettier updates

* use plugin system for new components

* move ME Cypress helpers to other file
2019-06-29 19:52:51 +01:00

680 lines
24 KiB
JavaScript

module.exports = {
ParameterPrimitiveTestCases,
RequestBodyPrimitiveTestCases,
ResponsePrimitiveTestCases,
}
function ParameterPrimitiveTestCases({
operationDomId,
parameterName,
exampleA, // { value, key }
exampleB, // { value, key }
exampleC,
customUserInput,
customExpectedUrlSubstring,
}) {
it("should render examples options without Modified Value by default", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
.get(operationDomId)
.click()
.get(`tr[data-param-name="${parameterName}"]`)
.find(".examples-select option")
.should("have.length", exampleC ? 3 : 2)
// Ensure the relevant input is disabled
.get(
`tr[data-param-name="${parameterName}"] input, tr[data-param-name="${parameterName}"] textarea`
)
.should("have.attr", "disabled")
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
.get(`.opblock-section-request-body`)
.find(".examples-select option")
.should("have.length", exampleC ? 3 : 2)
})
it("should set default static and Try-It-Out values based on the first member", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Assert on the static docs value
.get(
`tr[data-param-name="${parameterName}"] input,tr[data-param-name="${parameterName}"] textarea`
)
.should("have.value", exampleA.value)
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Assert on the Try-It-Out value
.get(
`tr[data-param-name="${parameterName}"] input,tr[data-param-name="${parameterName}"] textarea`
)
.should("have.value", exampleA.value)
// Execute the operation
.get(".execute")
.click()
// Assert on the request URL
.get(".request-url")
.contains(
exampleA.serializedValue || `?message=${escape(exampleA.value)}`
)
})
it("should set static and Try-It-Out values based on the second member", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Choose the second example
.get("table.parameters .examples-select > select")
.select(exampleB.key)
// Assert on the static docs value
.get(
`tr[data-param-name="${parameterName}"] input,tr[data-param-name="${parameterName}"] textarea`
)
.should("have.value", exampleB.value)
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Assert on the Try-It-Out value
.get(
`tr[data-param-name="${parameterName}"] input,tr[data-param-name="${parameterName}"] textarea`
)
.should("have.value", exampleB.value)
// Execute the operation
.get(".execute")
.click()
// Assert on the request URL
.get(".request-url")
.contains(
exampleB.serializedValue
? `?${exampleB.serializedValue}`
: `?message=${escape(exampleB.value)}`
)
})
it("should handle user-entered values correctly", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Modify the input value
.get(
`tr[data-param-name="${parameterName}"] input,tr[data-param-name="${parameterName}"] textarea`
)
.clear()
.type(customUserInput)
// Assert on the active select menu item
.get("table.parameters .examples-select > select")
.find(":selected")
.should("have.text", "[Modified value]")
// Execute the operation
.get(".execute")
.click()
// Assert on the request URL
.get(".request-url")
.contains(
customExpectedUrlSubstring || `?message=${escape(customUserInput)}`
)
})
it("should retain user-entered values correctly", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Modify the input value
.get(
`tr[data-param-name="${parameterName}"] input,tr[data-param-name="${parameterName}"] textarea`
)
.clear()
.type(customUserInput)
// Select the first example
.get("table.parameters .examples-select > select")
.select(exampleA.key)
// Execute the operation
.get(".execute")
.click()
// Assert on the request URL
.get(".request-url")
.contains(
exampleA.serializedValue
? `?${exampleA.serializedValue}`
: `?message=${escape(exampleA.value)}`
)
// Select the modified value
.get("table.parameters .examples-select > select")
.select("__MODIFIED__VALUE__")
// Execute the operation
.get(".execute")
.click()
// Assert on the request URL
.get(".request-url")
.contains(
customExpectedUrlSubstring || `?message=${escape(customUserInput)}`
)
})
}
function RequestBodyPrimitiveTestCases({
operationDomId,
exampleA, // { value, key, summary }
exampleB, // { value, key, summary }
exampleC,
customUserInput,
customUserInputExpectedCurlSubstring,
primaryMediaType = "text/plain",
secondaryMediaType = "text/plain+other",
}) {
it("should render examples options without Modified Value by default", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
.get(operationDomId)
.click()
.get(`.opblock-section-request-body`)
.find(".examples-select option")
.should("have.length", exampleC ? 3 : 2)
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
.get(`.opblock-section-request-body`)
.find(".examples-select option")
.should("have.length", exampleC ? 3 : 2)
})
it("should set default static and Try-It-Out values based on the first member", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Assert on the static docs value
.get(`.opblock-section-request-body .microlight`)
.should("have.text", exampleA.value)
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Assert on the Try-It-Out value
.get(`.opblock-section-request-body textarea`)
.should("have.value", exampleA.value)
// Execute the operation
.get(".execute")
.click()
// Assert on the curl body
// TODO: use an interceptor instead of curl
.get(".curl")
.contains(`-d "${exampleA.serializedValue || exampleA.value}"`)
})
it("should set default static and Try-It-Out values based on choosing the second member in static mode", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Choose the second example
.get(".opblock-section-request-body .examples-select > select")
.select(exampleB.key)
// Assert on the static docs value
.get(`.opblock-section-request-body .microlight`)
.should("have.text", exampleB.value)
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Assert on the Try-It-Out value
.get(`.opblock-section-request-body textarea`)
.should("have.value", exampleB.value)
// Execute the operation
.get(".execute")
.click()
// Assert on the request URL
// TODO: use an interceptor instead of curl
.get(".curl")
.contains(`-d "${exampleB.serializedValue || exampleB.value}"`)
})
it("should set default static and Try-It-Out values based on choosing the second member in Try-It-Out mode", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Choose the second example
.get(".opblock-section-request-body .examples-select > select")
.select(exampleB.key)
// Assert on the Try-It-Out value
.get(`.opblock-section-request-body textarea`)
.should("have.value", exampleB.value)
// Execute the operation
.get(".execute")
.click()
// Assert on the request URL
// TODO: use an interceptor instead of curl
.get(".curl")
.contains(`-d "${exampleB.serializedValue || exampleB.value}"`)
// Switch to static docs
.get(".try-out__btn")
.click()
// Assert on the static docs value
.get(`.opblock-section-request-body .microlight`)
.should("have.text", exampleB.value)
})
it("should return the dropdown entry for an example when manually returning to its value", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Assert on the static docs value
.get(`.opblock-section-request-body .microlight`)
.should("have.text", exampleA.value)
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Assert on the Try-It-Out value
.get(`.opblock-section-request-body textarea`)
.should("have.value", exampleA.value)
// Clear the Try-It-Out value, replace it with custom value
.clear()
.type(customUserInput)
// Assert on the dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", "[Modified value]")
// Modify the value again, going back to the example value
.get(`.opblock-section-request-body textarea`)
.clear()
.type(exampleA.value)
// Assert on the dropdown value returning to the example value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleA.summary)
})
it("should retain choosing a member in static docs when changing the media type", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Choose the second example
.get(".opblock-section-request-body .examples-select > select")
.select(exampleB.key)
// Change the media type
.get(".opblock-section-request-body .content-type")
.select(secondaryMediaType)
// Assert on the static docs value
.get(`.opblock-section-request-body .microlight`)
.should("have.text", exampleB.value)
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Assert on the Try-It-Out value
.get(`.opblock-section-request-body textarea`)
.should("have.value", exampleB.value)
// Execute the operation
.get(".execute")
.click()
// Assert on the request URL
// TODO: use an interceptor instead of curl
.get(".curl")
.contains(`-d "${exampleB.serializedValue || exampleB.value}"`)
})
it("should use the first example for the media type when changing the media type without prior interactions with the value", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Change the media type
.get(".opblock-section-request-body .content-type")
.select(secondaryMediaType)
// Assert on the static docs value
.get(`.opblock-section-request-body .microlight`)
.should("have.text", exampleA.value)
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Assert on the Try-It-Out value
.get(`.opblock-section-request-body textarea`)
.should("have.value", exampleA.value)
// Execute the operation
.get(".execute")
.click()
// Assert on the request URL
// TODO: use an interceptor instead of curl
.get(".curl")
.contains(`-d "${exampleA.serializedValue || exampleA.value}"`)
})
it("static mode toggling: mediaType -> example -> mediaType -> example", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Change the media type
.get(".opblock-section-request-body .content-type")
.select(secondaryMediaType)
// Assert on the static docs value
.get(`.opblock-section-request-body .microlight`)
.should("have.text", exampleA.value)
// Assert on the dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleA.summary)
// Choose exampleB
.get(".opblock-section-request-body .examples-select > select")
.select(exampleB.key)
// Assert on the static docs value
.get(`.opblock-section-request-body .microlight`)
.should("have.text", exampleB.value)
// Assert on the dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleB.summary)
// Change the media type
.get(".opblock-section-request-body .content-type")
.select(primaryMediaType)
// Assert that the static docs value didn't change
.get(`.opblock-section-request-body .microlight`)
.should("have.text", exampleB.value)
// Assert that the dropdown value didn't change
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleB.summary)
// Choose exampleA
.get(".opblock-section-request-body .examples-select > select")
.select(exampleA.key)
// Assert on the static docs value
.get(`.opblock-section-request-body .microlight`)
.should("have.text", exampleA.value)
// Assert on the dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleA.summary)
})
it("Try-It-Out toggling: mediaType -> example -> mediaType -> example", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Change the media type
.get(".opblock-section-request-body .content-type")
.select(secondaryMediaType)
// Assert on the static docs value
.get(`.opblock-section-request-body textarea`)
.should("have.text", exampleA.value)
// Assert on the dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleA.summary)
// Choose exampleB
.get(".opblock-section-request-body .examples-select > select")
.select(exampleB.key)
// Assert on the static docs value
.get(`.opblock-section-request-body textarea`)
.should("have.text", exampleB.value)
// Assert on the dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleB.summary)
// Change the media type
.get(".opblock-section-request-body .content-type")
.select(primaryMediaType)
// Assert that the static docs value didn't change
.get(`.opblock-section-request-body textarea`)
.should("have.text", exampleB.value)
// Assert that the dropdown value didn't change
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleB.summary)
// Choose exampleA
.get(".opblock-section-request-body .examples-select > select")
.select(exampleA.key)
// Assert on the static docs value
.get(`.opblock-section-request-body textarea`)
.should("have.text", exampleA.value)
// Assert on the dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleA.summary)
})
it("Try-It-Out toggling and execution with modified values: mediaType -> modified value -> example -> mediaType -> example", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get(operationDomId)
.click()
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Change the media type
.get(".opblock-section-request-body .content-type")
.select(secondaryMediaType)
// Assert on the static docs value
.get(`.opblock-section-request-body textarea`)
.should("have.text", exampleA.value)
// Assert on the dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleA.summary)
// Modify the value
.get(`.opblock-section-request-body textarea`)
.clear()
.type(customUserInput)
// Assert on the dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", "[Modified value]")
// Fire the operation
.get(".execute")
.click()
// Assert on the curl body
// TODO: use an interceptor instead of curl
.get(".curl")
.contains(
`-d "${customUserInputExpectedCurlSubstring || customUserInput}"`
)
// Choose exampleB
.get(".opblock-section-request-body .examples-select > select")
.select(exampleB.key)
// Assert on the static docs value
.get(`.opblock-section-request-body textarea`)
.should("have.text", exampleB.value)
// Assert on the dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleB.summary)
// Fire the operation
.get(".execute")
.click()
// Assert on the curl body
// TODO: use an interceptor instead of curl
.get(".curl")
.contains(`-d "${exampleB.serializedValue || exampleB.value}"`)
// Ensure the modified value is still accessible
.get(".opblock-section-request-body .examples-select > select")
.contains("[Modified value]")
// Change the media type to text/plain
.get(".opblock-section-request-body .content-type")
.select(primaryMediaType)
// Assert that the static docs value didn't change
.get(`.opblock-section-request-body textarea`)
.should("have.text", exampleB.value)
// Assert that the dropdown value didn't change
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleB.summary)
// Fire the operation
.get(".execute")
.click()
// Assert on the curl body
// TODO: use an interceptor instead of curl
.get(".curl")
.contains(`-d "${exampleB.serializedValue || exampleB.value}"`)
// Ensure the modified value is still accessible
.get(".opblock-section-request-body .examples-select > select")
.contains("[Modified value]")
// Choose exampleA
.get(".opblock-section-request-body .examples-select > select")
.select(exampleA.key)
// Assert on the static docs value
.get(`.opblock-section-request-body textarea`)
.should("have.text", exampleA.value)
// Assert on the dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", exampleA.summary)
// Fire the operation
.get(".execute")
.click()
// Assert on the curl body
// TODO: use an interceptor instead of curl
.get(".curl")
.contains(`-d "${exampleA.serializedValue || exampleA.value}"`)
// Ensure the modified value is still the same value
.get(".opblock-section-request-body .examples-select > select")
.select("__MODIFIED__VALUE__")
// Assert on the static docs value
.get(`.opblock-section-request-body textarea`)
.should("have.text", customUserInput.replace(/{{}/g, "{"))
// Assert on the dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", "[Modified value]")
// Fire the operation
.get(".execute")
.click()
// Assert on the curl body
// TODO: use an interceptor instead of curl
.get(".curl")
.contains(
`-d "${customUserInputExpectedCurlSubstring || customUserInput}"`
)
})
// TODO: Try-It-Out + Try-It-Out media type changes
}
function ResponsePrimitiveTestCases({
operationDomId,
exampleA, // { value, key, summary }
exampleB, // { value, key, summary }
exampleC, // { value, key, summary }
}) {
it("should render the first example by default", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
.get(operationDomId)
.click()
.get(".responses-wrapper")
.within(() => {
cy.get(".examples-select > select")
.find(":selected")
.should("have.text", exampleA.summary)
.get(".microlight")
.should("have.text", exampleA.value)
})
})
it("should render the second example", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
.get(operationDomId)
.click()
.get(".responses-wrapper")
.within(() => {
cy.get(".examples-select > select")
.select(exampleB.key)
.find(":selected")
.should("have.text", exampleB.summary)
.get(".microlight")
.should("have.text", exampleB.value)
})
})
it("should retain an example choice across media types if they share the same example", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
.get(operationDomId)
.click()
.get(".responses-wrapper")
.within(() => {
cy
// Change examples
.get(".examples-select > select")
.select(exampleB.key)
// Assert against dropdown value
.find(":selected")
.should("have.text", exampleB.summary)
// Assert against example value
.get(".microlight")
.should("have.text", exampleB.value)
// Change media types
.get(".content-type")
.select("text/plain+other")
// Assert against dropdown value
.get(".examples-select > select")
.find(":selected")
.should("have.text", exampleB.summary)
// Assert against example value
.get(".microlight")
.should("have.text", exampleB.value)
})
})
;(exampleC ? it : it.skip)(
"should reset to the first example if the new media type lacks the current example",
() => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
.get(operationDomId)
.click()
.get(".responses-wrapper")
.within(() => {
cy
// Change media types
.get(".content-type")
.select("text/plain+other")
// Change examples
.get(".examples-select > select")
.select(exampleC.key)
// Assert against dropdown value
.find(":selected")
.should("have.text", exampleC.summary || exampleC.key)
// Assert against example value
.get(".microlight")
.should("have.text", exampleC.value)
// Change media types
.get(".content-type")
.select("text/plain")
// Assert against dropdown value
.get(".examples-select > select")
.find(":selected")
.should("have.text", exampleA.summary)
// Assert against example value
.get(".microlight")
.should("have.text", exampleA.value)
})
}
)
}