This commit is contained in:
2024-05-24 15:27:07 +03:00
parent 17df2ce6a9
commit fc1da2c238
643 changed files with 110185 additions and 231 deletions

View File

@ -0,0 +1,35 @@
describe("Response tab elements", () => {
describe("ModelExample within Operation", () => {
it("should render Example tabpanel by default", () => {
cy
.visit("/?url=/documents/petstore-expanded.openapi.yaml")
.get("#operations-default-addPet")
.click()
.get("div[data-name=examplePanel]")
.first()
.should("have.attr", "aria-hidden", "false")
})
it("should click Schema tab button and render Schema tabpanel for OpenAPI 3", () => {
cy
.visit("/?url=/documents/petstore-expanded.openapi.yaml")
.get("#operations-default-addPet")
.click()
.get("button.tablinks[data-name=model]")
.first()
.click()
.get("div[data-name=modelPanel]")
.first()
.should("have.attr", "aria-hidden", "false")
})
it("should click Model tab button and render Model tabpanel for OpenAPI 2", () => {
cy
.visit("/?url=/documents/petstore.swagger.yaml")
.get("#operations-pet-addPet")
.click()
.get("button.tablinks[data-name=model]")
.click()
.get("div[data-name=modelPanel]")
.should("have.attr", "aria-hidden", "false")
})
})
})

View File

@ -0,0 +1,37 @@
/**
* @prettier
*/
describe("UI #4442: Parameter.content display and execution", function() {
it("should display textareas as static documentation according to the `example`", () => {
cy.visit("/?url=/documents/bugs/4442.yaml")
.get(`#operations-default-get_`)
.click()
.get(".btn.try-out__btn")
.click()
.get(
`div.json-schema-array > div:nth-child(1) > div > textarea`
)
.should("have.value", `{\n "userId": 1,\n "currency": "USD"\n}`)
.get(
`div.json-schema-array > div:nth-child(2) > div > textarea`
)
.should("have.value", `{\n "userId": 2,\n "currency": "CAD"\n}`)
})
it("should serialize JSON into a query correctly", () => {
cy.visit("/?url=/documents/bugs/4442.yaml")
.get(`#operations-default-get_`)
.click()
.get(".btn.try-out__btn")
.click()
.get(".btn.execute")
.click()
.get(".request-url pre")
.should(
"have.text",
`http://localhost:3230/?users=${encodeURIComponent(
`[{"userId":1,"currency":"USD"},{"userId":2,"currency":"CAD"}]`
)}`
)
})
})

View File

@ -0,0 +1,99 @@
const clickTryItOutAndExecute = () => {
return cy
.get(".btn.try-out__btn") // expand "try it out"
.click()
.get(".btn.execute") // execute request
.click()
}
const fillInApiKeyAndAuthorise = apiKey => () => {
return cy
.get("section>input") // type api key into input
.type(apiKey)
.get(".auth-btn-wrapper > .authorize") // authorise button
.click()
}
const clickLogoutAndReauthorise = () => {
return cy
.get(".auth-btn-wrapper button:nth-child(1)") // logout button
.click()
.get(".auth-btn-wrapper > .authorize") // authorise button
.click()
}
describe("#4641: The Logout button in Authorize popup not clearing API Key", () => {
beforeEach(() => {
cy.server()
cy
.route({
url: "/4641*",
response: "OK",
})
.as("request")
})
it("should include the given api key in requests", () => {
cy
.visit("/?url=/documents/bugs/4641.yaml")
.get("button.btn.authorize") // open authorize popup
.click()
.get(".modal-ux-content > :nth-child(1)") // only deal with api_key_1 for this test
.within(fillInApiKeyAndAuthorise("my_api_key"))
.get(".close-modal") // close authorise popup button
.click()
.get("#operations-default-get_4641_1") // expand the route details onClick
.click()
.within(clickTryItOutAndExecute)
.wait("@request")
.its("request")
.then((req) => {
expect(req.headers, "request headers").to.have.property("api_key_1", "my_api_key")
})
})
it("should not remember the previous auth value when you logout and reauthorise", () => {
cy
.visit("/?url=/documents/bugs/4641.yaml")
.get("button.btn.authorize") // open authorize popup
.click()
.get(".modal-ux-content > :nth-child(1)") // only deal with api_key_1 for this test
.within(fillInApiKeyAndAuthorise("my_api_key"))
.get(".modal-ux-content > :nth-child(1)") // only deal with api_key_1 for this test
.within(clickLogoutAndReauthorise)
.get(".close-modal") // close authorise popup button
.click()
.get("#operations-default-get_4641_1") // expand the route details onClick
.click()
.within(clickTryItOutAndExecute)
.wait("@request")
.its("request")
.then((req) => {
expect(req.headers, "request headers").not.to.have.property("api_key_1")
})
})
it("should only forget the value of the auth the user logged out from", () => {
cy
.visit("/?url=/documents/bugs/4641.yaml")
.get("button.btn.authorize") // open authorize popup
.click()
.get(".modal-ux-content > :nth-child(1)") // deal with api_key_1
.within(fillInApiKeyAndAuthorise("my_api_key"))
.get(".modal-ux-content > :nth-child(2)") // deal with api_key_2
.within(fillInApiKeyAndAuthorise("my_second_api_key"))
.get(".modal-ux-content > :nth-child(1)") // deal with api_key_1 again
.within(clickLogoutAndReauthorise)
.get(".close-modal") // close authorise popup button
.click()
.get("#operations-default-get_4641_2") // expand the route details onClick
.click()
.within(clickTryItOutAndExecute)
.wait("@request")
.its("request")
.then((req) => {
expect(req.headers, "request headers").not.to.have.property("api_key_1")
expect(req.headers, "request headers").to.have.property("api_key_2", "my_second_api_key")
})
})
})

View File

@ -0,0 +1,11 @@
import repeat from "lodash/repeat"
describe("#4838: empty request bodies result in endless loading", () => {
it("should render model content changes correctly", () => {
cy
.visit("/?url=/documents/bugs/4838.yaml")
.get("#operations-Some-post_some_route")
.click()
.contains("This should be visible")
})
})

View File

@ -0,0 +1,19 @@
describe("#4865: multiple invocations + OAS3 plugin", () => {
it("control: should render the OAS3 badge correctly", () => {
// This is a sanity check to make sure the badge is present.
// If this is failing, it's probably not related to #4865.
cy.visit("/?url=/documents/petstore-expanded.openapi.yaml")
.get("#swagger-ui")
.get("pre.version")
.contains("OAS3")
})
it("test: should render the OAS3 badge correctly after re-initializing the UI", () => {
cy.visit("/?url=/documents/petstore-expanded.openapi.yaml")
.window()
.then(win => win.onload()) // re-initializes Swagger UI
.get("#swagger-ui")
.get("pre.version")
.contains("OAS3")
})
})

View File

@ -0,0 +1,17 @@
describe("#4867: callback parameter rendering", () => {
it("should render parameters correctly", () => {
cy
.visit("/?url=/documents/bugs/4867.yaml")
.get("#operations-default-myOp")
.click()
.contains("Callbacks")
.click()
.get(".callbacks-container .opblock-summary-path")
.should("have.attr", "data-path", "http://$request.query.url")
.click()
.get(".parameters-container")
.contains("myParam")
})
})

View File

@ -0,0 +1,20 @@
describe("#4943: XML example not rendered correctly with oneOf", () => {
it("should render integer property correctly", () => {
cy
.visit("/?url=/documents/bugs/4943.yaml")
.get("#operations-Test-postTest")
.click()
.get(".microlight")
.contains("<b>0</b>")
})
it("should render oneOf property correctly", () => {
cy
.visit("/?url=/documents/bugs/4943.yaml")
.get("#operations-Test-postTest")
.click()
.get(".try-out__btn")
.click()
.get(".microlight")
.contains("<c>\n\t</c>")
})
})

View File

@ -0,0 +1,30 @@
describe("#5043: path-level $ref path items should inherit global consumes/produces", () => {
it("should render consumes options correctly", () => {
cy
.visit("/?url=/documents/bugs/5043/swagger.yaml")
.get("#operations-pet-findPetsByStatus")
.click()
.get(".try-out__btn")
.click()
.get(".content-type")
.contains("application/json")
.get(".content-type")
.contains("application/xml")
.get(".content-type")
.contains("text/csv")
})
it("should render produces options correctly", () => {
cy
.visit("/?url=/documents/bugs/5043/swagger.yaml")
.get("#operations-pet-findPetsByStatus")
.click()
.get(".try-out__btn")
.click()
.get(".body-param-content-type select")
.contains("application/json")
.get(".body-param-content-type select")
.contains("application/xml")
.get(".body-param-content-type select")
.contains("text/csv")
})
})

View File

@ -0,0 +1,15 @@
describe("#5060: unwanted smart quotes in rendered Markdown", () => {
it("should not convert regular quotes to smart quotes", () => {
cy
.visit("/?url=/documents/bugs/5060.yaml")
.get("div.description")
.should($el => {
const text = $el.get(0).textContent
expect(text).to.include(`Example of a simple GET request via curl with bearer HTTP Authentication`)
expect(text).to.include(`curl -X GET "https://foobar.com/stuff"`)
expect(text).to.include(`-H "Accept: application/json"`)
expect(text).to.include(`-H "Authorization: Bearer abc123.xyz.789"`)
expect(text.indexOf(``)).to.equal(-1)
})
})
})

View File

@ -0,0 +1,32 @@
describe("#5070: Required field not highlighted on click of Execute button (second time)", () => {
it("should not clear error class=invalid on input field (Swagger)", () => {
cy
.visit("/?url=/documents/petstore.swagger.yaml")
.get("#operations-pet-getPetById")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Execute without user input
.get(".execute.opblock-control__btn")
.click()
.get(".parameters-col_description input")
.should($el => {
expect($el).to.have.length(1)
const className = $el[0].className
expect(className).to.match(/invalid/i)
})
// Cancel Try It Out
.get(".cancel")
.click()
// Expand Try It Out (Again)
.get(".try-out__btn")
.click()
.get(".parameters-col_description input")
.should($el => {
expect($el).to.have.length(1)
const className = $el[0].className
expect(className).to.match(/invalid/i)
})
})
})

View File

@ -0,0 +1,22 @@
describe("#5072: x-www-form-urlencoded request body input when `properties` is missing", () => {
it("should provide a JSON input for an empty object schema", () => {
cy
.visit("?url=/documents/bugs/5072/empty.yaml")
.get("#operations-default-postObject")
.click()
.get(".try-out__btn")
.click()
.get(`.opblock-section-request-body textarea`)
.should("have.value", "{}")
})
it("should provide a JSON input for an additionalProperties object schema", () => {
cy
.visit("?url=/documents/bugs/5072/additional.yaml")
.get("#operations-default-postObject")
.click()
.get(".try-out__btn")
.click()
.get(`.opblock-section-request-body textarea`)
.contains(`"additionalProp1": "string"`)
})
})

View File

@ -0,0 +1,121 @@
describe("#5129: parameter required + allowEmptyValue interactions", () => {
describe("allowEmptyValue parameter", () => {
const opId = "#operations-default-get_aev"
it("should omit the parameter by default", () => {
cy
.visit("/?url=/documents/bugs/5129.yaml")
.get(opId)
.click()
.get(".btn.try-out__btn")
.click()
.get(".btn.execute")
.click()
.get(".request-url pre")
.should("have.text", "http://localhost:3230/aev")
})
it("should include a value", () => {
cy
.visit("/?url=/documents/bugs/5129.yaml")
.get(opId)
.click()
.get(".btn.try-out__btn")
.click()
.get(`.parameters-col_description input[type=text]`)
.type("asdf")
.get(".btn.execute")
.click()
.get(".request-url pre")
.should("have.text", "http://localhost:3230/aev?param=asdf")
})
it("should include an empty value when empty value box is checked", () => {
cy
.visit("/?url=/documents/bugs/5129.yaml")
.get(opId)
.click()
.get(".btn.try-out__btn")
.click()
.get(`.parameters-col_description input[type=checkbox]`)
.check()
.get(".btn.execute")
.click()
.get(".request-url pre")
.should("have.text", "http://localhost:3230/aev?param=")
})
it("should include a value when empty value box is checked and then input is provided", () => {
cy
.visit("/?url=/documents/bugs/5129.yaml")
.get(opId)
.click()
.get(".btn.try-out__btn")
.click()
.get(`.parameters-col_description input[type=checkbox]`)
.check()
.get(`.parameters-col_description input[type=text]`)
.type("1234")
.get(".btn.execute")
.click()
.get(".request-url pre")
.should("have.text", "http://localhost:3230/aev?param=1234")
})
})
describe("allowEmptyValue + required parameter", () => {
const opId = "#operations-default-get_aev_and_required"
it("should refuse to execute by default", () => {
cy
.visit("/?url=/documents/bugs/5129.yaml")
.get(opId)
.click()
.get(".btn.try-out__btn")
.click()
.get(".btn.execute")
.click()
.wait(1000)
.get(".request-url pre")
.should("not.exist")
})
it("should include a value", () => {
cy
.visit("/?url=/documents/bugs/5129.yaml")
.get(opId)
.click()
.get(".btn.try-out__btn")
.click()
.get(`.parameters-col_description input[type=text]`)
.type("asdf")
.get(".btn.execute")
.click()
.get(".request-url pre")
.should("have.text", "http://localhost:3230/aev/and/required?param=asdf")
})
it("should include an empty value when empty value box is checked", () => {
cy
.visit("/?url=/documents/bugs/5129.yaml")
.get(opId)
.click()
.get(".btn.try-out__btn")
.click()
.get(`.parameters-col_description input[type=checkbox]`)
.check()
.get(".btn.execute")
.click()
.get(".request-url pre")
.should("have.text", "http://localhost:3230/aev/and/required?param=")
})
it("should include a value when empty value box is checked and then input is provided", () => {
cy
.visit("/?url=/documents/bugs/5129.yaml")
.get(opId)
.click()
.get(".btn.try-out__btn")
.click()
.get(`.parameters-col_description input[type=checkbox]`)
.check()
.get(`.parameters-col_description input[type=text]`)
.type("1234")
.get(".btn.execute")
.click()
.get(".request-url pre")
.should("have.text", "http://localhost:3230/aev/and/required?param=1234")
})
})
})

View File

@ -0,0 +1,10 @@
describe("#5138: unwanted `url`/`urls` interactions", () => {
it("should stably render the first `urls` entry", () => {
cy
.visit("/pages/5138/")
.get("h2.title")
.contains("USPTO Data Set API")
.wait(3000)
.contains("USPTO Data Set API")
})
})

View File

@ -0,0 +1,19 @@
describe("#5164: multipart property initial values", () => {
it("should provide correct initial values for objects and arrays", () => {
const correctObjectValue = JSON.stringify({
"one": "abc",
"two": 123
}, null, 2)
cy
.visit("?url=/documents/bugs/5164.yaml")
.get("#operations-default-post_")
.click()
.get(".try-out__btn")
.click()
.get(`.parameters[data-property-name="first"] textarea`)
.should("have.value", correctObjectValue)
.get(`.parameters[data-property-name="second"] input`)
.should("have.value", "hi")
})
})

View File

@ -0,0 +1,18 @@
describe("#5188: non-string operation summary value", () => {
it("should gracefully handle an object value for an operation summary", () => {
cy
.visit("?url=/documents/bugs/5188.yaml")
.get("#operations-default-objectSummary")
.click()
.get(".opblock-summary-description")
.contains("[object Object]")
})
it("should gracefully handle a missing value for an operation summary", () => {
cy
.visit("?url=/documents/bugs/5188.yaml")
.get("#operations-default-noSummary")
.click()
// check for response rendering; makes sure the Operation itself rendered
.contains("Invalid input")
})
})

View File

