From 993a2b984844d5e952de61cf5d4f684884149bff Mon Sep 17 00:00:00 2001 From: Mike Plummer Date: Mon, 5 Feb 2024 15:26:47 -0600 Subject: [PATCH] feat: Allow specifying preferred attributes (#7) --- src/{getData.js => getAttribute.js} | 8 +-- src/index.js | 24 ++++---- test/unique-selector.js | 85 ++++++++++++++++++----------- 3 files changed, 71 insertions(+), 46 deletions(-) rename src/{getData.js => getAttribute.js} (65%) diff --git a/src/getData.js b/src/getAttribute.js similarity index 65% rename from src/getData.js rename to src/getAttribute.js index a638f13..b5f038f 100644 --- a/src/getData.js +++ b/src/getAttribute.js @@ -1,11 +1,11 @@ /** - * Returns the data-{dataAttr} selector of the element - * @param { String } selectorType - The type of selector to return. + * Returns the {attr} selector of the element + * @param { String } selectorType - The attribute selector to return. * @param { String } attributes - The attributes of the element. - * @return { String | null } - The data-{dataAttr} selector of the element. + * @return { String | null } - The {attr} selector of the element. */ -export const getData = ( selectorType, attributes ) => +export const getAttribute = ( selectorType, attributes ) => { for ( let i = 0; i < attributes.length; i++ ) { diff --git a/src/index.js b/src/index.js index c39ac63..f53b879 100644 --- a/src/index.js +++ b/src/index.js @@ -11,9 +11,10 @@ import { getNthChild } from './getNthChild'; import { getTag } from './getTag'; import { isUnique } from './isUnique'; import { getParents } from './getParents'; -import { getData } from './getData'; +import { getAttribute } from './getAttribute'; -const dataRegex = /^data-(.+)/; +const dataRegex = /^data-.+/; +const attrRegex = /^attribute:(.+)/m; /** * Returns all the selectors of the element @@ -33,7 +34,7 @@ function getAllSelectors( el, selectors, attributesToIgnore ) }; return selectors - .filter( ( selector ) => !dataRegex.test( selector ) ) + .filter( ( selector ) => !dataRegex.test( selector ) && !attrRegex.test( selector ) ) .reduce( ( res, next ) => { res[ next ] = funcs[ next ]( el ); @@ -119,15 +120,18 @@ function getUniqueSelector( element, selectorTypes, attributesToIgnore ) let selector = elementSelectors[ selectorType ]; // if we are a data attribute - if ( dataRegex.test( selectorType ) ) + const isDataAttributeSelectorType = dataRegex.test(selectorType) + const isAttributeSelectorType = !isDataAttributeSelectorType && attrRegex.test(selectorType) + if ( isDataAttributeSelectorType || isAttributeSelectorType ) { - const dataSelector = getData( selectorType, attributes ); + const attributeToQuery = isDataAttributeSelectorType ? selectorType : selectorType.replace(attrRegex, '$1') + const attributeSelector = getAttribute( attributeToQuery, attributes ); - // if we found a selector via data attributes - if ( dataSelector ) + // if we found a selector via attribute + if ( attributeSelector ) { - selector = dataSelector; - selectorType = 'data'; + selector = attributeSelector; + selectorType = 'attribute'; } } @@ -135,7 +139,7 @@ function getUniqueSelector( element, selectorTypes, attributesToIgnore ) switch ( selectorType ) { - case 'data' : + case 'attribute' : case 'id' : case 'name': case 'tag': diff --git a/test/unique-selector.js b/test/unique-selector.js index 2b6b468..32c73f0 100644 --- a/test/unique-selector.js +++ b/test/unique-selector.js @@ -107,41 +107,62 @@ describe( 'Unique Selector Tests', () => expect( uniqueSelector ).to.equal( '[test="5"]' ); } ); - it( 'data-foo', () => - { - $( 'body' ).get( 0 ).innerHTML = ''; // Clear previous appends - $( 'body' ).append( '
' ); - const findNode = $( 'body' ).find( '.test6' ).get( 0 ); - const uniqueSelector = unique( findNode, { selectorTypes : ['data-foo'] } ); - expect( uniqueSelector ).to.equal( '[data-foo="so"]' ); - } ); + describe('data attribute', () => { + it( 'data-foo', () => + { + $( 'body' ).get( 0 ).innerHTML = ''; // Clear previous appends + $( 'body' ).append( '
' ); + const findNode = $( 'body' ).find( '.test6' ).get( 0 ); + const uniqueSelector = unique( findNode, { selectorTypes : ['data-foo'] } ); + expect( uniqueSelector ).to.equal( '[data-foo="so"]' ); + } ); - it( 'data-foo-bar-baz', () => - { - $( 'body' ).get( 0 ).innerHTML = ''; // Clear previous appends - $( 'body' ).append( '
' ); - const findNode = $( 'body' ).find( '.test6' ).get( 0 ); - const uniqueSelector = unique( findNode, { selectorTypes : ['data-foo-bar-baz'] } ); - expect( uniqueSelector ).to.equal( '[data-foo-bar-baz="so"]' ); - } ); + it( 'data-foo-bar-baz', () => + { + $( 'body' ).get( 0 ).innerHTML = ''; // Clear previous appends + $( 'body' ).append( '
' ); + const findNode = $( 'body' ).find( '.test6' ).get( 0 ); + const uniqueSelector = unique( findNode, { selectorTypes : ['data-foo-bar-baz'] } ); + expect( uniqueSelector ).to.equal( '[data-foo-bar-baz="so"]' ); + } ); - it( 'data-foo-bar with quotes', () => - { - $( 'body' ).get( 0 ).innerHTML = ''; // Clear previous appends - $( 'body' ).append( '
' ); - const findNode = $( 'body' ).find( '.test7' ).get( 0 ); - const uniqueSelector = unique( findNode, { selectorTypes : ['data-foo-bar'] } ); - expect( uniqueSelector ).to.equal( '[data-foo-bar="button 123"]' ); - } ); + it( 'data-foo-bar with quotes', () => + { + $( 'body' ).get( 0 ).innerHTML = ''; // Clear previous appends + $( 'body' ).append( '
' ); + const findNode = $( 'body' ).find( '.test7' ).get( 0 ); + const uniqueSelector = unique( findNode, { selectorTypes : ['data-foo-bar'] } ); + expect( uniqueSelector ).to.equal( '[data-foo-bar="button 123"]' ); + } ); - it( 'data-foo without value', () => - { - $( 'body' ).get( 0 ).innerHTML = ''; // Clear previous appends - $( 'body' ).append( '
' ); - const findNode = $( 'body' ).find( '.test7' ).get( 0 ); - const uniqueSelector = unique( findNode, { selectorTypes : ['data-foo'] } ); - expect( uniqueSelector ).to.equal( '[data-foo]' ); - } ); + it( 'data-foo without value', () => + { + $( 'body' ).get( 0 ).innerHTML = ''; // Clear previous appends + $( 'body' ).append( '
' ); + const findNode = $( 'body' ).find( '.test7' ).get( 0 ); + const uniqueSelector = unique( findNode, { selectorTypes : ['data-foo'] } ); + expect( uniqueSelector ).to.equal( '[data-foo]' ); + } ); + }); + + describe('standard attribute', () => { + it('attribute without value', () => { + $( 'body' ).get( 0 ).innerHTML = ''; // Clear previous appends + $( 'body' ).append( '
' ); + const findNode = $( 'body' ).find( '.test8' ).get( 0 ); + const uniqueSelector = unique( findNode, { selectorTypes : ['attribute:contenteditable'] } ); + expect( uniqueSelector ).to.equal( '[contenteditable]' ); + }) + + it('attribute with value', () => { + $( 'body' ).get( 0 ).innerHTML = ''; // Clear previous appends + $( 'body' ).append( '
' ); + const findNode = $( 'body' ).find( '.test9' ).get( 0 ); + const uniqueSelector = unique( findNode, { selectorTypes : ['attribute:role'] } ); + expect( uniqueSelector ).to.equal( '[role="button"]' ); + }) + }) + describe('name', () => { beforeEach(() => {