Skip to content

Commit b970b33

Browse files
authored
fix: extra protection around tagName accessor (#13)
* fix: extra protection around tagName accessor * extra fallback to nodeName to help keep us on the rails if possible
1 parent 2d5844c commit b970b33

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

src/getTag.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
function isString(value) {
2+
return typeof value === 'string';
3+
}
4+
15
/**
26
* Returns the Tag of the element
37
* @param { Object } element
@@ -6,7 +10,26 @@
610
*/
711
export function getTag( el, filter )
812
{
9-
const tagName = el.tagName.toLowerCase().replace(/:/g, '\\:')
13+
let tagName = el.tagName;
14+
15+
// If the tagName attribute has been overridden, we should
16+
// check the nodeName property instead. If the nodeName property
17+
// is also not a string, we should return null and ignore tagName
18+
// for selector generation.
19+
//
20+
// This can happen when a <form> element contains an <input>
21+
// with an id of `tagName`. In this case, the form element's
22+
// tagName property is a reference to the input element, not
23+
// a string.
24+
if (!isString(tagName)) {
25+
tagName = el.nodeName;
26+
27+
if (!isString(tagName)) {
28+
return null;
29+
}
30+
}
31+
32+
tagName = tagName.toLowerCase().replace(/:/g, '\\:')
1033

1134
if (filter && !filter('tag', 'tag', tagName)) {
1235
return null;

test/unique-selector.js

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ describe( 'Unique Selector Tests', () =>
112112
expect( uniqueSelector ).to.equal( 'span' );
113113
} );
114114

115-
116115
it( 'Tag', () =>
117116
{
118117
$( 'body' ).append( '<div class="test5"><span></span></div><div class="test5"><span></span></div>' );
@@ -129,6 +128,74 @@ describe( 'Unique Selector Tests', () =>
129128
expect( uniqueSelector ).to.equal( 'a' );
130129
} );
131130

131+
it( 'Tag - fallback to nodeName', () =>
132+
{
133+
$( 'body' ).append(`
134+
<div class="test2">
135+
<form action="" method="get">
136+
<div class="form-example">
137+
<label for="name">Enter your name: </label>
138+
<input type="text" name="name" id="tagName" required />
139+
</div>
140+
</form>
141+
</div>
142+
`);
143+
144+
const formNode = $( 'form' ).get( 0 );
145+
146+
// JSDOM doesn't actually exhibit this behavior;
147+
// forcing the test to behave as a browser does.
148+
Object.defineProperty(formNode, 'tagName', {
149+
get: () => {
150+
return $( 'input#tagName' ).get( 0 );
151+
}
152+
})
153+
154+
expect(typeof formNode.tagName).to.not.equal('string')
155+
156+
const uniqueSelector = unique( formNode );
157+
// nodeName === 'form'
158+
expect( uniqueSelector ).to.equal( 'form' );
159+
} );
160+
161+
it( 'Tag - ignored due to property override', () =>
162+
{
163+
$( 'body' ).append(`
164+
<div class="test2">
165+
<form action="" method="get">
166+
<div class="form-example">
167+
<label for="name">Enter your name: </label>
168+
<input type="text" name="name" id="tagName" required />
169+
</div>
170+
</form>
171+
</div>
172+
`);
173+
174+
const formNode = $( 'form' ).get( 0 );
175+
176+
// JSDOM doesn't actually exhibit this behavior;
177+
// forcing the test to behave as a browser does.
178+
Object.defineProperty(formNode, 'tagName', {
179+
get: () => {
180+
return $( 'input#tagName' ).get( 0 );
181+
}
182+
})
183+
Object.defineProperty(formNode, 'nodeName', {
184+
get: () => {
185+
return $( 'input#tagName' ).get( 0 );
186+
}
187+
})
188+
189+
expect(typeof formNode.tagName).to.not.equal('string')
190+
expect(typeof formNode.nodeName).to.not.equal('string')
191+
192+
const uniqueSelector = unique( formNode );
193+
// with nodeName overridden, the isElement check will fail
194+
// and the wildcard selector is returned for that element.
195+
// This really shouldn't happen in practice.
196+
expect( uniqueSelector ).to.equal( '.test2 > *' );
197+
} );
198+
132199
it( 'Attributes', () =>
133200
{
134201
$( 'body' ).append( '<div class="test5" test="5"></div>' );

0 commit comments

Comments
 (0)