@ -0,0 +1,38 @@
/**
* @prettier
*/
describe("#5452: <Select /> crashing in Parameters", function() {
describe("in OpenAPI 3", () => {
it("should not result in a render error", function() {
cy.visit("http://localhost:3230/?url=/documents/bugs/5452/openapi.yaml")
.get("#operations-default-get_endpoint")
.click()
.get(".try-out__btn")
.click()
.get(".parameters > tbody > tr > .parameters-col_description > select")
.select("")
.get(".parameters > tbody > tr > .parameters-col_description > select")
.should("exist")
.select("fruit")
.get(".parameters > tbody > tr > .parameters-col_description > select")
.should("exist")
})
})
describe("in Swagger 2", () => {
it("should not result in a render error", function() {
cy.visit("http://localhost:3230/?url=/documents/bugs/5452/swagger.yaml")
.get("#operations-default-get_endpoint")
.click()
.get(".try-out__btn")
.click()
.get(".parameters > tbody > tr > .parameters-col_description > select")
.select("")
.get(".parameters > tbody > tr > .parameters-col_description > select")
.should("exist")
.select("fruit")
.get(".parameters > tbody > tr > .parameters-col_description > select")
.should("exist")
})
})
})

View File

@ -0,0 +1,11 @@
// http://github.com/swagger-api/swagger-ui/issues/5453
describe("#5453: Responses w/o `content` should not render ModelExample", () => {
it("should not render a ModelExample section", () => {
cy.visit("/?url=/documents/bugs/5453.yaml")
.get("#operations-default-get_foo")
.click()
.get(".responses-inner")
.should("not.have.descendants", ".model-example")
})
})

View File

@ -0,0 +1,11 @@
// http://github.com/swagger-api/swagger-ui/issues/5455
describe("#5455: Request bodies w/o `examples` should not render a dropdown", () => {
it("should not render a <select> element", () => {
cy.visit("/?url=/documents/bugs/5455.yaml")
.get("#operations-default-post_foo")
.click()
.get(".opblock-section-request-body > .opblock-description-wrapper")
.should("not.have.descendants", "select")
})
})

View File

@ -0,0 +1,22 @@
// http://github.com/swagger-api/swagger-ui/issues/5458
const expectedValue = `{
"foo": "custom value"
}`
describe("#5458: Swagger 2.0 `Response.examples` mappings", () => {
it("should render a custom example when a schema is not defined", () => {
cy.visit("/?url=/documents/bugs/5458.yaml")
.get("#operations-default-get_foo1")
.click()
.get(".model-example .highlight-code")
.contains(expectedValue)
})
it("should render a custom example when a schema is defined", () => {
cy.visit("/?url=/documents/bugs/5458.yaml")
.get("#operations-default-get_foo2")
.click()
.get(".model-example .highlight-code")
.contains(expectedValue)
})
})

View File

@ -0,0 +1,20 @@
// http://github.com/swagger-api/swagger-ui/issues/5660
const expectedValue = "nullable: true"
describe("#5660: Nullable object", () => {
it("should render `nullable` marker for object itself", () => {
cy.visit("/?url=/documents/bugs/5660-model.yaml")
.get("#model-SomeObject .model-toggle")
.click()
.get("#model-SomeObject > .model-box")
.contains(expectedValue)
})
it("should render `nullable` marker for next object in property", () => {
cy.visit("/?url=/documents/bugs/5660-property.yaml")
.get("#model-SomeObject .model-toggle")
.click()
.get("#model-SomeObject > .model-box")
.contains(expectedValue)
})
})

View File

@ -0,0 +1,42 @@
describe("Entries should be valid property name", () => {
it("should render a OAS3.0 definition that uses 'entries' as a 'components' property name", () => {
cy.visit("/?url=/documents/bugs/6016-oas3.yaml")
.get("#operations-tag-default")
.should("exist")
})
it("should render expanded Operations of OAS3.0 definition that uses 'entries' as a 'components' property name", () => {
cy.visit("/?url=/documents/bugs/6016-oas3.yaml")
.get("#operations-default-test_test__get")
.click()
.get("#operations-default-test_test__get > div .opblock-body")
.should("exist")
})
it("should render expanded Models of OAS3.0 definition that uses 'entries' as a 'components' property name", () => {
cy.visit("/?url=/documents/bugs/6016-oas3.yaml")
.get("#model-Testmodel > span .model-box")
.click()
.get("div .model-box")
.should("exist")
})
it("should render a OAS2.0 definition that uses 'entries' as a 'definitions' property name", () => {
cy.visit("/?url=/documents/bugs/6016-oas2.yaml")
.get("#operations-default-post_pet")
.should("exist")
})
it("should render expanded Operations of OAS2.0 definition that uses 'entries' as a 'definitions' property name", () => {
cy.visit("/?url=/documents/bugs/6016-oas2.yaml")
.get("#operations-default-post_pet")
.click()
.get("#operations-default-post_pet > div .opblock-body")
.should("exist")
})
it("should render expanded Models of OAS2.0 definition that uses 'entries' as a 'defintions' property name", () => {
cy.visit("/?url=/documents/bugs/6016-oas2.yaml")
.get("#model-Pet > span .model-box")
.click()
.get("div .model-box")
.should("exist")
})
})

View File

@ -0,0 +1,54 @@
describe("#6158: read-only property is not hidden in `POST/PUT`", () => {
describe("POST", () => {
it("should hide property 'id'", () => {
cy.visit("/?url=/documents/bugs/6158.yaml")
.get("#operations-User-post_users")
.click()
.get(".parameters[data-property-name='id']")
.should("not.exist")
.get(".parameters[data-property-name='name']")
.should("exist")
})
it("should hide property 'id' when trying it out", () => {
cy.visit("/?url=/documents/bugs/6158.yaml")
.get("#operations-User-post_users")
.click()
.get(".try-out__btn")
.click()
.get(".parameters[data-property-name='id']")
.should("not.exist")
.get("input[placeholder='id']")
.should("not.exist")
.get(".parameters[data-property-name='name']")
.should("exist")
.get("input[placeholder='name']")
.should("exist")
})
})
describe("PUT", () => {
it("should hide property 'id'", () => {
cy.visit("/?url=/documents/bugs/6158.yaml")
.get("#operations-User-put_users")
.click()
.get(".parameters[data-property-name='id']")
.should("not.exist")
.get(".parameters[data-property-name='name']")
.should("exist")
})
it("should hide property 'id' when trying it out", () => {
cy.visit("/?url=/documents/bugs/6158.yaml")
.get("#operations-User-put_users")
.click()
.get(".try-out__btn")
.click()
.get(".parameters[data-property-name='id']")
.should("not.exist")
.get("input[placeholder='id']")
.should("not.exist")
.get(".parameters[data-property-name='name']")
.should("exist")
.get("input[placeholder='name']")
.should("exist")
})
})
})

View File

@ -0,0 +1,45 @@
describe("When trying it out", () => {
it("should render the response headers as comma separated lists", () => {
cy.intercept(
{
method: "GET",
url: /^\/response-headers/,
hostname: "httpbin.org",
},
{
body: {
"Access-Control-Expose-Headers": "X-Header1, X-Header2, X-Header3, Access-Control-Expose-Headers",
"Content-Length": "289",
"Content-Type": "application/json",
"X-Header1": "value1,value2",
"X-Header2": "value3,value4",
"X-Header3": ["value5", "value6"]
},
headers: {
"access-control-expose-headers": "X-Header1,X-Header2,X-Header3,Access-Control-Expose-Headers",
"content-type": "application/json",
"x-header1": "value1,value2",
"x-header2": "value3,value4",
"x-header3": "value5,value6",
}
})
cy.visit("/?url=/documents/bugs/6183.yaml")
.get("#operations-default-get_response_headers")
.click()
.get(".try-out__btn")
.click()
.get(".btn.execute")
.click()
.wait(1000)
.get(".response-col_description .microlight")
.find(("span:contains(\"value1,value2\")"))
.should("exist")
.get(".response-col_description .microlight")
.find(("span:contains(\"value3,value4\")"))
.should("exist")
.get(".response-col_description .microlight")
.find(("span:contains(\"value5,value6\")"))
.should("exist")
})
})

View File

@ -0,0 +1,43 @@
describe("#6276: Query parameter filter=true is filtering by the value 'true'", () => {
describe("With filter=true", () => {
it("should display the filter bar", () => {
cy.visit("/?url=/documents/petstore.swagger.yaml&filter=true")
.get(".operation-filter-input")
.should("exist")
.should("be.empty")
.get(".opblock-tag[data-tag='pet']")
.should("exist")
.get(".opblock-tag[data-tag='store']")
.should("exist")
.get(".opblock-tag[data-tag='user']")
.should("exist")
})
})
describe("With filter=false", () => {
it("should not display the filter bar", () => {
cy.visit("/?url=/documents/petstore.swagger.yaml&filter=false")
.get(".operation-filter-input")
.should("not.exist")
.get(".opblock-tag[data-tag='pet']")
.should("exist")
.get(".opblock-tag[data-tag='store']")
.should("exist")
.get(".opblock-tag[data-tag='user']")
.should("exist")
})
})
describe("With filter=pet", () => {
it("should display the filter bar and only show the operations tagged with pet", () => {
cy.visit("/?url=/documents/petstore.swagger.yaml&filter=pet")
.get(".operation-filter-input")
.should("exist")
.should("have.value", "pet")
.get(".opblock-tag[data-tag='pet']")
.should("exist")
.get(".opblock-tag[data-tag='store']")
.should("not.exist")
.get(".opblock-tag[data-tag='user']")
.should("not.exist")
})
})
})

View File

@ -0,0 +1,11 @@
// http://github.com/swagger-api/swagger-ui/issues/6351
describe("#6351: Server dropdown should change when switched via oas3Actions.setSelectedServer", () => {
it("should show different selected server", () => {
cy.visit("/?url=/documents/bugs/6351.yaml")
.get("select").should("have.value", "http://testserver1.com")
.window()
.then(win => win.ui.oas3Actions.setSelectedServer("http://testserver2.com"))
.get("select").should("have.value", "http://testserver2.com")
})
})

View File

@ -0,0 +1,44 @@
describe("#6369: Object model render of field: deprecated", () => {
describe("OAS3", () => {
it("should display row with td:deprecated when set to true", () => {
cy.visit("/?url=/documents/bugs/6369-oas3-display.yaml")
.get("#model-IdentificationProfile > .model-box")
.click()
.get("#model-IdentificationProfile .model-box .model .inner-object table")
.find("tr")
.should("have.length", 3)
.contains("td", "deprecated")
})
it("should not display row with td:deprecated when set to false", () => {
cy.visit("/?url=/documents/bugs/6369-oas3-no-display.yaml")
.get("#model-IdentificationProfile > .model-box")
.click()
.get("#model-IdentificationProfile .model-box .model .inner-object table")
.find("tr")
.should("have.length", 2)
.get("#model-IdentificationProfile .model-box .model .inner-object table")
.find(("td:contains(\"deprecated\")"))
.should("not.exist")
})
})
describe ("OAS2", () => {
it("should display row with td:deprecated when set to true", () => {
cy.visit("/?url=/documents/bugs/6369-oas2-display.yaml")
.get("#model-IdentificationProfile > .model-box")
.click()
.get("#model-IdentificationProfile .model-box .model .inner-object")
.contains("td", "deprecated")
})
it("should not display row with td:deprecated when set to false", () => {
cy.visit("/?url=/documents/bugs/6369-oas2-no-display.yaml")
.get("#model-IdentificationProfile > .model-box")
.click()
.get("#model-IdentificationProfile .model-box .model .inner-object table")
.find("tr")
.should("have.length", 2)
.get("#model-IdentificationProfile .model-box .model .inner-object table")
.find(("td:contains(\"deprecated\")"))
.should("not.exist")
})
})
})

View File

@ -0,0 +1,33 @@
describe("#6442: 'Examples' keyword definitions can not be rendered as xml", () => {
it("should render response examples accourdingly to content-type xml", () => {
const xmlIndicator = "<x>should be xml</x>"
cy
.visit("?url=/documents/bugs/6442.yaml")
.get("#operations-default-xmlTest")
.click()
.get(".responses-wrapper")
.within(() => {
cy
.get(".microlight")
.should("include.text", xmlIndicator)
})
})
})
describe("#6442: 'Example' keyword definitions can not be rendered as xml", () => {
it("should render response examples accourdingly to content-type xml", () => {
const xmlIndicator = "<x>should be xml</x>"
cy
.visit("?url=/documents/bugs/6442.yaml")
.get("#operations-default-xmlTest2")
.click()
.get(".responses-wrapper")
.within(() => {
cy
.get(".microlight")
.should("include.text", xmlIndicator)
})
})
})

View File

@ -0,0 +1,65 @@
describe("#6475: 'Examples' keyword definitions can not be rendered as xml", () => {
it("should render requestBody examples preview accourdingly to content-type xml", () => {
const xmlIndicator = "<x>should be xml</x>"
cy
.visit("?url=/documents/bugs/6475.yaml")
.get("#operations-default-xmlTest_examples")
.click()
.get(".opblock-section-request-body")
.within(() => {
cy
.get(".microlight")
.should("include.text", xmlIndicator)
})
})
it("should requestBody examples input accourdingly to content-type xml", () => {
const xmlIndicator = "<x>should be xml</x>"
cy
.visit("?url=/documents/bugs/6475.yaml")
.get("#operations-default-xmlTest_examples")
.click()
.get(".btn.try-out__btn")
.click()
.get(".opblock-section-request-body")
.within(() => {
cy
.get("textarea")
.contains(xmlIndicator)
})
})
})
describe("#6475: 'Example' keyword definitions can not be rendered as xml", () => {
it("should render requestBody examples preview accourdingly to content-type xml", () => {
const xmlIndicator = "<x>should be xml</x>"
cy
.visit("?url=/documents/bugs/6475.yaml")
.get("#operations-default-xmlTest_example")
.click()
.get(".opblock-section-request-body")
.within(() => {
cy
.get(".microlight")
.should("include.text", xmlIndicator)
})
})
it("should requestBody examples input accourdingly to content-type xml", () => {
const xmlIndicator = "<x>should be xml</x>"
cy
.visit("?url=/documents/bugs/6475.yaml")
.get("#operations-default-xmlTest_example")
.click()
.get(".btn.try-out__btn")
.click()
.get(".opblock-section-request-body")
.within(() => {
cy
.get("textarea")
.contains(xmlIndicator)
})
})
})

View File

@ -0,0 +1,11 @@
describe("#6540: XML example not rendered correctly with oneOf", () => {
it("should render xml like json", () => {
const expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test>\n\t<a>string</a>\n\t<b>0</b>\n\t<c>\n\t\t<ObjectType>Text</ObjectType>\n\t\t<Data>This is a text</Data>\n\t</c>\n\t<c>\n\t\t<ObjectType>image</ObjectType>\n\t\t<Data>This is a image</Data>\n\t</c>\n\t<d>\n\t\t<ObjectType>Text</ObjectType>\n\t\t<Data>This is a text</Data>\n\t</d>\n\t<d>\n\t\t<ObjectType>image</ObjectType>\n\t\t<Data>This is a image</Data>\n\t</d>\n</test>"
cy
.visit("/?url=/documents/bugs/6540.yaml")
.get("#operations-Test-postTest")
.click()
.get(".microlight")
.contains(expected)
})
})

View File

@ -0,0 +1,11 @@
describe("#6627: XML example when defined as array", () => {
it("should render xml like json", () => {
const expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Users>\n\t<User id=\"123\" name=\"bob\">\n\t</User>\n\t<User id=\"456\" name=\"jane\">\n\t</User>\n</Users>"
cy
.visit("/?url=/documents/bugs/6627.yaml")
.get("#operations-default-get_users")
.click()
.get(".microlight")
.contains(expected)
})
})

View File

