From 1791759de58a6165d431670691bd7a88531d57f5 Mon Sep 17 00:00:00 2001 From: James ZHANG Date: Fri, 19 Oct 2018 05:55:30 +0800 Subject: [PATCH] improve(deeplink): support utf16 tags and IDs (via #4921) * ref #3958, support utf16 fragments on the deeplink plugin * put -> head for UTF16 operation this is a temporary fix, eventually we will run out of methods and need to use a new targeting strategy * drop obsolete %20 decoder * add full test suite for UTF16 operation * use encodeURIComponent when setting hash * drop obsolete test cases --- src/core/plugins/deep-linking/index.js | 3 +- src/core/plugins/deep-linking/layout.js | 6 +- .../features/deep-linking.openapi.yaml | 8 +++ .../features/deep-linking.swagger.yaml | 8 +-- test/e2e-cypress/tests/deep-linking.js | 70 +++++++++++++++++++ 5 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/core/plugins/deep-linking/index.js b/src/core/plugins/deep-linking/index.js index ebfe2d8d..8c034436 100644 --- a/src/core/plugins/deep-linking/index.js +++ b/src/core/plugins/deep-linking/index.js @@ -9,7 +9,8 @@ export default function() { wrapActions: { loaded: (ori, system) => (...args) => { ori(...args) - const hash = window.location.hash + // location.hash was an UTF-16 String, here is required UTF-8 + const hash = decodeURIComponent(window.location.hash) system.layoutActions.parseDeepLinkHash(hash) } } diff --git a/src/core/plugins/deep-linking/layout.js b/src/core/plugins/deep-linking/layout.js index 0eefa8e7..659a1299 100644 --- a/src/core/plugins/deep-linking/layout.js +++ b/src/core/plugins/deep-linking/layout.js @@ -32,9 +32,9 @@ export const show = (ori, { getConfigs, layoutSelectors }) => (...args) => { } if (urlHashArray.length === 2) { - setHash(createDeepLinkPath(`/${type}/${assetName}`)) + setHash(createDeepLinkPath(`/${encodeURIComponent(type)}/${encodeURIComponent(assetName)}`)) } else if (urlHashArray.length === 1) { - setHash(createDeepLinkPath(`/${type}`)) + setHash(createDeepLinkPath(`/${encodeURIComponent(type)}`)) } } catch (e) { @@ -73,7 +73,7 @@ export const parseDeepLinkHash = (rawHash) => ({ layoutActions, layoutSelectors, hash = hash.slice(1) } - const hashArray = hash.split("/").map(val => (val || "").replace(/%20/g, " ")) + const hashArray = hash.split("/").map(val => (val || "")) const isShownKey = layoutSelectors.isShownKeyFromUrlHashArray(hashArray) diff --git a/test/e2e-cypress/static/documents/features/deep-linking.openapi.yaml b/test/e2e-cypress/static/documents/features/deep-linking.openapi.yaml index 036f818c..0f7ef860 100644 --- a/test/e2e-cypress/static/documents/features/deep-linking.openapi.yaml +++ b/test/e2e-cypress/static/documents/features/deep-linking.openapi.yaml @@ -25,6 +25,14 @@ paths: application/json: schema: type: object + /utf16fragments: + head: + operationId: "пошел" + tags: ["шеллы"] + summary: an operation + responses: + "200": + description: ok /withUnderscores: patch: operationId: "underscore_Operation" diff --git a/test/e2e-cypress/static/documents/features/deep-linking.swagger.yaml b/test/e2e-cypress/static/documents/features/deep-linking.swagger.yaml index 60a085c7..7395f4e3 100644 --- a/test/e2e-cypress/static/documents/features/deep-linking.swagger.yaml +++ b/test/e2e-cypress/static/documents/features/deep-linking.swagger.yaml @@ -17,6 +17,10 @@ paths: responses: "200": description: ok + /utf16fragments: + head: + operationId: "пошел" + tags: ["шеллы"] /withUnderscores: patch: operationId: "underscore_Operation" @@ -28,7 +32,3 @@ paths: /noOperationId: put: tags: ["tagTwo"] - summary: an operation - responses: - "200": - description: ok diff --git a/test/e2e-cypress/tests/deep-linking.js b/test/e2e-cypress/tests/deep-linking.js index c2873fb6..58f3c252 100644 --- a/test/e2e-cypress/tests/deep-linking.js +++ b/test/e2e-cypress/tests/deep-linking.js @@ -114,6 +114,41 @@ describe("Deep linking feature", () => { }) }) + describe("Operation with UTF-16 characters", () => { + const elementToGet = ".opblock-head" + const correctElementId = "operations-шеллы-пошел" + const correctFragment = "#/%D1%88%D0%B5%D0%BB%D0%BB%D1%8B/%D0%BF%D0%BE%D1%88%D0%B5%D0%BB" + const correctHref = "#/шеллы/пошел" + + it("should generate a correct element ID", () => { + cy.get(elementToGet) + .should("have.id", correctElementId) + }) + + it("should add the correct element fragment to the URL when expanded", () => { + cy.get(elementToGet) + .click() + .window() + .should("have.deep.property", "location.hash", correctFragment) + }) + + it("should provide an anchor link that has the correct fragment as href", () => { + cy.get(elementToGet) + .find("a") + .should("have.attr", "href", correctHref) + .click() + .should("have.attr", "href", correctHref) // should be valid after expanding + + }) + + it("should expand the operation when reloaded", () => { + cy.visit(`${baseUrl}${correctFragment}`) + .reload() + .get(`${elementToGet}.is-open`) + .should("exist") + }) + }) + describe("Operation with no operationId", () => { const elementToGet = ".opblock-put" const correctElementId = "operations-tagTwo-put_noOperationId" @@ -276,6 +311,41 @@ describe("Deep linking feature", () => { }) }) + describe("Operation with UTF-16 characters", () => { + const elementToGet = ".opblock-head" + const correctElementId = "operations-шеллы-пошел" + const correctFragment = "#/%D1%88%D0%B5%D0%BB%D0%BB%D1%8B/%D0%BF%D0%BE%D1%88%D0%B5%D0%BB" + const correctHref = "#/шеллы/пошел" + + it("should generate a correct element ID", () => { + cy.get(elementToGet) + .should("have.id", correctElementId) + }) + + it("should add the correct element fragment to the URL when expanded", () => { + cy.get(elementToGet) + .click() + .window() + .should("have.deep.property", "location.hash", correctFragment) + }) + + it("should provide an anchor link that has the correct fragment as href", () => { + cy.get(elementToGet) + .find("a") + .should("have.attr", "href", correctHref) + .click() + .should("have.attr", "href", correctHref) // should be valid after expanding + + }) + + it("should expand the operation when reloaded", () => { + cy.visit(`${baseUrl}${correctFragment}`) + .reload() + .get(`${elementToGet}.is-open`) + .should("exist") + }) + }) + describe("Operation with no operationId", () => { const elementToGet = ".opblock-put" const correctElementId = "operations-tagTwo-put_noOperationId"