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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/core/plugins/deep-linking/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,17 @@ export const parseDeepLinkHash = (rawHash) => ({ layoutActions, layoutSelectors,
hash = hash.slice(1)
}

if(hash[0] === "/") {
// "/pet/addPet" => "pet/addPet"
// makes the split result cleaner
// also handles forgotten leading slash
hash = hash.slice(1)
if(hash[0] !== "/") {
// Hash is not a Swagger UI deep link (which are always rooted at "/").
// Treat it as an external/native anchor (e.g. "#model-Category") and
// leave the browser to handle scrolling. See #10527.
return
}

// "/pet/addPet" => "pet/addPet"
// makes the split result cleaner
hash = hash.slice(1)

const hashArray = hash.split("/").map(val => (val || ""))

const isShownKey = layoutSelectors.isShownKeyFromUrlHashArray(hashArray)
Expand Down
22 changes: 22 additions & 0 deletions test/e2e-cypress/e2e/bugs/10527.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
describe("#10527: External links to swagger-ui anchors don't work", () => {
const baseUrl = "/?deepLinking=true&url=/documents/bugs/10527.yaml"

it("should not rewrite a hash anchor that targets a Model panel id", () => {
cy.visit(`${baseUrl}#model-Category`)
// give the deep-linking parser a chance to run
.get("#model-Category")
.should("exist")
cy.location().should((loc) => {
expect(loc.hash).to.eq("#model-Category")
})
})

it("should still expand a deep-link rooted at '/' for an operation", () => {
cy.visit(`${baseUrl}#/pets/listPets`)
.get("#operations-pets-listPets.is-open")
.should("exist")
cy.location().should((loc) => {
expect(loc.hash).to.eq("#/pets/listPets")
})
})
})
33 changes: 33 additions & 0 deletions test/e2e-cypress/static/documents/bugs/10527.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
openapi: "3.0.4"
info:
title: Bug 10527 - external anchors should not be rewritten as deep links
version: "1.0"
paths:
/pets:
get:
operationId: "listPets"
tags: ["pets"]
summary: list pets
responses:
"200":
description: ok
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
components:
schemas:
Pet:
type: object
properties:
id:
type: integer
name:
type: string
Category:
type: object
properties:
id:
type: integer
name:
type: string
95 changes: 95 additions & 0 deletions test/unit/core/plugins/deep-linking/layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* @prettier
*/

import { parseDeepLinkHash } from "core/plugins/deep-linking/layout"

describe("deep-linking plugin - parseDeepLinkHash", () => {
const makeSystem = ({ deepLinking = true } = {}) => {
const show = jest.fn()
const scrollTo = jest.fn()
return {
system: {
getConfigs: () => ({ deepLinking }),
layoutActions: { show, scrollTo },
layoutSelectors: {
isShownKeyFromUrlHashArray: (hashArray) => {
const [tag, operationId] = hashArray
if (operationId) {
return ["operations", tag, operationId]
} else if (tag) {
return ["operations-tag", tag]
}
return []
},
},
},
show,
scrollTo,
}
}

it("does not parse the hash when deepLinking is disabled", () => {
const { system, show, scrollTo } = makeSystem({ deepLinking: false })
parseDeepLinkHash("#/myTag/myOperation")(system)
expect(show).not.toHaveBeenCalled()
expect(scrollTo).not.toHaveBeenCalled()
})

it("does nothing when the hash is empty", () => {
const { system, show, scrollTo } = makeSystem()
parseDeepLinkHash("")(system)
expect(show).not.toHaveBeenCalled()
expect(scrollTo).not.toHaveBeenCalled()
})

it("expands a tag deep link rooted at '/'", () => {
const { system, show, scrollTo } = makeSystem()
parseDeepLinkHash("#/myTag")(system)
expect(show).toHaveBeenLastCalledWith(["operations-tag", "myTag"], true)
expect(scrollTo).toHaveBeenCalledWith(["operations-tag", "myTag"])
})

it("expands an operation deep link rooted at '/'", () => {
const { system, show, scrollTo } = makeSystem()
parseDeepLinkHash("#/myTag/myOperation")(system)
expect(show).toHaveBeenCalledWith(["operations-tag", "myTag"], true)
expect(show).toHaveBeenLastCalledWith(
["operations", "myTag", "myOperation"],
true
)
expect(scrollTo).toHaveBeenCalledWith([
"operations",
"myTag",
"myOperation",
])
})

it("expands a deep link with the legacy '!/' shebang prefix", () => {
const { system, show, scrollTo } = makeSystem()
parseDeepLinkHash("#!/myTag/myOperation")(system)
expect(show).toHaveBeenLastCalledWith(
["operations", "myTag", "myOperation"],
true
)
expect(scrollTo).toHaveBeenCalledWith([
"operations",
"myTag",
"myOperation",
])
})

it("ignores a native anchor hash that is not rooted at '/' (regression for #10527)", () => {
const { system, show, scrollTo } = makeSystem()
parseDeepLinkHash("#model-Category")(system)
expect(show).not.toHaveBeenCalled()
expect(scrollTo).not.toHaveBeenCalled()
})

it("ignores a single-token hash that is not rooted at '/' (regression for #10527)", () => {
const { system, show, scrollTo } = makeSystem()
parseDeepLinkHash("#some-section")(system)
expect(show).not.toHaveBeenCalled()
expect(scrollTo).not.toHaveBeenCalled()
})
})