@ -0,0 +1,14 @@
describe("#7996: tag description text fills container when externalDocs section absent", () => {
it("should show externalDocs div when externalDocs present in specification", () => {
cy
.visit("?url=/documents/bugs/7996-tags-externalDocs.yaml")
.get("#operations-tag-foo .info__externaldocs")
.should("exist")
})
it("should have no externalDocs div when externalDocs absent from specification", () => {
cy
.visit("?url=/documents/bugs/7996-tags-externalDocs.yaml")
.get("#operations-tag-bar .info__externaldocs")
.should("not.exist")
})
})

View File

@ -0,0 +1,24 @@
describe("#8217: Reset Request Body not using default values", () => {
it("it reset the user edited value and executes with the default value in case of try out reset. (#6517)", () => {
cy
.visit("?url=/documents/bugs/8217.yaml")
.get("#operations-default-addPet")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// replace default sample with bad value
.get(`.parameters[data-property-name="bodyParameter"] input`)
.type("{selectall}not the default value")
// Reset Try It Out
.get(".try-out__btn.reset")
.click()
// Submit using default value
.get(".btn.execute")
.click()
// No required validation error on body parameter
.get(`.parameters[data-property-name="bodyParameter"] input`)
.should("have.value", "default")
.and("not.have.class", "invalid")
})
})

View File

@ -0,0 +1,26 @@
import repeat from "lodash/repeat"
describe("Editor #1868: model changes break rendering", () => {
it("should render model content changes correctly", () => {
cy
.visit("/?url=/documents/bugs/editor-1868.yaml")
.get(".model-toggle.collapsed")
.click()
.get("#model-MyModel")
.contains("a")
.window()
.then(win => {
// Simulate Swagger Editor updating a model
const content = win.ui.specSelectors.specStr()
win.ui.specActions.updateSpec(content + `\n b:\n type: string`)
})
.get("#model-MyModel")
.contains("a")
.get("#model-MyModel")
.contains("b")
})
})

View File

@ -0,0 +1,35 @@
describe("SWOS-63: Schema/Model labeling", () => {
describe("SchemaS/Models section", () => {
it("should render `Schemas` for OpenAPI 3", () => {
cy
.visit("/?url=/documents/petstore-expanded.openapi.yaml")
.get("section.models > h4")
.contains("Schemas")
})
it("should render `Models` for OpenAPI 2", () => {
cy
.visit("/?url=/documents/petstore.swagger.yaml")
.get("section.models > h4")
.contains("Models")
})
})
describe("ModelExample within Operation", () => {
it("should render `Schemas` for OpenAPI 3", () => {
cy
.visit("/?url=/documents/petstore-expanded.openapi.yaml")
.get("#operations-default-findPets")
.click()
.get("button.tablinks[data-name=model]")
.contains("Schema")
})
it("should render `Models` for OpenAPI 2", () => {
cy
.visit("/?url=/documents/petstore.swagger.yaml")
.get("section.models > h4")
.get("#operations-pet-addPet")
.click()
.get("button.tablinks[data-name=model]")
.contains("Model")
})
})
})

View File

@ -0,0 +1,51 @@
describe("OAuth2 Bearer flow", () => {
beforeEach(() => {
const staticResponse = {
statusCode: 200,
body: {
name: "not a random secret for test",
}
}
cy.intercept("GET", "/get*", staticResponse).as(
"tokenRequest"
)
})
it("should be focused on input field with aria-label", () => {
cy.visit(
"/?url=/documents/features/auth-bearer-flow.yaml"
)
.get("button.authorize")
.click()
cy.focused()
.should("have.attr", "aria-label").and("eq", "auth-bearer-value")
})
it("should make a header request with proper sample cURL header", () => {
cy.visit(
"/?url=/documents/features/auth-bearer-flow.yaml"
)
.get("button.authorize")
.click()
.get("section > input")
.type("secret_token")
.get(".auth-btn-wrapper > .authorize")
.click()
.get("button.close-modal")
.click()
// Try-it-out
.get("#operations-default-get_get")
.click()
.get(".btn.try-out__btn")
.click()
.get(".btn.execute")
.click()
cy.wait("@tokenRequest")
.its("request")
.its("headers")
.its("authorization")
.should("equal", "Bearer secret_token")
.get(".curl")
.contains("Authorization: Bearer secret_token")
.should("be.visible")
})
})

View File

@ -0,0 +1,47 @@
describe("Check client_secret for OAuth2 Authorization Code flow with and without PKCE (#6290)", () => {
it("should display client_secret field for authorization code flow with PKCE", () => {
cy.visit(
"/?url=/documents/features/auth-code-flow-pkce-without-secret.yaml"
)
.window()
.then(win => {
// set auth config to use PKCE
let authConfigs = win.ui.authSelectors.getConfigs()
win.ui.authActions.configureAuth({
...authConfigs,
usePkceWithAuthorizationCodeGrant: true,
})
})
.get("button.authorize")
.click()
.get("h4")
.contains("authorizationCode with PKCE")
.get(".flow")
.contains("authorizationCode with PKCE")
.get("#client_secret")
.should("exist")
})
it("should display client_secret field for authorization code flow without PKCE", () => {
cy.visit(
"/?url=/documents/features/auth-code-flow-pkce-without-secret.yaml"
)
.window()
.then(win => {
// set auth config to not use PKCE
let authConfigs = win.ui.authSelectors.getConfigs()
win.ui.authActions.configureAuth({
...authConfigs,
usePkceWithAuthorizationCodeGrant: false,
})
})
.get("button.authorize")
.click()
.get("h4")
.contains("authorizationCode")
.get(".flow")
.contains("authorizationCode")
.get("#client_secret")
.should("exist")
})
})

View File

@ -0,0 +1,292 @@
describe("Deep linking feature", () => {
describe("in Swagger 2", () => {
const swagger2BaseUrl = "/?deepLinking=true&url=/documents/features/deep-linking.swagger.yaml"
describe("regular Operation", () => {
OperationDeeplinkTestFactory({
baseUrl: swagger2BaseUrl,
elementToGet: ".opblock-get",
correctElementId: "operations-myTag-myOperation",
correctFragment: "#/myTag/myOperation",
correctHref: "#/myTag/myOperation"
})
})
describe("Operation with whitespace in tag+id", () => {
const elementToGet = ".opblock-post"
const correctFragment = "#/my%20Tag/my%20Operation"
OperationDeeplinkTestFactory({
baseUrl: swagger2BaseUrl,
elementToGet,
correctElementId: "operations-my_Tag-my_Operation",
correctFragment,
correctHref: "#/my%20Tag/my%20Operation"
})
const legacyFragment = "#/my_Tag/my_Operation"
it("should expand the operation when reloaded and provided the legacy fragment", () => {
cy.visit(`${swagger2BaseUrl}${legacyFragment}`)
.reload()
.get(`${elementToGet}.is-open`)
.should("exist")
})
it.skip("should rewrite to the correct fragment when provided the legacy fragment", () => {
cy.visit(`${swagger2BaseUrl}${legacyFragment}`)
.reload()
.window()
.should("have.deep.property", "location.hash", correctFragment)
})
})
describe("Operation with underscores in tag+id", () => {
OperationDeeplinkTestFactory({
baseUrl: swagger2BaseUrl,
elementToGet: ".opblock-patch",
correctElementId: "operations-underscore_Tag-underscore_Operation",
correctFragment: "#/underscore_Tag/underscore_Operation",
correctHref: "#/underscore_Tag/underscore_Operation"
})
})
describe("Operation with UTF-16 characters", () => {
OperationDeeplinkTestFactory({
baseUrl: swagger2BaseUrl,
elementToGet: ".opblock-head",
correctElementId: "operations-шеллы-пошел",
correctFragment: "#/%D1%88%D0%B5%D0%BB%D0%BB%D1%8B/%D0%BF%D0%BE%D1%88%D0%B5%D0%BB",
correctHref: "#/шеллы/пошел"
})
})
describe("Operation with no operationId", () => {
OperationDeeplinkTestFactory({
baseUrl: swagger2BaseUrl,
elementToGet: ".opblock-put",
correctElementId: "operations-tagTwo-put_noOperationId",
correctFragment: "#/tagTwo/put_noOperationId",
correctHref: "#/tagTwo/put_noOperationId"
})
})
describe("regular Tag", () => {
TagDeeplinkTestFactory({
isTagCase: true,
baseUrl: swagger2BaseUrl,
elementToGet: `.opblock-tag[data-tag="myTag"][data-is-open="true"]`,
correctElementId: "operations-tag-myTag",
correctFragment: "#/myTag",
correctHref: "#/myTag"
})
})
describe("Tag with whitespace", () => {
TagDeeplinkTestFactory({
isTagCase: true,
baseUrl: swagger2BaseUrl,
elementToGet: `.opblock-tag[data-tag="my Tag"][data-is-open="true"]`,
correctElementId: "operations-tag-my_Tag",
correctFragment: "#/my%20Tag",
correctHref: "#/my%20Tag"
})
})
})
describe("in OpenAPI 3", () => {
const openAPI3BaseUrl = "/?deepLinking=true&url=/documents/features/deep-linking.openapi.yaml"
describe("regular Operation", () => {
OperationDeeplinkTestFactory({
baseUrl: openAPI3BaseUrl,
elementToGet: ".opblock-get",
correctElementId: "operations-myTag-myOperation",
correctFragment: "#/myTag/myOperation",
correctHref: "#/myTag/myOperation"
})
})
describe("Operation with whitespace in tag+id", () => {
const elementToGet = ".opblock-post"
const correctFragment = "#/my%20Tag/my%20Operation"
OperationDeeplinkTestFactory({
baseUrl: openAPI3BaseUrl,
elementToGet: ".opblock-post",
correctElementId: "operations-my_Tag-my_Operation",
correctFragment,
correctHref: "#/my%20Tag/my%20Operation"
})
const legacyFragment = "#/my_Tag/my_Operation"
it("should expand the operation when reloaded and provided the legacy fragment", () => {
cy.visit(`${openAPI3BaseUrl}${legacyFragment}`)
.reload()
.get(`${elementToGet}.is-open`)
.should("exist")
})
it.skip("should rewrite to the correct fragment when provided the legacy fragment", () => {
cy.visit(`${openAPI3BaseUrl}${legacyFragment}`)
.reload()
.window()
.should("have.deep.property", "location.hash", correctFragment)
})
})
describe("Operation with underscores in tag+id", () => {
OperationDeeplinkTestFactory({
baseUrl: openAPI3BaseUrl,
elementToGet: ".opblock-patch",
correctElementId: "operations-underscore_Tag-underscore_Operation",
correctFragment: "#/underscore_Tag/underscore_Operation",
correctHref: "#/underscore_Tag/underscore_Operation"
})
})
describe("Operation with UTF-16 characters", () => {
OperationDeeplinkTestFactory({
baseUrl: openAPI3BaseUrl,
elementToGet: ".opblock-head",
correctElementId: "operations-шеллы-пошел",
correctFragment: "#/%D1%88%D0%B5%D0%BB%D0%BB%D1%8B/%D0%BF%D0%BE%D1%88%D0%B5%D0%BB",
correctHref: "#/шеллы/пошел"
})
})
describe("Operation with no operationId", () => {
OperationDeeplinkTestFactory({
baseUrl: openAPI3BaseUrl,
elementToGet: ".opblock-put",
correctElementId: "operations-tagTwo-put_noOperationId",
correctFragment: "#/tagTwo/put_noOperationId",
correctHref: "#/tagTwo/put_noOperationId"
})
})
describe("regular Tag", () => {
TagDeeplinkTestFactory({
isTagCase: true,
baseUrl: openAPI3BaseUrl,
elementToGet: `.opblock-tag[data-tag="myTag"][data-is-open="true"]`,
correctElementId: "operations-tag-myTag",
correctFragment: "#/myTag",
correctHref: "#/myTag"
})
})
describe("Tag with whitespace", () => {
TagDeeplinkTestFactory({
isTagCase: true,
baseUrl: openAPI3BaseUrl,
elementToGet: `.opblock-tag[data-tag="my Tag"][data-is-open="true"]`,
correctElementId: "operations-tag-my_Tag",
correctFragment: "#/my%20Tag",
correctHref: "#/my%20Tag"
})
})
})
})
function OperationDeeplinkTestFactory({ baseUrl, elementToGet, correctElementId, correctFragment, correctHref }) {
it("should generate a correct element ID", () => {
cy.visit(baseUrl)
.get(elementToGet)
.should("have.id", correctElementId)
})
it("should add the correct element fragment to the URL when expanded", () => {
cy.visit(baseUrl)
.get(elementToGet)
.click()
cy.location().should((loc) => {
expect(loc.hash).to.eq(correctFragment)
})
})
it("should provide an anchor link that has the correct fragment as href", () => {
cy.visit(baseUrl)
.get(elementToGet)
.find("a")
.should("have.attr", "href", correctHref)
.click()
cy.location().should((loc) => {
expect(loc.hash).to.eq(correctFragment)
})
})
it("should expand the operation when reloaded", () => {
cy.visit(`${baseUrl}${correctFragment}`)
.get(`${elementToGet}.is-open`)
.should("exist")
})
it("should retain the correct fragment when reloaded", () => {
cy.visit(`${baseUrl}${correctFragment}`)
.reload()
.should("exist")
cy.location().should((loc) => {
expect(loc.hash).to.eq(correctFragment)
})
})
it("should expand a tag with docExpansion disabled", () => {
cy.visit(`${baseUrl}&docExpansion=none${correctFragment}`)
.get(`.opblock-tag-section.is-open`)
.should("have.length", 1)
})
it("should expand an operation with docExpansion disabled", () => {
cy.visit(`${baseUrl}&docExpansion=none${correctFragment}`)
.get(`.opblock.is-open`)
.should("have.length", 1)
})
}
function TagDeeplinkTestFactory({ baseUrl, elementToGet, correctElementId, correctFragment, correctHref, isTagCase = false }) {
it("should generate a correct element ID", () => {
cy.visit(baseUrl)
.get(elementToGet)
.should("have.id", correctElementId)
})
it("should add the correct element fragment to the URL when expanded", () => {
cy.visit(baseUrl)
.get(elementToGet)
.click()
.click() // tags need two clicks because they're expanded by default
cy.location().should((loc) => {
expect(loc.hash).to.eq(correctFragment)
})
})
it("should provide an anchor link that has the correct fragment as href", () => {
cy.visit(baseUrl)
.get(elementToGet)
.find("a")
.should("have.attr", "href", correctHref)
})
it("should expand the tag when reloaded", () => {
cy.visit(`${baseUrl}${correctFragment}`)
.get(`${elementToGet}[data-is-open="true"]`)
.should("exist")
})
it("should retain the correct fragment when reloaded", () => {
cy.visit(`${baseUrl}${correctFragment}`)
.reload()
.should("exist")
cy.location().should((loc) => {
expect(loc.hash).to.eq(correctFragment)
})
})
it("should expand a tag with docExpansion disabled", () => {
cy.visit(`${baseUrl}&docExpansion=none${correctFragment}`)
.get(`.opblock-tag-section.is-open`)
.should("have.length", 1)
})
}

View File

@ -0,0 +1,26 @@
describe("dynamic default oauth2RedirectUrl", () => {
it("should compute an oauth2RedirectUrl based on the browser's location at runtime", () => {
cy.visit("/")
.window()
.then(win => win.ui.getConfigs())
.should("include", { oauth2RedirectUrl: "http://localhost:3230/oauth2-redirect.html" })
})
it("should compute an oauth2RedirectUrl based on the browser's location at runtime, including the path", () => {
cy.visit("/pages/5085/")
.window()
.then(win => win.ui.getConfigs())
.should("include", { oauth2RedirectUrl: "http://localhost:3230/pages/5085/oauth2-redirect.html" })
})
it("should compute an oauth2RedirectUrl based on the browser's location at runtime, including the path, without confusing the file name for a folder name", () => {
cy.visit("/pages/5085/index.html")
.window()
.then(win => win.ui.getConfigs())
.should("include", { oauth2RedirectUrl: "http://localhost:3230/pages/5085/oauth2-redirect.html" })
})
it("should compute an oauth2RedirectUrl based on the browser's location at runtime, including the path, even it does not end with a slash", () => {
cy.visit("/pages/5085")
.window()
.then(win => win.ui.getConfigs())
.should("include", { oauth2RedirectUrl: "http://localhost:3230/pages/5085/oauth2-redirect.html" })
})
})

