Skip to content

Commit 09bcc5b

Browse files
sainthkhemilyrohrboughmjhenkes
authored
fix (#19262)
Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com> Co-authored-by: Matt Henkes <mjhenkes@gmail.com>
1 parent dd0fc9b commit 09bcc5b

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
</head>
5+
<body>
6+
<script>
7+
function defaultBehavior(e) {
8+
document.getElementById('result').innerHTML = JSON.stringify(e.target.getAttribute('target'))
9+
}
10+
11+
function setAttributeBehavior(e) {
12+
e.target.setAttribute('target', '_top')
13+
document.getElementById('result2').innerHTML = JSON.stringify(e.target.getAttribute('target'))
14+
}
15+
16+
function removeAttributeBehavior(e) {
17+
e.target.setAttribute('target', '_top')
18+
e.target.removeAttribute('target')
19+
document.getElementById('result3').innerHTML = JSON.stringify(e.target.getAttribute('target'))
20+
}
21+
</script>
22+
23+
<div>
24+
<a href="#" id="link" onclick="defaultBehavior(event)">link 1</a>
25+
<div id="result"></div>
26+
</div>
27+
28+
<div>
29+
<a href="#" id="link2" onclick="setAttributeBehavior(event)">link 2</a>
30+
<div id="result2"></div>
31+
</div>
32+
33+
<div>
34+
<a href="#" id="link3" onclick="removeAttributeBehavior(event)">link 3</a>
35+
<div id="result3"></div>
36+
</div>
37+
</body>
38+
</html>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
describe('issue 17512', () => {
2+
beforeEach(() => {
3+
cy.visit('fixtures/issue-17512.html')
4+
})
5+
6+
it('returns null when target is not defined', () => {
7+
cy.get('#link').click()
8+
cy.get('#result').should('have.text', 'null')
9+
10+
cy.get('#link2').click()
11+
cy.get('#result2').should('have.text', '"_top"')
12+
13+
cy.get('#link3').click()
14+
cy.get('#result3').should('have.text', 'null')
15+
})
16+
})

packages/driver/src/cy/top_attr_guards.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,24 @@ const invalidTargets = new Set(['_parent', '_top'])
88
*/
99
export function handleInvalidEventTarget (e: Event & {target: HTMLFormElement | HTMLAnchorElement}) {
1010
let targetValue = e.target.target
11+
let targetSet = e.target.hasAttribute('target')
1112

1213
if (invalidTargets.has(e.target.target)) {
1314
e.target.target = ''
1415
}
1516

16-
const { getAttribute, setAttribute } = e.target
17+
const { getAttribute, setAttribute, removeAttribute } = e.target
1718
const targetDescriptor = Object.getOwnPropertyDescriptor(e.target, 'target')
1819

1920
e.target.getAttribute = function (k) {
2021
if (k === 'target') {
22+
// https://github.com/cypress-io/cypress/issues/17512
23+
// When the target attribute doesn't exist, it should return null.
24+
// @see https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute#non-existing_attributes
25+
if (!targetSet) {
26+
return null
27+
}
28+
2129
return targetValue
2230
}
2331

@@ -26,6 +34,7 @@ export function handleInvalidEventTarget (e: Event & {target: HTMLFormElement |
2634

2735
e.target.setAttribute = function (k, v) {
2836
if (k === 'target') {
37+
targetSet = true
2938
targetValue = v
3039

3140
return $elements.callNativeMethod(this, 'setAttribute', 'cyTarget', v)
@@ -34,6 +43,16 @@ export function handleInvalidEventTarget (e: Event & {target: HTMLFormElement |
3443
return setAttribute.call(this, k, v)
3544
}
3645

46+
e.target.removeAttribute = function (k) {
47+
if (k === 'target') {
48+
targetSet = false
49+
targetValue = ''
50+
51+
// We're not using `$elements.callNativeMethod` here because it disallows `removeAttribute`.
52+
return removeAttribute.call(this, k)
53+
}
54+
}
55+
3756
if (!targetDescriptor) {
3857
Object.defineProperty(e.target, 'target', {
3958
configurable: false,

0 commit comments

Comments
 (0)