Skip to content

Commit 5d0fe2f

Browse files
committed
extra fallback to nodeName to help keep us on the rails if possible
1 parent e19e70f commit 5d0fe2f

File tree

2 files changed

+63
-12
lines changed

2 files changed

+63
-12
lines changed

src/getTag.js

Lines changed: 22 additions & 10 deletions
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,18 +10,26 @@
610
*/
711
export function getTag( el, filter )
812
{
9-
if (typeof el.tagName !== 'string') {
10-
// If the tagName attribute has been overridden, we should
11-
// return null and not use tagName for selector generation.
12-
//
13-
// This can happen when a <form> element contains an <input>
14-
// with an id of `tagName`. In this case, the form element's
15-
// tagName property is a reference to the input element, not
16-
// a string.
17-
return null;
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+
}
1830
}
1931

20-
const tagName = el.tagName.toLowerCase().replace(/:/g, '\\:')
32+
tagName = tagName.toLowerCase().replace(/:/g, '\\:')
2133

2234
if (filter && !filter('tag', 'tag', tagName)) {
2335
return null;

test/unique-selector.js

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ describe( 'Unique Selector Tests', () =>
128128
expect( uniqueSelector ).to.equal( 'a' );
129129
} );
130130

131-
it( 'Tag - filtered due to property override', () =>
131+
it( 'Tag - fallback to nodeName', () =>
132132
{
133133
$( 'body' ).append(`
134134
<div class="test2">
@@ -154,9 +154,48 @@ describe( 'Unique Selector Tests', () =>
154154
expect(typeof formNode.tagName).to.not.equal('string')
155155

156156
const uniqueSelector = unique( formNode );
157-
expect( uniqueSelector ).to.equal( '.test2 > :nth-child(1)' );
157+
// nodeName === 'form'
158+
expect( uniqueSelector ).to.equal( 'form' );
158159
} );
159160

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+
160199
it( 'Attributes', () =>
161200
{
162201
$( 'body' ).append( '<div class="test5" test="5"></div>' );

0 commit comments

Comments
 (0)