View File

@ -0,0 +1,108 @@
describe("External docs feature", () => {
describe("in Swagger 2", () => {
ExternalDocsTest("/?url=/documents/features/external-docs.swagger.yaml")
})
describe("in OpenAPI 3", () => {
ExternalDocsTest("/?url=/documents/features/external-docs.openapi.yaml")
})
})
function ExternalDocsTest(baseUrl) {
describe("for Root", () => {
it("should display link to external docs with description", () => {
cy.visit(baseUrl)
.get(".info__extdocs")
.should("exist")
.and("contain.text", "Read external docs")
.and("have.attr", "href", "http://swagger.io")
})
it("should display link to external docs without description", () => {
cy
.intercept({
path: /^\/documents\/features\/external-docs\.(swagger|openapi)\.yaml\?intercept$/
}, (req) => {
delete req.headers["if-none-match"]
delete req.headers["if-modified-since"]
req.continue((res) => {
res.send({body: res.body.replace(" description: Read external docs\n", "")})
})
})
.visit(`${baseUrl}?intercept`)
.get(".info__extdocs")
.should("exist")
.and("contain.text", "http://swagger.io")
.and("have.attr", "href", "http://swagger.io")
})
})
describe("for Tags", () => {
it("should display link to external docs with description", () => {
cy.visit(baseUrl)
.get(`.opblock-tag[data-tag="pet"] .info__externaldocs`)
.should("exist")
.find("a")
.should("contain.text", "Pet Documentation")
.and("have.attr", "href", "http://swagger.io")
})
it("should display link to external docs without description", () => {
cy.visit(baseUrl)
.get(`.opblock-tag[data-tag="petWithoutDescription"] .info__externaldocs`)
.should("exist")
.find("a")
.should("contain.text", "http://swagger.io")
.and("have.attr", "href", "http://swagger.io")
})
})
describe("for Schemas", () => {
function SchemaTestFactory(type) {
return () => {
it("should display link with description", () => {
cy.visit(baseUrl)
.get(`.models #model-${type} button`)
.click()
.get(`.models #model-${type} .external-docs a`)
.should("contain.text", `${type} Docs`)
.and("have.attr", "href", "http://swagger.io")
})
it("should display link without description", () => {
cy.visit(baseUrl)
.get(`.models #model-${type}WithoutDescription button`)
.click()
.get(`.models #model-${type}WithoutDescription .external-docs a`)
.should("contain.text", "http://swagger.io")
.and("have.attr", "href", "http://swagger.io")
})
}
}
describe("Primitive Schema", SchemaTestFactory("Primitive"))
describe("Array Schema", SchemaTestFactory("Array"))
describe("Object Schema", SchemaTestFactory("Object"))
})
describe("for Operation", () => {
it("should display link to external docs with description", () => {
cy.visit(baseUrl)
.get("#operations-pet-updatePet button")
.click()
.get("#operations-pet-updatePet .opblock-external-docs-wrapper .opblock-external-docs__description")
.should("contain.text", "More details about putting a pet")
.get("#operations-pet-updatePet .opblock-external-docs-wrapper .opblock-external-docs__link")
.should("have.attr", "href", "http://swagger.io")
})
it("should display link to external docs without description", () => {
cy.visit(baseUrl)
.get("#operations-pet-addPet button")
.click()
.get("#operations-pet-addPet .opblock-external-docs-wrapper .opblock-external-docs__description")
.should("not.exist")
.get("#operations-pet-addPet .opblock-external-docs-wrapper .opblock-external-docs__link")
.should("have.attr", "href", "http://swagger.io")
})
})
}

View File

@ -0,0 +1,50 @@
describe("Model collapse/expand feature", () => {
describe("in Swagger 2", () => {
const swagger2BaseUrl = "/?deepLinking=true&url=/documents/features/models.swagger.yaml"
const urlFragment = "#/definitions/Pet"
ModelCollapseTest(swagger2BaseUrl, urlFragment)
})
describe("in OpenAPI 3", () => {
const openAPI3BaseUrl = "/?deepLinking=true&url=/documents/features/models.openapi.yaml"
ModelCollapseTest(openAPI3BaseUrl)
})
})
function ModelCollapseTest(baseUrl, urlFragment) {
it("Models section should be expanded on load", () => {
cy.visit(baseUrl)
.get(".models")
.should("have.class", "is-open")
.get("#model-Pet")
.should("exist")
})
it("Models section should collapse and expand when toggled", () => {
cy.visit(baseUrl)
.get(".models h4 .models-control")
.click()
.get(".models")
.should("not.have.class", "is-open")
.get("#model-Order")
.should("not.exist")
.get(".models h4 .models-control")
.click()
.get(".models")
.should("have.class", "is-open")
.get("#model-Order")
.should("exist")
})
it("Model should collapse and expand when toggled clicking button", () => {
cy.visit(baseUrl)
.get("#model-User .model-box .model-box-control")
.click()
.get("#model-User .model-box .model .inner-object")
.should("exist")
.get("#model-User .model-box .model-box-control")
.first()
.click()
.get("#model-User .model-box .model .inner-object")
.should("not.exist")
})
}

View File

@ -0,0 +1,662 @@
/**
* @prettier
*/
const {
ParameterPrimitiveTestCases,
RequestBodyPrimitiveTestCases,
ResponsePrimitiveTestCases,
} = require("../../helpers/multiple-examples")
describe("OpenAPI 3.0 Multiple Examples - core features", () => {
describe("/String", () => {
describe("in a parameter", () => {
ParameterPrimitiveTestCases({
operationDomId: "#operations-default-post_String",
parameterName: "message",
exampleA: {
key: "StringExampleA",
value: "hello world",
},
exampleB: {
key: "StringExampleB",
value: "The quick brown fox jumps over the lazy dog",
},
customUserInput: "OpenAPIs.org <3",
})
})
describe("in a Request Body", () => {
RequestBodyPrimitiveTestCases({
operationDomId: "#operations-default-post_String",
exampleA: {
key: "StringExampleA",
value: "hello world",
serializedValue: "hello world",
summary: "Don't just string me along...",
},
exampleB: {
key: "StringExampleB",
value: "The quick brown fox jumps over the lazy dog",
serializedValue: "The quick brown fox jumps over the lazy dog",
summary: "I'm a pangram!",
},
customUserInput: "OpenAPIs.org <3",
})
})
describe("in a Response", () => {
ResponsePrimitiveTestCases({
operationDomId: "#operations-default-post_String",
exampleA: {
key: "StringExampleA",
value: "hello world",
summary: "Don't just string me along...",
},
exampleB: {
key: "StringExampleB",
value: "The quick brown fox jumps over the lazy dog",
summary: "I'm a pangram!",
},
exampleC: {
key: "StringExampleC",
value: "JavaScript rules",
summary: "A third example, for use in special places...",
},
})
})
})
describe("/Number", () => {
describe("in a parameter", () => {
ParameterPrimitiveTestCases({
operationDomId: "#operations-default-post_Number",
parameterName: "message",
exampleA: {
key: "NumberExampleA",
value: "7710263025",
},
exampleB: {
key: "NumberExampleB",
value: "9007199254740991",
},
exampleC: {
key: "NumberExampleC",
value: "0",
},
customUserInput: "9001",
})
})
describe("in a Request Body", () => {
RequestBodyPrimitiveTestCases({
operationDomId: "#operations-default-post_Number",
exampleA: {
key: "NumberExampleA",
value: "7710263025",
summary: "World population",
},
exampleB: {
key: "NumberExampleB",
value: "9007199254740991",
summary: "Number.MAX_SAFE_INTEGER",
},
exampleC: {
key: "NumberExampleC",
value: "0",
},
customUserInput: "1337",
})
})
describe("in a Response", () => {
ResponsePrimitiveTestCases({
operationDomId: "#operations-default-post_Number",
exampleA: {
key: "NumberExampleA",
value: "7710263025",
summary: "World population",
},
exampleB: {
key: "NumberExampleB",
value: "9007199254740991",
summary: "Number.MAX_SAFE_INTEGER",
},
exampleC: {
key: "NumberExampleC",
value: "0",
},
})
})
})
describe("/Boolean", () => {
describe("in a parameter", () => {
it("should render and apply the first example and value by default", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Boolean")
.click()
// Assert on the initial dropdown value
.get("table.parameters .examples-select > select")
.find(":selected")
.should("have.text", "The truth will set you free")
// Assert on the initial JsonSchemaForm value
.get(".parameters-col_description > select")
.should("have.attr", "disabled")
.get(".parameters-col_description > select")
.find(":selected")
.should("have.text", "true")
// Execute
.get(".try-out__btn")
.click()
.get(".execute")
.click()
// Assert on the request URL
.get(".request-url")
.contains(`?message=true`)
})
it("should render and apply the second value when chosen", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Boolean")
.click()
// Set the dropdown value, then assert on it
.get("table.parameters .examples-select > select")
.select("BooleanExampleB")
.find(":selected")
.should("have.text", "Friends don't lie to friends")
// Set the JsonSchemaForm value, then assert on it
.get(".parameters-col_description > select")
.find(":selected")
.should("have.text", "false")
// Execute
.get(".try-out__btn")
.click()
.get(".execute")
.click()
// Assert on the request URL
.get(".request-url")
.contains(`?message=false`)
})
it("should track value changes against valid examples", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Boolean")
.click()
.get(".try-out__btn")
.click()
// Set the JsonSchemaForm value, then assert on it
.get(".parameters-col_description > select")
.select("false")
.find(":selected")
.should("have.text", "false")
// Assert on the dropdown value
.get("table.parameters .examples-select > select")
.find(":selected")
.should("have.text", "Friends don't lie to friends")
// Execute
.get(".execute")
.click()
// Assert on the request URL
.get(".request-url")
.contains(`?message=false`)
})
})
describe("in a Request Body", () => {
RequestBodyPrimitiveTestCases({
operationDomId: "#operations-default-post_Boolean",
exampleA: {
key: "BooleanExampleA",
value: "true",
summary: "The truth will set you free",
},
exampleB: {
key: "BooleanExampleB",
value: "false",
summary: "Friends don't lie to friends",
},
customUserInput: "tralse",
})
})
describe("in a Response", () => {
it("should render and apply the first example and value by default", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Boolean")
.click()
// Assert on the initial dropdown value
.get(".responses-wrapper .examples-select > select")
.find(":selected")
.should("have.text", "The truth will set you free")
// Assert on the example value
.get(".example.microlight")
.should("have.text", "true")
})
it("should render and apply the second value when chosen", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Boolean")
.click()
// Set the dropdown value, then assert on it
.get(".responses-wrapper .examples-select > select")
.select("BooleanExampleB")
.find(":selected")
.should("have.text", "Friends don't lie to friends")
// Assert on the example value
.get(".example.microlight")
.should("have.text", "false")
})
})
})
describe("/Array", () => {
describe("in a Parameter", () => {
it("should have the first example's array entries by default", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"a",
"b",
"c",
])
})
.get(".parameters-col_description .examples-select > select")
.find(":selected")
.should("have.text", "A lowly array of strings")
})
it("should switch to the second array's entries via dropdown", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
.get(".parameters-col_description .examples-select > select")
.select("ArrayExampleB")
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"1",
"2",
"3",
"4",
])
})
.get(".parameters-col_description .examples-select > select")
.find(":selected")
.should("have.text", "A lowly array of numbers")
})
it("should not allow modification of values in static mode", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
.get(".parameters-col_description .examples-select > select")
.select("ArrayExampleB")
// Add a new item
.get(".json-schema-form-item > input")
.should("have.attr", "disabled")
})
it("should allow modification of values in Try-It-Out", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
.get(".try-out__btn")
.click()
.get(".parameters-col_description .examples-select > select")
.select("ArrayExampleB")
// Add a new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > input")
.type("{selectall}5")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"1",
"2",
"3",
"4",
"5",
])
})
.get(".parameters-col_description .examples-select > select")
.find(":selected")
.should("have.text", "[Modified value]")
})
it("should retain a modified value, and support returning to it", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
.get(".try-out__btn")
.click()
.get(".parameters-col_description .examples-select > select")
.select("ArrayExampleB")
// Add a new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > input")
.type("{selectall}5")
// Reset to an example
.get(".parameters-col_description .examples-select > select")
.select("ArrayExampleB")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"1",
"2",
"3",
"4",
])
})
.get(".parameters-col_description .examples-select > select")
.find(":selected")
.should("have.text", "A lowly array of numbers")
// Return to the modified value
.get(".parameters-col_description .examples-select > select")
.select("__MODIFIED__VALUE__")
// Assert that our modified value is back
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"1",
"2",
"3",
"4",
"5",
])
})
.get(".parameters-col_description .examples-select > select")
.find(":selected")
.should("have.text", "[Modified value]")
})
})
describe("in a Request Body", () => {
it("should have the first example's array entries by default", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
// Check HighlightCode value
.get(".opblock-section-request-body .highlight-code")
.should("include.text", JSON.stringify(["a", "b", "c"], null, 2))
// Check dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", "A lowly array of strings")
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Check textarea value
.get(".opblock-section-request-body textarea")
.should("have.value", JSON.stringify(["a", "b", "c"], null, 2))
// Check dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", "A lowly array of strings")
})
it("should switch to the second array's entries via dropdown", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
.get(".opblock-section-request-body .examples-select > select")
.select("ArrayExampleB")
.get(".opblock-section-request-body .highlight-code")
.should("include.text", JSON.stringify([1, 2, 3, 4], null, 2))
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", "A lowly array of numbers")
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Check textarea value
.get(".opblock-section-request-body textarea")
.should("include.text", JSON.stringify([1, 2, 3, 4], null, 2))
// Check dropdown value
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", "A lowly array of numbers")
})
it("should allow modification of values", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Choose the second example
.get(".opblock-section-request-body .examples-select > select")
.select("ArrayExampleB")
// Change the value
.get(".opblock-section-request-body textarea")
.type(`{leftarrow}{leftarrow},{enter} 5`)
// Check that [Modified value] is displayed in dropdown
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", "[Modified value]")
// Check textarea value
.get(".opblock-section-request-body textarea")
.should("include.text", JSON.stringify([1, 2, 3, 4, 5], null, 2))
})
it("should retain a modified value, and support returning to it", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Choose the second example as the example to start with
.get(".opblock-section-request-body .examples-select > select")
.select("ArrayExampleB")
// Change the value
.get(".opblock-section-request-body textarea")
.type(`{leftarrow}{leftarrow},{enter} 5`)
// Check that [Modified value] is displayed in dropdown
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", "[Modified value]")
// Check textarea value
.get(".opblock-section-request-body textarea")
.should("include.text", JSON.stringify([1, 2, 3, 4, 5], null, 2))
// Choose the second example
.get(".opblock-section-request-body .examples-select > select")
.select("ArrayExampleB")
// Check that the example is displayed in dropdown
.get(".opblock-section-request-body .examples-select > select")
.find(":selected")
.should("have.text", "A lowly array of numbers")
// Check textarea value
.get(".opblock-section-request-body textarea")
.should("include.text", JSON.stringify([1, 2, 3, 4], null, 2))
// Switch back to the modified value
.get(".opblock-section-request-body .examples-select > select")
.select("__MODIFIED__VALUE__")
// Check textarea value
.get(".opblock-section-request-body textarea")
.should("include.text", JSON.stringify([1, 2, 3, 4, 5], null, 2))
})
})
describe("in a Response", () => {
it("should render and apply the first example and value by default", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
// Assert on the initial dropdown value
.get(".responses-wrapper .examples-select > select")
.find(":selected")
.should("have.text", "A lowly array of strings")
// Assert on the example value
.get(".example.microlight")
.should("include.text", JSON.stringify(["a", "b", "c"], null, 2))
})
it("should render and apply the second value when chosen", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
// Set the dropdown value, then assert on it
.get(".responses-wrapper .examples-select > select")
.select("ArrayExampleB")
.find(":selected")
.should("have.text", "A lowly array of numbers")
// Assert on the example value
.get(".example.microlight")
.should("include.text", JSON.stringify([1, 2, 3, 4], null, 2))
})
})
})
describe("/Object", () => {
describe("in a Parameter", () => {
ParameterPrimitiveTestCases({
operationDomId: "#operations-default-post_Object",
parameterName: "data",
customUserInput: `{{} "openapiIsCool": true }`,
customExpectedUrlSubstring: "?openapiIsCool=true",
exampleA: {
key: "ObjectExampleA",
serializedValue:
"firstName=Kyle&lastName=Shockey&email=kyle.shockey%40smartbear.com",
value: JSON.stringify(
{
firstName: "Kyle",
lastName: "Shockey",
email: "kyle.shockey@smartbear.com",
},
null,
2
),
},
exampleB: {
key: "ObjectExampleB",
serializedValue:
"name=Abbey&type=kitten&color=calico&gender=female&age=11%20weeks",
value: JSON.stringify(
{
name: "Abbey",
type: "kitten",
color: "calico",
gender: "female",
age: "11 weeks",
},
null,
2
),
},
})
})
describe("in a Request Body", () => {
const exampleA = JSON.stringify(
{
firstName: "Kyle",
lastName: "Shockey",
email: "kyle.shockey@smartbear.com",
},
null,
2
)
const exampleB = JSON.stringify(
{
name: "Abbey",
type: "kitten",
color: "calico",
gender: "female",
age: "11 weeks",
},
null,
2
)
RequestBodyPrimitiveTestCases({
operationDomId: "#operations-default-post_Object",
primaryMediaType: "application/json",
// ↓ not a typo, Cypress requires escaping { when using `cy.type`
customUserInput: `{{} "openapiIsCool": true }`,
customExpectedUrlSubstring: "?openapiIsCool=true",
customUserInputExpectedCurlSubstring: `{ "openapiIsCool": true }`,
exampleA: {
key: "ObjectExampleA",
serializedValue: exampleA,
value: exampleA,
summary: "A user's contact info",
},
exampleB: {
key: "ObjectExampleB",
serializedValue: exampleB,
value: exampleB,
summary: "A wonderful kitten's info",
},
})
it("should display an error message when input validation fails", () => {
cy.visit("/?url=/documents/features/multiple-examples-core.openapi.yaml")
// Expand the operation
.get("#operations-default-post_Object")
.click()
// Switch to Try-It-Out
.get(".try-out__btn")
.click()
// Set an invalid value
.get(".parameters-container > div > table > tbody > tr > td.parameters-col_description > div:nth-child(2) > textarea")
.type("{{{{ [[[[ <<<< invalid JSON here.")
// Execute the operation
.get(".execute")
.click()
// Verify that an error is shown
.get(".validation-errors")
.contains("Parameter string value must be valid JSON")
})
})
describe("in a Response", () => {
ResponsePrimitiveTestCases({
operationDomId: "#operations-default-post_Object",
exampleA: {
key: "ObjectExampleA",
value: JSON.stringify(
{
firstName: "Kyle",
lastName: "Shockey",
email: "kyle.shockey@smartbear.com",
},
null,
2
),
summary: "A user's contact info",
},
exampleB: {
key: "ObjectExampleB",
value: JSON.stringify(
{
name: "Abbey",
type: "kitten",
color: "calico",
gender: "female",
age: "11 weeks",
},
null,
2
),
summary: "A wonderful kitten's info",
},
})
})
})
})

