Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: cypress-io/unique-selector
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.0.0
Choose a base ref
...
head repository: cypress-io/unique-selector
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.1.0
Choose a head ref
  • 1 commit
  • 3 files changed
  • 1 contributor

Commits on Feb 5, 2024

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    993a2b9 View commit details
Showing with 71 additions and 46 deletions.
  1. +4 −4 src/{getData.js → getAttribute.js}
  2. +14 −10 src/index.js
  3. +53 −32 test/unique-selector.js
8 changes: 4 additions & 4 deletions src/getData.js → src/getAttribute.js
Original file line number Diff line number Diff line change
@@ -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++ )
{
24 changes: 14 additions & 10 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -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,23 +120,26 @@ 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';
}
}

if ( !Boolean( selector ) ) continue;

switch ( selectorType )
{
case 'data' :
case 'attribute' :
case 'id' :
case 'name':
case 'tag':
85 changes: 53 additions & 32 deletions test/unique-selector.js
Original file line number Diff line number Diff line change
@@ -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( '<div data-foo="so" class="test6"></div>' );
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( '<div data-foo="so" class="test6"></div>' );
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( '<div data-foo-bar-baz="so" class="test6"></div>' );
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( '<div data-foo-bar-baz="so" class="test6"></div>' );
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( '<div data-foo-bar="button 123" class="test7"></div>' );
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( '<div data-foo-bar="button 123" class="test7"></div>' );
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( '<div data-foo class="test7"></div>' );
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( '<div data-foo class="test7"></div>' );
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( '<div contenteditable class="test8"></div>' );
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( '<div role="button" class="test9"></div>' );
const findNode = $( 'body' ).find( '.test9' ).get( 0 );
const uniqueSelector = unique( findNode, { selectorTypes : ['attribute:role'] } );
expect( uniqueSelector ).to.equal( '[role="button"]' );
})
})


describe('name', () => {
beforeEach(() => {