From 09bcc5b0ff6bad67d0dec5e6ecec5cddc76ff264 Mon Sep 17 00:00:00 2001 From: Kukhyeon Heo Date: Sat, 11 Dec 2021 02:17:03 +0900 Subject: [PATCH] fix (#19262) Co-authored-by: Emily Rohrbough Co-authored-by: Matt Henkes --- .../driver/cypress/fixtures/issue-17512.html | 38 +++++++++++++++++++ .../cypress/integration/issues/17512_spec.js | 16 ++++++++ packages/driver/src/cy/top_attr_guards.ts | 21 +++++++++- 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 packages/driver/cypress/fixtures/issue-17512.html create mode 100644 packages/driver/cypress/integration/issues/17512_spec.js diff --git a/packages/driver/cypress/fixtures/issue-17512.html b/packages/driver/cypress/fixtures/issue-17512.html new file mode 100644 index 0000000000..b73dfe9eef --- /dev/null +++ b/packages/driver/cypress/fixtures/issue-17512.html @@ -0,0 +1,38 @@ + + + + + + + +
+ link 1 +
+
+ +
+ link 2 +
+
+ +
+ link 3 +
+
+ + diff --git a/packages/driver/cypress/integration/issues/17512_spec.js b/packages/driver/cypress/integration/issues/17512_spec.js new file mode 100644 index 0000000000..8afedff275 --- /dev/null +++ b/packages/driver/cypress/integration/issues/17512_spec.js @@ -0,0 +1,16 @@ +describe('issue 17512', () => { + beforeEach(() => { + cy.visit('fixtures/issue-17512.html') + }) + + it('returns null when target is not defined', () => { + cy.get('#link').click() + cy.get('#result').should('have.text', 'null') + + cy.get('#link2').click() + cy.get('#result2').should('have.text', '"_top"') + + cy.get('#link3').click() + cy.get('#result3').should('have.text', 'null') + }) +}) diff --git a/packages/driver/src/cy/top_attr_guards.ts b/packages/driver/src/cy/top_attr_guards.ts index e97607d72c..0471757feb 100644 --- a/packages/driver/src/cy/top_attr_guards.ts +++ b/packages/driver/src/cy/top_attr_guards.ts @@ -8,16 +8,24 @@ const invalidTargets = new Set(['_parent', '_top']) */ export function handleInvalidEventTarget (e: Event & {target: HTMLFormElement | HTMLAnchorElement}) { let targetValue = e.target.target + let targetSet = e.target.hasAttribute('target') if (invalidTargets.has(e.target.target)) { e.target.target = '' } - const { getAttribute, setAttribute } = e.target + const { getAttribute, setAttribute, removeAttribute } = e.target const targetDescriptor = Object.getOwnPropertyDescriptor(e.target, 'target') e.target.getAttribute = function (k) { if (k === 'target') { + // https://github.com/cypress-io/cypress/issues/17512 + // When the target attribute doesn't exist, it should return null. + // @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute#non-existing_attributes + if (!targetSet) { + return null + } + return targetValue } @@ -26,6 +34,7 @@ export function handleInvalidEventTarget (e: Event & {target: HTMLFormElement | e.target.setAttribute = function (k, v) { if (k === 'target') { + targetSet = true targetValue = v return $elements.callNativeMethod(this, 'setAttribute', 'cyTarget', v) @@ -34,6 +43,16 @@ export function handleInvalidEventTarget (e: Event & {target: HTMLFormElement | return setAttribute.call(this, k, v) } + e.target.removeAttribute = function (k) { + if (k === 'target') { + targetSet = false + targetValue = '' + + // We're not using `$elements.callNativeMethod` here because it disallows `removeAttribute`. + return removeAttribute.call(this, k) + } + } + if (!targetDescriptor) { Object.defineProperty(e.target, 'target', { configurable: false,