View File

@ -0,0 +1,184 @@
// https://github.com/swagger-api/swagger-ui/issues/6201
// https://github.com/swagger-api/swagger-ui/issues/6250
// https://github.com/swagger-api/swagger-ui/issues/6476
describe("OpenAPI 3.0 Multiple Media Types with different schemas", () => {
const mediaTypeFormData = "multipart/form-data"
const mediaTypeUrlencoded = "application/x-www-form-urlencoded"
const mediaTypeJson = "application/json"
beforeEach(() => {
cy.intercept({
method: "POST",
url: "/post",
hostname: "httpbin.org",
}, {})
cy.visit(
"/?url=/documents/features/oas3-multiple-media-type.yaml"
)
.get("#operations-default-post_post")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// @alias Execute Button
cy.get(".execute.opblock-control__btn").as("executeBtn")
// @alias Media Type Dropdown
cy.get(".opblock-section-request-body .content-type").as("selectMediaType")
})
// In all cases,
// - assume that examples are populated based on schema (not explicitly tested)
// - assume validation passes based on successful "execute"
// - expect final cURL command result doees not contain unexpected artifacts from other content-type schemas
describe("multipart/form-data (only 'bar')", () => {
it("should execute multipart/form-data", () => {
cy.get("@selectMediaType")
.select(mediaTypeUrlencoded)
.get("@executeBtn")
.click()
.get("@selectMediaType")
.select(mediaTypeFormData)
.get("@executeBtn")
.click()
// cURL component
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "bar")
.should("not.contains.text", "foo")
})
it("should execute application/x-www-form-urlencoded THEN execute multipart/form-data", () => {
cy.get("@selectMediaType")
.select(mediaTypeUrlencoded)
.get("@executeBtn")
.click()
.get("@selectMediaType")
.select(mediaTypeFormData)
.get("@executeBtn")
.click()
// cURL component
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "bar")
.should("not.contains.text", "foo")
})
it("should execute application/json THEN execute multipart/form-data", () => {
cy.get("@selectMediaType")
.select(mediaTypeJson)
.get("@executeBtn")
.click()
.get("@selectMediaType")
.select(mediaTypeFormData)
.get("@executeBtn")
.click()
// cURL component
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "bar")
.should("not.contains.text", "foo")
})
})
describe("application/x-www-form-urlencoded (only 'foo')", () => {
it("should execute application/x-www-form-urlencoded", () => {
cy.get("@selectMediaType")
.select(mediaTypeUrlencoded)
.get("@executeBtn")
.click()
// cURL component
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "foo")
.should("not.contains.text", "bar")
})
it("should execute multipart/form-data THEN execute application/x-www-form-urlencoded", () => {
cy.get("@selectMediaType")
.select(mediaTypeFormData)
.get("@executeBtn")
.click()
.get("@selectMediaType")
.select(mediaTypeUrlencoded)
.get("@executeBtn")
.click()
// cURL component
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "foo")
.should("not.contains.text", "bar")
})
it("should execute application/json THEN execute application/x-www-form-urlencoded", () => {
cy.get("@selectMediaType")
.select(mediaTypeJson)
.get("@executeBtn")
.click()
.get("@selectMediaType")
.select(mediaTypeUrlencoded)
.get("@executeBtn")
.click()
// cURL component
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "foo")
.should("not.contains.text", "bar")
})
})
describe("application/json (both 'foo' and 'bar')", () => {
// note: form input for "application/json" is a string; not multiple form fields
it("should execute application/json", () => {
// final curl should have both "bar" and "foo"
cy.get("@selectMediaType")
.select(mediaTypeJson)
.get("@executeBtn")
.click()
.get("@executeBtn")
.click()
// cURL component
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "foo")
.should("contains.text", "bar")
})
it("should execute multipart/form-data THEN execute application/json", () => {
cy.get("@selectMediaType")
.select(mediaTypeFormData)
.get("@executeBtn")
.click()
.get("@selectMediaType")
.select(mediaTypeJson)
.get("@executeBtn")
.click()
// cURL component
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "foo")
.should("contains.text", "bar")
})
it("should execute application/x-www-form-urlencoded THEN execute application/json", () => {
// final curl should have both "bar" and "foo"
cy.get("@selectMediaType")
.select(mediaTypeUrlencoded)
.get("@executeBtn")
.click()
.get("@selectMediaType")
.select(mediaTypeJson)
.get("@executeBtn")
.click()
// cURL component
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "foo")
.should("contains.text", "bar")
})
})
})

View File

@ -0,0 +1,82 @@
/**
* @prettier
*/
describe("OpenAPI 3.0 Multiple Servers", () => {
it("should render and execute for server '/test-url-1'", () => {
cy.visit(
"/?url=/documents/features/oas3-multiple-servers.yaml"
)
.get(".scheme-container .schemes .servers label > select")
.select("/test-url-1")
.get("#operations-default-get_")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
.get(".responses-wrapper .request-url")
.should("contains.text", "/test-url-1")
})
it("should render and execute for server '/test-url-2'", () => {
cy.visit(
"/?url=/documents/features/oas3-multiple-servers.yaml"
)
.get(".scheme-container .schemes .servers label > select")
.select("/test-url-2")
.get("#operations-default-get_")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
.get(".responses-wrapper .request-url")
.should("contains.text", "/test-url-2")
})
it("should render and execute for server '/test-url-1' after sequence: select '/test-url-2' -> Try-It-Out -> select '/test-url-1'", () => {
cy.visit(
"/?url=/documents/features/oas3-multiple-servers.yaml"
)
.get(".scheme-container .schemes .servers label > select")
.select("/test-url-2")
.get("#operations-default-get_")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Select a different server
.get(".scheme-container .schemes .servers label > select")
.select("/test-url-1")
// Execute
.get(".execute.opblock-control__btn")
.click()
.get(".responses-wrapper .request-url")
.should("contains.text", "/test-url-1")
})
it("should render and execute for server '/test-url-switch-1' after changing api definition", () => {
cy.visit(
"/?url=/documents/features/oas3-multiple-servers.yaml"
)
.get(".scheme-container .schemes .servers label > select")
.select("/test-url-2")
cy.visit(
"/?url=/documents/features/oas3-multiple-servers-switch.yaml"
)
.get(".scheme-container .schemes .servers label > select")
.select("/test-url-switch-2")
.get("#operations-default-get_")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
.get(".responses-wrapper .request-url")
.should("contains.text", "/test-url-switch-2")
})
})

View File

@ -0,0 +1,145 @@
/**
* @prettier
*/
describe("OpenAPI 3.0 Allow Empty Values in Request Body", () => {
it("should not apply or render to required fields", () => {
cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml"
)
.get("#operations-pet-addPet")
.click()
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Request Body
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(2) > .parameters-col_description .parameter__empty_value_toggle input")
.should("not.exist")
})
it("by default, should be checked for all non-required fields", () => {
cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml"
)
.get("#operations-pet-addPet")
.click()
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Request Body
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input")
.should("be.checked")
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(6) > .parameters-col_description .parameter__empty_value_toggle input")
.should("be.checked")
})
it("checkbox should be toggle-able", () => {
cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml"
)
.get("#operations-pet-addPet")
.click()
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Request Body
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input")
.should("be.checked")
.uncheck()
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input")
.should("not.be.checked")
})
it("on execute, should allow send with all empty values", () => {
cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml"
)
.get("#operations-pet-addPet")
.click()
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// add item to pass required validation
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description button")
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
// cURL component
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "tags=&status=")
})
it("on execute, should allow send with some empty values", () => {
cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml"
)
.get("#operations-pet-addPet")
.click()
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Request Body
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input")
.uncheck()
// add item to pass required validation
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description button")
.click()
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) input")
.clear()
// Execute
.get(".execute.opblock-control__btn")
.click()
// cURL component
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "&status=")
.should("not.contains.text", "tags=")
})
it("on execute, should allow send with skip all empty values", () => {
cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml"
)
.get("#operations-pet-addPet")
.click()
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Request Body
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input")
.uncheck()
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(6) > .parameters-col_description .parameter__empty_value_toggle input")
.uncheck()
// add item to pass required validation
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description button")
.click()
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) input")
.clear()
// Execute
.get(".execute.opblock-control__btn")
.click()
// cURL component
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("not.contains.text", "tags=")
.should("not.contains.text", "status=")
})
})

View File

@ -0,0 +1,16 @@
describe("OAS3 default views", () => {
describe("multipart/form-data", () => {
it("should display calculated object string, when no examples provided (#7268)", () => {
cy.visit(
"/?url=/documents/features/request-body/multipart/default-views.yaml",
)
.get("#operations-default-post_test")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
.get(".parameters-col_description textarea")
.should("contains.text", "\"stuff\": \"string\"")
})
})
})

View File

@ -0,0 +1,265 @@
/**
* @prettier
*/
describe("OpenAPI 3.0 Validation for Required Request Body and Request Body Fields", () => {
describe("Request Body required bug/5181", () => {
beforeEach(() => {
cy.intercept(
{
method: "POST",
url: "/anything/foos",
hostname: "httpbin.org",
},
{}
)
})
it("on execute, if empty value, SHOULD render class 'invalid' and should NOT render cURL component", () => {
cy.visit("/?url=/documents/bugs/5181.yaml")
.get("#operations-default-post_foos")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// get input
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(1) > .parameters-col_description input"
)
.should("not.have.class", "invalid")
// Execute
.get(".execute.opblock-control__btn")
.click()
// class "invalid" should now exist (and render red, which we won't check)
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(1) > .parameters-col_description input"
)
.should("have.class", "invalid")
// cURL component should not exist
.get(".responses-wrapper .curl-command")
.should("not.exist")
})
it("on execute, if value exists, should NOT render class 'invalid' and SHOULD render cURL component", () => {
cy.visit("/?url=/documents/bugs/5181.yaml")
.get("#operations-default-post_foos")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// get input
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(1) > .parameters-col_description input"
)
.type("abc")
// Execute
.get(".execute.opblock-control__btn")
.click()
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(1) > .parameters-col_description input"
)
.should("not.have.class", "invalid")
// cURL component should exist
.get(".responses-wrapper .curl-command")
.should("exist")
})
})
describe("Request Body required fields - application/json", () => {
it("on execute, if empty value, SHOULD render class 'invalid' and should NOT render cURL component", () => {
cy.visit("/?url=/documents/features/petstore-only-pet.openapi.yaml")
.get("#operations-pet-addPet")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// get and clear textarea
.get(
".opblock-body .opblock-section .opblock-section-request-body .body-param textarea"
)
.should("not.have.class", "invalid")
.clear()
// Execute
.get(".execute.opblock-control__btn")
.click()
// class "invalid" should now exist (and render red, which we won't check)
.get(
".opblock-body .opblock-section .opblock-section-request-body .body-param textarea"
)
.should("have.class", "invalid")
// cURL component should not exist
.get(".responses-wrapper .curl-command")
.should("not.exist")
})
it("on execute, if value exists, even if just single space, should NOT render class 'invalid' and SHOULD render cURL component that contains the single space", () => {
cy.visit("/?url=/documents/features/petstore-only-pet.openapi.yaml")
.get("#operations-pet-addPet")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// get, clear, then modify textarea
.get(
".opblock-body .opblock-section .opblock-section-request-body .body-param textarea"
)
.clear()
.type(" ")
// Execute
.get(".execute.opblock-control__btn")
.click()
.get(
".opblock-body .opblock-section .opblock-section-request-body .body-param textarea"
)
.should("not.have.class", "invalid")
// cURL component should exist
.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "' '")
})
})
/*
petstore ux notes:
- required field, but if example value exists, will populate the field. So this test will clear the example value.
- "add item" will insert an empty array, and display an input text box. This establishes a value for the field.
*/
describe("Request Body required fields - application/x-www-form-urlencoded", () => {
it("on execute, if empty value, SHOULD render class 'invalid' and should NOT render cURL component", () => {
cy.visit("/?url=/documents/features/petstore-only-pet.openapi.yaml")
.get("#operations-pet-addPet")
.click()
.get(
".opblock-section .opblock-section-request-body .body-param-content-type > select"
)
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// get and clear input populated from example value
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(2) > .parameters-col_description input"
)
.clear()
// Execute
.get(".execute.opblock-control__btn")
.click()
// class "invalid" should now exist (and render red, which we won't check)
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(2) > .parameters-col_description input"
)
.should("have.class", "invalid")
// cURL component should not exist
.get(".responses-wrapper .curl-command")
.should("not.exist")
})
it("on execute, if all values exist, even if array exists but is empty, should NOT render class 'invalid' and SHOULD render cURL component", () => {
cy.visit("/?url=/documents/features/petstore-only-pet.openapi.yaml")
.get("#operations-pet-addPet")
.click()
.get(
".opblock-section .opblock-section-request-body .body-param-content-type > select"
)
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// add item to get input
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description button"
)
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(2) > .parameters-col_description input"
)
.should("have.value", "doggie")
.should("not.have.class", "invalid")
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description input"
)
.should("have.value", "string")
.should("not.have.class", "invalid")
// cURL component should exist
.get(".responses-wrapper .curl-command")
.should("exist")
})
})
describe("Request Body: switching between Content Types", () => {
it("after application/json 'invalid' error, on switch content type to application/x-www-form-urlencoded, SHOULD be free of errors", () => {
cy.visit("/?url=/documents/features/petstore-only-pet.openapi.yaml")
.get("#operations-pet-addPet")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// get and clear textarea
.get(
".opblock-body .opblock-section .opblock-section-request-body .body-param textarea"
)
.should("not.have.class", "invalid")
.clear()
// Execute
.get(".execute.opblock-control__btn")
.click()
.get(
".opblock-body .opblock-section .opblock-section-request-body .body-param textarea"
)
.should("have.class", "invalid")
// switch content type
.get(
".opblock-section .opblock-section-request-body .body-param-content-type > select"
)
.select("application/x-www-form-urlencoded")
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(2) > .parameters-col_description input"
)
.should("not.have.class", "invalid")
// add item to get input, just an extra confirmation of non-invalid class
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description button"
)
.click()
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(4) > .parameters-col_description input"
)
.should("not.have.class", "invalid")
})
it("after application/x-www-form-urlencoded 'invalid' error, on switch content type to application/json, SHOULD be free of errors", () => {
cy.visit("/?url=/documents/features/petstore-only-pet.openapi.yaml")
.get("#operations-pet-addPet")
.click()
.get(
".opblock-section .opblock-section-request-body .body-param-content-type > select"
)
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// get and clear input
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(2) > .parameters-col_description input"
)
.clear()
// Execute
.get(".execute.opblock-control__btn")
.click()
// class "invalid" should now exist (and render red, which we won't check)
.get(
".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(2) > .parameters-col_description input"
)
.should("have.class", "invalid")
// switch content type
.get(
".opblock-section .opblock-section-request-body .body-param-content-type > select"
)
.select("application/json")
.get(
".opblock-body .opblock-section .opblock-section-request-body .body-param textarea"
)
.should("not.have.class", "invalid")
})
})
})

View File

@ -0,0 +1,106 @@
function getExpandedTryout(page = null, operationId = "#operations-pet-addPet") {
return (page || cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml",
))
.get(operationId)
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
}
const getRequestBodyFromCY = (page = null, operationId = "#operations-pet-addPet") =>
getExpandedTryout(page, operationId)
// get textarea
.get(".opblock-body .opblock-section .opblock-section-request-body .body-param textarea")
const xmlIndicator = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
const userEditXmlSample = xmlIndicator +
"<pet>\n" +
"\t<id>420</id>\n" +
"\t<name>doggie<3</name>\n" +
"\t<category>\n" +
"\t\t<id>99999999999</id>\n" +
"\t\t<name>Dogiiiiiiiieeee</name>\n" +
"\t</category>\n" +
"\t<photoUrls>\n" +
"\t\t<photoUrl>string</photoUrl>\n" +
"\t</photoUrls>\n" +
"\t<tags>\n" +
"\t\t<tag>\n" +
"\t\t\t<id>0</id>\n" +
"\t\t\t<name>string</name>\n" +
"\t\t</tag>\n" +
"\t</tags>\n" +
"\t<status>available</status>\n" +
"</pet>"
describe("OAS3 Request Body user edit flows", () => {
// Case: Copy xml from email, paste into request body editor, change media-type to xml
it("it should never overwrite user edited value in case of media-type change", () => {
getRequestBodyFromCY()
// replace default sample with xml edited value
.type(`{selectall}${userEditXmlSample}`)
// change media type to xml, because I have forgotten it
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/xml")
// Ensure user edited body is not overwritten
.get(".opblock-section-request-body")
.within(() => {
cy
.get("textarea")
.should(($div) => {
expect($div.get(0).textContent).to.eq(userEditXmlSample)
})
})
})
// Case: User really wants to try out the brand new xml content-type
it("it should overwrite default value in case of content-type change, even within request body editor(#6836)", () => {
getRequestBodyFromCY()
// change media type to xml, because I have forgotten it (sry really wanted to try out the new xml content-type)
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/xml")
// Ensure default value is xml after content type change
.get(".opblock-section-request-body")
.within(() => {
cy
.get("textarea")
.should(($div) => {
expect($div.get(0).textContent).to.contain(xmlIndicator)
})
})
})
// Case: User wants to get the default value back
it("it reset the user edited value and render the default value in case of try out reset. (#6517)", () => {
getRequestBodyFromCY()
// replace default sample with bad value
.type("{selectall}ups that should not have happened")
// Cancel Try It Out
.get(".try-out__btn.reset")
.click()
// Ensure default value is xml after content type change
.get(".opblock-section-request-body")
.within(() => {
cy
.get("textarea")
.should(($div) => {
expect($div.get(0).textContent).to.not.contain("ups that should not have happened")
})
})
})
describe("multipart/", () => {
// Case: User wants to execute operation with media-type multipart/ with a enum property. The user expects the first enum value to be used when executed.
it("should use the first enum value on execute if not changed by user (#6976)", () => {
// test/e2e-cypress/static/documents/features/request-body/multipart/enum.yaml
getExpandedTryout(
cy.visit(
"/?url=/documents/features/request-body/multipart/enum.yaml",
), "#operations-default-post_test")
.get(".execute")
.click()
// Assert on the request URL
.get(".curl")
.contains("test_enum=A")
})
})
})

View File

@ -0,0 +1,70 @@
describe("XML schema rendering examples", () => {
it("Should render RequestBody example value when schema contains `oneOf` for mediaType `text/xml`", () => {
cy.visit("?url=/documents/features/oas3-xml.json")
.get("#operations-default-post_foo")
.click()
.get("label > .content-type-wrapper > .content-type option:selected")
.should("have.text", "text/xml")
.get(".body-param__example")
.should("contains.text", "<fooOne>")
})
it("Should render RequestBody example value when schema contains `anyOf` for mediaType `text/xml`", () => {
cy.visit("?url=/documents/features/oas3-xml.json")
.get("#operations-default-post_bar")
.click()
.get("label > .content-type-wrapper > .content-type option:selected")
.should("have.text", "text/xml")
.get(".body-param__example")
.should("contains.text", "<fooOne>")
})
it("Should render RequestBody example value when schema contains `oneOf` for mediaType `application/xml`", () => {
cy.visit("?url=/documents/features/oas3-xml.json")
.get("#operations-default-post_foobar")
.click()
.get("label > .content-type-wrapper > .content-type option:selected")
.should("have.text", "application/xml")
.get(".body-param__example")
.should("contains.text", "<fooOne>")
})
it("Should render RequestBody example value when schema contains `anyOf` for mediaType `application/xml`", () => {
cy.visit("?url=/documents/features/oas3-xml.json")
.get("#operations-default-post_barfoo")
.click()
.get("label > .content-type-wrapper > .content-type option:selected")
.should("have.text", "application/xml")
.get(".body-param__example")
.should("contains.text", "<fooOne>")
})
it("Should render RequestBody example value when switching mediaType to `text/xml` with singular content schema", () => {
cy.visit("?url=/documents/features/oas3-xml.json")
.get("#operations-default-post_barfoo")
.click()
.get("label > .content-type-wrapper > .content-type")
.select("text/xml")
.get(".body-param__example")
.should("contains.text", "<fooThree>")
})
it("Should render RequestBody example value when switching mediaType to `application/xml` with singular content schema", () => {
cy.visit("?url=/documents/features/oas3-xml.json")
.get("#operations-default-post_foo")
.click()
.get("label > .content-type-wrapper > .content-type")
.select("application/xml")
.get(".body-param__example")
.should("contains.text", "<fooTwo>")
})
it("Should render Response example value for mediaType `application/xml`", () => {
cy.visit("?url=/documents/features/oas3-xml.json")
.get("#operations-default-post_foo")
.click()
.get(".response-col_description > .model-example")
.should("contains.text", "<foobarResObj>")
})
it("Should render Response example value for mediaType `text/xml`", () => {
cy.visit("?url=/documents/features/oas3-xml.json")
.get("#operations-default-post_foobar")
.click()
.get(".response-col_description > .model-example")
.should("contains.text", "<foobarResObj>")
})
})

View File

@ -0,0 +1,66 @@
describe("OAuth2 Application flow", function() {
beforeEach(() => {
cy.server()
cy.route({
url: "**/oauth/*",
method: "POST"
}).as("tokenRequest")
})
// https://github.com/swagger-api/swagger-ui/issues/6395
it("should have first authorization input autofocused", () => {
cy
.visit("/?url=http://localhost:3231/swagger.yaml")
.get(".btn.authorize")
.click()
cy.focused()
.should("have.id", "oauth_username")
})
it("should make an application flow Authorization header request", () => {
cy
.visit("/?url=http://localhost:3231/swagger.yaml")
.get(".btn.authorize")
.click()
.get("div.modal-ux-content > div:nth-child(2)").within(() => {
cy.get("#client_id")
.clear()
.type("confidentialApplication")
.get("#client_secret")
.clear()
.type("topSecret")
.get("button.btn.modal-btn.auth.authorize.button")
.click()
})
cy.get("button.close-modal")
.click()
.get("#operations-default-get_application")
.click()
.get(".btn.try-out__btn")
.click()
.get(".btn.execute")
.click()
cy.get("@tokenRequest")
.its("request")
.its("body")
.should("equal", "grant_type=client_credentials")
cy.get("@tokenRequest")
.its("request")
.its("headers")
.its("authorization")
.should("equal", "Basic Y29uZmlkZW50aWFsQXBwbGljYXRpb246dG9wU2VjcmV0")
.get(".live-responses-table .response-col_status")
.contains("200")
})
})

View File

@ -0,0 +1,122 @@
describe("OAuth2 Password flow", function() {
beforeEach(() => {
cy.server()
cy.route({
url: "**/oauth/*",
method: "POST"
}).as("tokenRequest")
})
it("should make a password flow Authorization header request", () => {
cy
.visit("/?url=http://localhost:3231/swagger.yaml")
.get(".btn.authorize")
.click()
.get("#oauth_username")
.type("swagger")
.get("#oauth_password")
.type("password")
.get("#password_type")
.select("basic")
.get("#client_id")
.clear()
.type("application")
.get("#client_secret")
.clear()
.type("secret")
.get("div.modal-ux-content > div:nth-child(1) > div > div:nth-child(2) > div > div.auth-btn-wrapper > button.btn.modal-btn.auth.authorize.button")
.click()
.get("button.close-modal")
.click()
.get("#operations-default-get_password")
.click()
.get(".btn.try-out__btn")
.click()
.get(".btn.execute")
.click()
cy.get("@tokenRequest")
.its("request")
.its("body")
.should("include", "grant_type=password")
.should("include", "username=swagger")
.should("include", "password=password")
.should("not.include", "client_id")
.should("not.include", "client_secret")
cy.get("@tokenRequest")
.its("request")
.its("headers")
.its("authorization")
.should("equal", "Basic YXBwbGljYXRpb246c2VjcmV0")
.get(".live-responses-table .response-col_status")
.contains("200")
})
it("should make a Password flow request-body request", () => {
cy
.visit("/?url=http://localhost:3231/swagger.yaml")
.get(".btn.authorize")
.click()
.get("#oauth_username")
.type("swagger")
.get("#oauth_password")
.type("password")
.get("#password_type")
.select("request-body")
.get("#client_id")
.clear()
.type("application")
.get("#client_secret")
.clear()
.type("secret")
.get("div.modal-ux-content > div:nth-child(1) > div > div:nth-child(2) > div > div.auth-btn-wrapper > button.btn.modal-btn.auth.authorize.button")
.click()
.get("button.close-modal")
.click()
.get("#operations-default-get_password")
.click()
.get(".btn.try-out__btn")
.click()
.get(".btn.execute")
.click()
cy.get("@tokenRequest")
.its("request")
.its("body")
.should("include", "grant_type=password")
.should("include", "username=swagger")
.should("include", "password=password")
.should("include", "client_id=application")
.should("include", "client_secret=secret")
cy.get("@tokenRequest")
.its("request")
.its("headers")
.should("not.have.property", "authorization")
.get(".live-responses-table .response-col_status")
.contains("200")
})
})

View File

@ -0,0 +1,10 @@
describe("Parameter - Invalid definition with missing array 'items' (#7375)", () => {
it("should render gracefully with fallback to default value", () => {
cy.visit("/?url=/documents/features/parameter-array-missing-items.yaml")
.get("#operations-default-get_example1")
.click()
.get("tbody > tr > .parameters-col_description textarea")
.should("exist")
.should("contains.text", "{}")
})
})

View File

@ -0,0 +1,30 @@
describe("Parameter order", () => {
it("should be well ordered", () => {
cy.visit("/?url=/documents/features/parameter-order.yaml")
.get("#operations-default-post_test__id__related__relatedId_")
.click()
.get(".parameters > tbody")
.children()
.each((tr, i, arr) => {
const parameterTableRows = Array.from(arr)
expect(tr).to.have.attr("data-param-in")
if (i === 0) {
return
}
const inValue = tr[0].getAttribute("data-param-in")
if (!inValue) {
return
}
const beforeInValue = parameterTableRows[i - 1].getAttribute("data-param-in")
const sameAsBefore = beforeInValue === inValue
if (sameAsBefore) {
expect(parameterTableRows[i - 1]).to.have.attr("data-param-in", inValue)
return
}
for (let x = i + 1; x < parameterTableRows.length; x++) {
expect(parameterTableRows[x]).to.not.have.attr("data-param-in", beforeInValue)
}
})
})
})

View File

@ -0,0 +1,23 @@
describe("Loading specs by url.primaryName param", () => {
describe("with no param", () => {
it("should load the default spec", () => {
cy.visit("/pages/multiple-urls/index.html")
.get("span.url")
.contains("/documents/petstore-expanded.openapi.yaml")
})
})
describe("with an invalid param", () => {
it("should fall back to the default spec", () => {
cy.visit("/pages/multiple-urls/index.html?urls.primaryName=undefinedUrlName")
.get("span.url")
.contains("/documents/petstore-expanded.openapi.yaml")
})
})
describe("with a valid url.primaryName param", () => {
it("should render the requested spec", () => {
cy.visit("/pages/multiple-urls/index.html?urls.primaryName=Petstore Swagger")
.get("span.url")
.contains("/documents/petstore.swagger.yaml")
})
})
})

View File

@ -0,0 +1,114 @@
/**
* @prettier
*/
describe("OpenAPI 3.0 Request Body upload file button", () => {
describe("application/octet-stream", () => {
it("should display description with the correct content type", () => {
cy.visit("/?url=/documents/features/request-body-upload-file.yaml")
.get("#operations-default-uploadApplicationOctetStream")
.click()
.get(".opblock-section-request-body .opblock-description-wrapper i")
.should("have.text", "Example values are not available for application/octet-stream media types.")
})
it("should display a file upload button", () => {
cy.visit("/?url=/documents/features/request-body-upload-file.yaml")
.get("#operations-default-uploadApplicationOctetStream")
.click()
.get(".try-out__btn")
.click()
.get(".opblock-section-request-body .opblock-description-wrapper input")
.should("have.prop", "type", "file")
})
})
describe("image/png", () => {
it("should display description with the correct content type", () => {
cy.visit("/?url=/documents/features/request-body-upload-file.yaml")
.get("#operations-default-uploadImagePng")
.click()
.get(".opblock-section-request-body .opblock-description-wrapper i")
.should("have.text", "Example values are not available for image/png media types.")
})
it("should display a file upload button", () => {
cy.visit("/?url=/documents/features/request-body-upload-file.yaml")
.get("#operations-default-uploadApplicationOctetStream")
.click()
.get(".try-out__btn")
.click()
.get(".opblock-section-request-body .opblock-description-wrapper input")
.should("have.prop", "type", "file")
})
})
describe("audio/wav", () => {
it("should display description with the correct content type", () => {
cy.visit("/?url=/documents/features/request-body-upload-file.yaml")
.get("#operations-default-uploadAudioWav")
.click()
.get(".opblock-section-request-body .opblock-description-wrapper i")
.should("have.text", "Example values are not available for audio/wav media types.")
})
it("should display a file upload button", () => {
cy.visit("/?url=/documents/features/request-body-upload-file.yaml")
.get("#operations-default-uploadApplicationOctetStream")
.click()
.get(".try-out__btn")
.click()
.get(".opblock-section-request-body .opblock-description-wrapper input")
.should("have.prop", "type", "file")
})
})
describe("video/mpeg", () => {
it("should display description with the correct content type", () => {
cy.visit("/?url=/documents/features/request-body-upload-file.yaml")
.get("#operations-default-uploadVideoMpeg")
.click()
.get(".opblock-section-request-body .opblock-description-wrapper i")
.should("have.text", "Example values are not available for video/mpeg media types.")
})
it("should display a file upload button", () => {
cy.visit("/?url=/documents/features/request-body-upload-file.yaml")
.get("#operations-default-uploadApplicationOctetStream")
.click()
.get(".try-out__btn")
.click()
.get(".opblock-section-request-body .opblock-description-wrapper input")
.should("have.prop", "type", "file")
})
})
describe("schema format binary", () => {
it("should display description with the correct content type", () => {
cy.visit("/?url=/documents/features/request-body-upload-file.yaml")
.get("#operations-default-uploadSchemaFormatBinary")
.click()
.get(".opblock-section-request-body .opblock-description-wrapper i")
.should("have.text", "Example values are not available for application/x-custom media types.")
})
it("should display a file upload button", () => {
cy.visit("/?url=/documents/features/request-body-upload-file.yaml")
.get("#operations-default-uploadSchemaFormatBinary")
.click()
.get(".try-out__btn")
.click()
.get(".opblock-section-request-body .opblock-description-wrapper input")
.should("have.prop", "type", "file")
})
})
describe("schema format base64", () => {
it("should display description with the correct content type", () => {
cy.visit("/?url=/documents/features/request-body-upload-file.yaml")
.get("#operations-default-uploadSchemaFormatBase64")
.click()
.get(".opblock-section-request-body .opblock-description-wrapper i")
.should("have.text", "Example values are not available for application/x-custom media types.")
})
it("should display a file upload button", () => {
cy.visit("/?url=/documents/features/request-body-upload-file.yaml")
.get("#operations-default-uploadSchemaFormatBinary")
.click()
.get(".try-out__btn")
.click()
.get(".opblock-section-request-body .opblock-description-wrapper input")
.should("have.prop", "type", "file")
})
})
})

View File

@ -0,0 +1,49 @@
describe("Response extension feature", () => {
describe("in Swagger 2", () => {
const swagger2BaseUrl = "/?showExtensions=true&docExpansion=full&url=/documents/features/response-extension.swagger.yaml"
describe("without x- values", () => {
it("should omit response extensions section", () => {
cy.visit(swagger2BaseUrl)
.get("tr.response[data-code='200'] td.response-col_description div.response__extension")
.should("not.exist")
})
})
describe("with x- values", () => {
it("should list each value", () => {
const page = cy.visit(swagger2BaseUrl)
page.get("tr.response[data-code='404'] td.response-col_description div.response__extension:nth-child(2)")
.should("have.text", "x-error: true")
page.get("tr.response[data-code='404'] td.response-col_description div.response__extension:nth-child(3)")
.should("have.text", "x-error-codes: List [ \"NOT_FOUND\" ]")
})
})
})
describe("in OpenAPI 3", () => {
const openAPI3BaseUrl = "/?showExtensions=true&docExpansion=full&url=/documents/features/response-extension.openapi.yaml"
describe("without x- values", () => {
it("should omit response extensions section", () => {
cy.visit(openAPI3BaseUrl)
.get("tr.response[data-code='200'] td.response-col_description div.response__extension")
.should("not.exist")
})
})
describe("with x- values", () => {
it("should list each value", () => {
const page = cy.visit(openAPI3BaseUrl)
page.get("tr.response[data-code='404'] td.response-col_description div.response__extension:nth-child(2)")
.should("have.text", "x-error: true")
page.get("tr.response[data-code='404'] td.response-col_description div.response__extension:nth-child(3)")
.should("have.text", "x-error-codes: List [ \"NOT_FOUND\" ]")
})
})
})
})

View File

@ -0,0 +1,129 @@
/**
* @prettier
*/
describe("JSON Schema Form: Enum & Boolean in a Parameter", () => {
beforeEach(() => {
cy.visit(
"/?url=/documents/features/schema-form-enum-boolean.yaml"
)
.get("#operations-pet-findPetsByStatus")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// @alias Execute Button
cy.get(".execute.opblock-control__btn").as("executeBtn")
// @alias Parameters
cy.get(".opblock-section tbody > tr > .parameters-col_description > select")
.eq(0)
.as("enumIsRequired")
cy.get(".opblock-section tbody > tr > .parameters-col_description > select")
.eq(1)
.as("booleanIsOptional")
cy.get(".opblock-section tbody > tr > .parameters-col_description > select")
.eq(2)
.as("booleanIsRequired")
})
it("should render @enumIsRequired with list of three options", () => {
cy.get("@enumIsRequired")
.should("contains.text", "available")
.should("contains.text", "pending")
.should("contains.text", "sold")
.should("not.contains.text", "--")
.find("option")
.should("have.length", 3)
})
it("should render @booleanIsOptional with default empty string value (display '--')", () => {
cy.get("@booleanIsOptional")
.should("have.value", "")
.should("contains.text", "--")
})
it("should render @booleanIsRequired with default empty string value (display '--')", () => {
cy.get("@booleanIsRequired")
.should("have.value", "")
.should("contains.text", "--")
})
it("should NOT be able to execute with empty @enumIsRequired and @booleanIsRequired values", () => {
// Execute
cy.get("@executeBtn")
.click()
cy.get("@enumIsRequired")
.should("have.class", "invalid")
cy.get("@booleanIsRequired")
.should("have.class", "invalid")
// cURL component
cy.get(".responses-wrapper .curl-command")
.should("not.exist")
})
it("should NOT be able to execute with empty @booleanIsRequired value, but valid @enumIsRequired", () => {
cy.get("@enumIsRequired")
.select("pending")
// Execute
cy.get("@executeBtn")
.click()
cy.get("@enumIsRequired")
.should("not.have.class", "invalid")
cy.get("@booleanIsRequired")
.should("have.class", "invalid")
// cURL component
cy.get(".responses-wrapper .curl-command")
.should("not.exist")
})
it("should NOT be able to execute with empty @enumIsRequired value, but valid @booleanIsRequired", () => {
cy.get("@booleanIsRequired")
.select("false")
// Execute
cy.get("@executeBtn")
.click()
cy.get("@enumIsRequired")
.should("have.class", "invalid")
cy.get("@booleanIsRequired")
.should("not.have.class", "invalid")
// cURL component
cy.get(".responses-wrapper .curl-command")
.should("not.exist")
})
it("should execute, if @booleanIsOptional value is 'false'", () => {
cy.get("@enumIsRequired")
.select("pending")
cy.get("@booleanIsRequired")
.select("false")
cy.get("@booleanIsOptional")
.select("false")
// Execute
cy.get("@executeBtn")
.click()
cy.get("@enumIsRequired")
.should("not.have.class", "invalid")
cy.get("@booleanIsRequired")
.should("not.have.class", "invalid")
.should("not.contains.text", "expectIsOptional")
// cURL component
cy.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("contains.text", "expectIsOptional=false")
})
it("should execute, but NOT send @booleanIsOptional value if not provided", () => {
cy.get("@enumIsRequired")
.select("pending")
cy.get("@booleanIsRequired")
.select("false")
// Execute
cy.get("@executeBtn")
.click()
cy.get("@enumIsRequired")
.should("not.have.class", "invalid")
cy.get("@booleanIsRequired")
.should("not.have.class", "invalid")
.should("not.contains.text", "expectIsOptional")
// cURL component
cy.get(".responses-wrapper .curl-command")
.should("exist")
.get(".responses-wrapper .curl-command span")
.should("not.contains.text", "expectIsOptional")
})
})

View File

@ -0,0 +1,830 @@
/**
* @prettier
*/
describe("OpenAPI 3.0 Additional JsonSchemaForm in a Parameter", () => {
describe("incomplete API definition with missing schema key or schema value(s)", () => {
describe("parameter exists as global", () => {
it("should render when parameter exists as global, but missing schema key", () => {
cy.visit("/?url=/documents/features/schema-form-missing-values.yaml")
.get("#operations-default-get_case_one_no_schema")
.click()
.get(".opblock-description .renderedMarkdown p")
.should("have.text", "sf")
})
it("should render when parameter exists as global, but missing all schema values", () => {
cy.visit("/?url=/documents/features/schema-form-missing-values.yaml")
.get("#operations-default-get_case_one_no_type_or_format")
.click()
.get(".opblock-description .renderedMarkdown p")
.should("have.text", "sf")
})
it("should render when parameter exists as global, schema key exists, but missing schema values: format", () => {
cy.visit("/?url=/documents/features/schema-form-missing-values.yaml")
.get("#operations-default-get_case_one_format_only_no_type")
.click()
.get(".opblock-description .renderedMarkdown p")
.should("have.text", "sf")
})
it("should render when parameter exists as global, schema key exists, but missing schema value: type", () => {
cy.visit("/?url=/documents/features/schema-form-missing-values.yaml")
.get("#operations-default-get_case_one_type_only_no_format")
.click()
.get(".opblock-description .renderedMarkdown p")
.should("have.text", "sf")
})
})
describe("parameter exists in method", () => {
it("should render when parameter exists in method, but missing schema key", () => {
cy.visit("/?url=/documents/features/schema-form-missing-values.yaml")
.get("#operations-default-get_case_two_no_schema")
.click()
.get(".opblock-description .renderedMarkdown p")
.should("have.text", "sf")
})
it("should render when parameter exists in method, schema key exists, but missing all schema values", () => {
cy.visit("/?url=/documents/features/schema-form-missing-values.yaml")
.get("#operations-default-get_case_two_no_type_or_format")
.click()
.get(".opblock-description .renderedMarkdown p")
.should("have.text", "sf")
})
it("should render when parameter exists in method, schema key exists, but missing schema value: format", () => {
cy.visit("/?url=/documents/features/schema-form-missing-values.yaml")
.get("#operations-default-get_case_one_type_only_no_format")
.click()
.get(".opblock-description .renderedMarkdown p")
.should("have.text", "sf")
})
it("should render when parameter exists in method, schema key exists, but missing schema value: type", () => {
cy.visit("/?url=/documents/features/schema-form-missing-values.yaml")
.get("#operations-default-get_case_one_format_only_no_type")
.click()
.get(".opblock-description .renderedMarkdown p")
.should("have.text", "sf")
})
})
})
describe("/Array", () => {
describe("in a Parameter", () => {
it("should allow modification of values in Try-It-Out", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
.get(".parameters-col_description .examples-select > select")
.select("ArrayExampleB")
// Add a new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > input")
.type("{selectall}5")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"1",
"2",
"3",
"4",
"5",
])
})
.get(".parameters-col_description .examples-select > select")
.find(":selected")
.should("have.text", "[Modified value]")
})
it("should allow removal of added value in Try-It-Out", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
.get(".parameters-col_description .examples-select > select")
.select("ArrayExampleB")
// Add a new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > input")
.type("{selectall}5")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"1",
"2",
"3",
"4",
"5",
])
})
.get(".parameters-col_description .examples-select > select")
.find(":selected")
.should("have.text", "[Modified value]")
// Remove the last item that was just added
.get(
".json-schema-form-item:last-of-type > .json-schema-form-item-remove"
)
.click()
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"1",
"2",
"3",
"4",
])
})
})
it("should allow removal of nth of values in Try-It-Out", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
.get(".parameters-col_description .examples-select > select")
.select("ArrayExampleB")
// Add a new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > input")
.type("{selectall}5")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"1",
"2",
"3",
"4",
"5",
])
})
.get(".parameters-col_description .examples-select > select")
.find(":selected")
.should("have.text", "[Modified value]")
// Remove the second item in list
.get(
".json-schema-form-item:nth-child(2) > .json-schema-form-item-remove"
)
.click()
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"1",
"3",
"4",
"5",
])
})
})
it("should allow execution of operation in Try-It-Out", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
.get(".parameters-col_description .examples-select > select")
.select("ArrayExampleB")
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
})
it("should add empty item and allow execution of operation in Try-It-Out", () => {
cy.visit(
"/?url=/documents/features/multiple-examples-core.openapi.yaml"
)
.get("#operations-default-post_Array")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
.get(".parameters-col_description .examples-select > select")
.select("ArrayExampleB")
// Add a new item
.get(".json-schema-form-item-add")
.click()
// Execute without prior typing a value
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
})
})
})
describe("Petstore", () => {
describe("/pet/findByStatus", () => {
it("should render the operation, execute with default value", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-default-findPetsByStatus")
.click()
// Expand operation
.get(".opblock-title span")
.should("have.text", "Parameters")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "available")
})
it("should render the operation, modify value, and execute with modified value", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-default-findPetsByStatus")
.click()
// Expand operation
.get(".opblock-title span")
.should("have.text", "Parameters")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Select
.get(".parameters-col_description > select")
.select("pending")
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "pending")
})
})
describe("/pet/findByTags", () => {
it("should allow modification of values in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-pet-findPetsByTags")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Add a new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item > input")
.type("{selectall}spotted")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"spotted",
])
})
})
it("should allow removal of added value in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-pet-findPetsByTags")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Add a new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > input")
.type("{selectall}spotted")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"spotted",
])
})
// Remove the last item that was just added
.get(
".json-schema-form-item:last-of-type > .json-schema-form-item-remove"
)
.click()
.get(".json-schema-form-item > input")
.should("not.exist")
})
it("should allow removal of nth of values in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-pet-findPetsByTags")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Add a new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > input")
.type("{selectall}spotted")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"spotted",
])
})
// Add a 2nd new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > input")
.type("{selectall}large")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"spotted",
"large",
])
})
// Add a 3rd new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > input")
.type("{selectall}puppy")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"spotted",
"large",
"puppy",
])
})
// Remove the second item in list
.get(
".json-schema-form-item:nth-child(2) > .json-schema-form-item-remove"
)
.click()
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"spotted",
"puppy",
])
})
})
it("should allow execution of operation without modifications in Try-It-Out (debounce)", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-pet-findPetsByTags")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "findByTags")
})
it("should add empty item and allow execution of operation in Try-It-Out (debounce)", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-pet-findPetsByTags")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Add a new item
.get(".json-schema-form-item-add")
.click()
// Execute without prior typing a value
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "findByTags")
})
it("should add modified item and allow execution of operation in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-pet-findPetsByTags")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Add a new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item > input")
.type("{selectall}spotted")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"spotted",
])
})
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "spotted")
})
it("should add 3 modified items, remove the middle child, and allow execution of operation Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-pet-findPetsByTags")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Add a new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > input")
.type("{selectall}spotted")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"spotted",
])
})
// Add a 2nd new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > input")
.type("{selectall}large")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"spotted",
"large",
])
})
// Add a 3rd new item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > input")
.type("{selectall}puppy")
// Assert against the input fields
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"spotted",
"large",
"puppy",
])
})
// Remove the second item in list
.get(
".json-schema-form-item:nth-child(2) > .json-schema-form-item-remove"
)
.click()
.get(".json-schema-form-item > input")
.then((inputs) => {
expect(inputs.map((i, el) => el.value).toArray()).to.deep.equal([
"spotted",
"puppy",
])
})
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "tags=spotted&tags=puppy")
.should("not.have.text", "large")
})
})
describe("/petOwner/{petOwnerId}", () => {
// This is a (GET) debounce test for schema type: string
it("should render the operation, and allow execute of operation with empty value (debounce)", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-getPetOwnerById")
.click()
// Expand operation
.get(".opblock-title span")
.should("have.text", "Parameters")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "petOwner")
})
it("should render the operation, and input field, and allow execute of operation", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-getPetOwnerById")
.click()
// Expand operation
.get(".opblock-title span")
.should("have.text", "Parameters")
// Expand Try It Out
.get(".try-out__btn")
.click()
.get(".parameters-col_description > input")
.type("123")
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "petOwner")
.should("contain.text", "123")
})
})
describe("/petOwner/listOfServiceTrainer", () => {
it("should allow execution of operation with value=true in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-listOfServiceTrainer")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// add 1st item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item > select")
.select("true")
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "tags=true")
})
it("should allow execution of operation with value=false in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-listOfServiceTrainer")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// add 1st item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item > select")
.select("false")
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "tags=false")
})
it("should allow execution of operation with value=true&value=false in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-listOfServiceTrainer")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// add 1st item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item > select")
.select("true")
// add 2nd item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > select")
.select("false")
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "tags=true&tags=false")
})
it("should allow execution of operation with value=false after removing value=true in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-listOfServiceTrainer")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// add 1st item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item > select")
.select("true")
// add 2nd item
.get(".json-schema-form-item-add")
.click()
.get(".json-schema-form-item:last-of-type > select")
.select("false")
// remove 1st item
.get(
".json-schema-form-item:nth-child(1) > .json-schema-form-item-remove"
)
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "tags=false")
})
it("should allow execution of operation with value=(empty) in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-listOfServiceTrainer")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "listOfServiceTrainer")
})
})
describe("/petOwner/findByPreference", () => {
it("should allow execution of operation with value=(empty) in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-findByPreference")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "findByPreference")
})
it("should allow execution of operation with selected value in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-findByPreference")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Select
.get(".parameters-col_description > select")
.select("dog")
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "findByPreference")
.should("contain.text", "dog")
})
it("should allow execution of operation with multiple selected values in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-findByPreference")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Select
.get(".parameters-col_description > select")
.select(["dog", "cat"])
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "findByPreference")
.should("contain.text", "dog")
.should("contain.text", "cat")
})
})
describe("/petOwner/createWithList", () => {
it("should allow execution of operation with default text in textArea in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-petOwnerCreateWithList")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "createWithList")
})
it("should allow execution of operation with cleared textArea in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-petOwnerCreateWithList")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
.get(".body-param__text")
.clear()
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "createWithList")
})
it("should allow execution of operation with modified textArea in Try-It-Out", () => {
cy.visit("/?url=/documents/features/schema-form-core.yaml")
.get("#operations-petOwner-petOwnerCreateWithList")
.click()
// Expand Try It Out
.get(".try-out__btn")
.click()
.get(".body-param__text")
.clear()
// note: adding this much type adds 6+ seconds to test
.type(
`[
{
"id": 10,
"petId": 201,
"petOwnerFirstName": "John",
},
{
"id": 11,
"petId": 201,
"petOwnerFirstName": "Jane",
}
]`
)
.should("contain.text", "Jane")
.should("contain.text", "201")
// Execute
.get(".execute.opblock-control__btn")
.click()
// Expect new element to be visible after Execute
.get(".btn-clear.opblock-control__btn")
.should("have.text", "Clear")
// Compare Request URL
.get(".request-url pre.microlight")
.should("contain.text", "createWithList")
// Compare Curl
.get(".curl")
.should("contain.text", "Jane")
.should("contain.text", "201")
})
})
})
})

View File

@ -0,0 +1,31 @@
/**
* @prettier
*/
describe("Parse YAML as YAML@1.2 with json_schema for all JSON-supported types", () => {
it("should have date string even without quotes", () => {
cy.visit("/?url=/documents/features/spec-parse-to-json.yaml")
.get("#operations-default-get_foo")
.click()
// Responses -> example value tab
.get(".language-json > :nth-child(3)")
.should("have.text", "\"without-quotes\"")
.get(".language-json > :nth-child(5)")
.should("have.text", "\"1999-11-31\"")
// Responses -> schema tab
.get(".model-example > .tab > :nth-child(2)")
.click()
.get(":nth-child(1) > :nth-child(2) > .model > :nth-child(1)")
.click()
.get(
":nth-child(1) > :nth-child(2) > .model > :nth-child(1) > .prop > .property"
) // first element, without-quotes
.should("have.text", "example: 1999-11-31")
.get(":nth-child(2) > :nth-child(2) > .model > :nth-child(1)")
.click()
.get(
":nth-child(2) > :nth-child(2) > .model > :nth-child(1) > .prop > .property"
) // second element, with quotes
.should("have.text", "example: 1999-12-31")
})
})

View File

@ -0,0 +1,40 @@
/**
* @prettier
*/
describe("Syntax Highlighting for JSON value cases", () => {
// expect span contains entire string sample
// fail case is if the string sample gets broken up into segments
// due react-syntax-highlighter attempting to escape characters into multiple segments
describe("OAS 2", () => {
it("should render full syntax highlighted string in Request (param body) example", () => {
cy.visit("/?url=/documents/features/syntax-highlighting-json-oas2.yaml")
.get("#operations-default-post_setServices")
.click()
.get(".body-param__example > .language-json > :nth-child(10)")
.should("have.text", "\"79daf5b4-aa4b-1452-eae5-42c231477ba7\"")
})
it("should render full syntax highlighted string in Response example", () => {
cy.visit("/?url=/documents/features/syntax-highlighting-json-oas2.yaml")
.get("#operations-default-post_setServices")
.click()
.get(".example > .language-json > :nth-child(28)")
.should("have.text", "\"5ff06f632bb165394501b05d3a833355\"")
})
})
describe("OAS 3", () => {
it("should render full syntax highlighted string in Request example", () => {
cy.visit("/?url=/documents/features/syntax-highlighting-json-oas3.yaml")
.get("#operations-default-post_setServices")
.click()
.get(".body-param__example > .language-json > :nth-child(15)")
.should("have.text", "\"22a124b4-594b-4452-bdf5-fc3ef1477ba7\"")
})
it("should render full syntax highlighted string in Response example", () => {
cy.visit("/?url=/documents/features/syntax-highlighting-json-oas3.yaml")
.get("#operations-default-post_setServices")
.click()
.get(".example > .language-json > :nth-child(33)")
.should("have.text", "\"f0009babde9dbe204540d79cf754408e\"")
})
})
})

View File

@ -0,0 +1,22 @@
describe("Try it out enabled configuration", () => {
it("should enable the try it out section when true", () => {
cy
.visit("?tryItOutEnabled=true&url=/documents/features/try-it-out-enabled.yaml")
.get("#operations-default-get_")
.click()
.get(".try-out__btn")
.should("have.text","Cancel")
})
it("should disable the try it out section when false", () => {
cy
.visit("?tryItOutEnabled=false&url=/documents/features/try-it-out-enabled.yaml")
.get("#operations-default-get_")
.click()
.get(".try-out__btn")
.should("have.text","Try it out ")
})
})

View File

@ -0,0 +1,15 @@
describe("Try It Out: schema required properties can be overridden", () => {
it("should execute", () => {
cy
.visit("?tryItOutEnabled=true&url=/documents/features/try-it-out-schema-required-override-allowed.yaml")
.get("#operations-default-setDeliveryLocation")
.click()
.get(".body-param__text")
.should("include.value", "testProperty")
.clear() // swagger-ui will auto insert "{}" into textarea
.get(".execute-wrapper > .btn")
.click()
.get(".curl-command")
.should("exist")
})
})

View File

@ -0,0 +1,111 @@
describe("configuration options: `urls` and `urls.primaryName`", () => {
describe("`urls` only", () => {
it("should render a list of URLs correctly", () => {
cy.visit("/?configUrl=/configs/urls.yaml")
.get("select")
.children()
.should("have.length", 2)
.get("select > option")
.eq(0)
.should("have.text", "One")
.should("have.attr", "value", "/documents/features/urls/1.yaml")
.get("select > option")
.eq(1)
.should("have.text", "Two")
.should("have.attr", "value", "/documents/features/urls/2.yaml")
})
it("should render the first URL in the list", () => {
cy.visit("/?configUrl=/configs/urls.yaml")
.get("h2.title")
.should("have.text", "One")
.window()
.then(win => win.ui.specSelectors.url())
.should("equal", "/documents/features/urls/1.yaml")
})
})
it("should respect a `urls.primaryName`", () => {
cy.visit("/?configUrl=/configs/urls-primary-name.yaml")
.get("select")
.should("have.value", "/documents/features/urls/2.yaml")
.get("h2.title")
.should("have.text", "Two")
.window()
.then(win => win.ui.specSelectors.url())
.should("equal", "/documents/features/urls/2.yaml")
})
})
describe("urls with server variables", () => {
it("should compute a url and default server variables", () => {
cy.visit("/?configUrl=/configs/urls-server-variables.yaml")
.get("code")
.should("have.text", "https://localhost:3200/oneFirstUrl")
.get("tr > :nth-child(1)")
.should("have.text", "basePath")
.get("input")
.should("have.value", "/oneFirstUrl")
})
it("should change server variables", () => {
cy.visit("/?configUrl=/configs/urls-server-variables.yaml")
.get("code")
.should("have.text", "https://localhost:3200/oneFirstUrl")
.get("tr > :nth-child(1)")
.should("have.text", "basePath")
.get("input")
.should("have.value", "/oneFirstUrl")
.get(".servers > label > select")
.eq(0)
.select(1)
.get("input")
.should("have.value", "/oneSecondUrl")
})
it("should select and compute second url", () => {
cy.visit("/?configUrl=/configs/urls-server-variables.yaml")
.get("select > option")
.eq(1)
.should("have.text", "Two")
.get("select")
.eq(0)
.select(1)
.get("code")
.should("have.text", "https://localhost:3200/twoFirstUrl")
.get("input")
.should("have.value", "/twoFirstUrl")
})
it("should select second url, then toggle back to first url", () => {
cy.visit("/?configUrl=/configs/urls-server-variables.yaml")
.get("select > option")
.get("select")
.eq(0)
.select(1)
.get("input")
.should("have.value", "/twoFirstUrl")
// toggle url back
.get("select")
.eq(0)
.select(0)
.get("code")
.should("have.text", "https://localhost:3200/oneFirstUrl")
.get("input")
.should("have.value", "/oneFirstUrl")
})
it("should change server variables, then select second url, and maintain server variables index", () => {
cy.visit("/?configUrl=/configs/urls-server-variables.yaml")
.get(".servers > label >select")
.eq(0)
.select(1)
.get("input")
.should("have.value", "/oneSecondUrl")
// change url
.get("select > option")
.get("select")
.eq(0)
.select(1)
.get("input")
.should("have.value", "/twoSecondUrl")
.get("input")
.should("have.value", "/twoSecondUrl")
})
})

View File

@ -0,0 +1,22 @@
describe("#6767: Operation should be considered anonymous if its security only includes empty object (this was decided by implementation choice and may change or be extended in the future)", () => {
it("Should consider method anonymous if security contains only empty object", () => {
cy
.visit("/?url=/documents/security/anonymous.yaml")
.get("#operations-default-get_onlyEmpty .authorization__btn")
.should("not.exist")
})
it("Should consider method as secured if security contains no empty object", () => {
cy
.visit("/?url=/documents/security/anonymous.yaml")
.get("#operations-default-get_required .authorization__btn")
.should("exist")
})
it("Should consider method as secured if security contains empty object but has at least one more security defined", () => {
cy
.visit("/?url=/documents/security/anonymous.yaml")
.get("#operations-default-get_withBoth .authorization__btn")
.should("exist")
})
})

View File

@ -0,0 +1,23 @@
describe("XSS: OAuth2 authorizationUrl sanitization", () => {
it("should filter out a javascript URL", () => {
cy.visit("/?url=/documents/security/xss-oauth2.yaml")
.window()
.then(win => {
let args = null
const stub = cy.stub(win, "open", (...callArgs) => {
args = callArgs
}).as("windowOpen")
cy.get(".authorize")
.click()
.get(".modal-btn.authorize")
.click()
.wait(100)
.then(() => {
console.log(args)
expect(args[0]).to.match(/^about:blank/)
})
})
})
})

View File

@ -0,0 +1,58 @@
describe("Security: CSS Sequential Import Chaining", () => {
describe("in OpenAPI 3.0", () => {
describe("CSS Injection via Markdown", () => {
it("should filter <style> tags out of Markdown fields", () => {
cy.visit("/?url=/documents/security/sequential-import-chaining/openapi.yaml")
.get("div.information-container")
.should("exist")
.and("not.have.descendants", "style")
})
it("should not apply `@import`ed CSS stylesheets", () => {
cy.visit("/?url=/documents/security/sequential-import-chaining/openapi.yaml")
.wait(500) // HACK: wait for CSS import to settle
.get("div.info h4")
.should("have.length", 1)
.and("not.be.hidden")
})
})
describe("Value Exfiltration via CSS", () => {
it("should not allow OAuth credentials to be visible via HTML `value` attribute", () => {
cy.visit("/?url=/documents/petstore-expanded.openapi.yaml")
.get(".scheme-container > .schemes > .auth-wrapper > .btn > span")
.click()
.get("div > div > .wrapper > .block-tablet > #client_id")
.clear()
.type("abc")
.should("not.have.attr", "value", "abc")
})
})
})
describe("in Swagger 2.0", () => {
describe("CSS Injection via Markdown", () => {
it("should filter <style> tags out of Markdown fields", () => {
cy.visit("/?url=/documents/security/sequential-import-chaining/swagger.yaml")
.get("div.information-container")
.should("exist")
.and("not.have.descendants", "style")
})
it("should not apply `@import`ed CSS stylesheets", () => {
cy.visit("/?url=/documents/security/sequential-import-chaining/swagger.yaml")
.wait(500) // HACK: wait for CSS import to settle
.get("div.info h4")
.should("have.length", 1)
.and("not.be.hidden")
})
})
describe("Value Exfiltration via CSS", () => {
it("should not allow OAuth credentials to be visible via HTML `value` attribute", () => {
cy.visit("/?url=/documents/petstore.swagger.yaml")
.get(".scheme-container > .schemes > .auth-wrapper > .btn > span")
.click()
.get("div > div > .wrapper > .block-tablet > #client_id")
.clear()
.type("abc")
.should("not.have.attr", "value", "abc")
})
})
})
})