import { appendElement } from '../../test' import { getSelectorFromElement, isSelectorUniqueAmongSiblings } from './getSelectorFromElement' describe('getSelectorFromElement', () => { afterEach(() => { document.body.classList.remove('foo') }) it('returns undefined for detached elements', () => { const element = document.createElement('div') expect(getSelector(element)).toBeUndefined() }) describe('ID selector', () => { it('should use the ID selector when the element as an ID', () => { expect(getSelector('
')).toBe('#foo') }) it('should not use the ID selector when the ID is not unique', () => { expect(getSelector('
')).not.toContain('#foo') }) it('should not use generated IDs', () => { expect(getSelector('
')).toBe('BODY>DIV') }) }) describe('class selector', () => { it('should use the class selector when the element as classes', () => { expect(getSelector('
')).toBe('BODY>DIV.foo') }) it('should use the class selector when siblings have the same classes but different tags', () => { expect(getSelector('
')).toBe('BODY>DIV.foo') }) it('should not use the class selector when siblings have the tag + classes', () => { expect(getSelector('
')).not.toContain('DIV.foo') expect(getSelector('
')).not.toContain('DIV.foo') }) it('should not use the class selector for body elements', () => { const element = appendElement('
') document.body.classList.add('foo') expect(getSelector(element)).toBe('BODY>DIV') }) it('should not use generated classes', () => { expect(getSelector('
')).toBe('BODY>DIV') }) it('uses only the first class', () => { expect(getSelector('
')).toBe('BODY>DIV.foo') }) }) describe('position selector', () => { it('should use nth-of-type when the selector matches multiple descendants', () => { expect( getSelector(`
`) ).toBe('BODY>DIV:nth-of-type(2)>BUTTON') }) it('should not use nth-of-type when the selector is matching a single descendant', () => { expect( getSelector(`
`) ).toBe('BODY>DIV>BUTTON') }) it('should only consider direct descendants (>) of the parent element when checking for unicity', () => { expect( getSelector(`
`) ).toBe('BODY>MAIN>DIV>BUTTON') }) }) describe('strategies priority', () => { it('ID selector should take precedence over class selector', () => { expect(getSelector('
')).toBe('#foo') }) it('class selector should take precedence over position selector', () => { expect(getSelector('
')).toBe('BODY>DIV.bar') }) }) describe('should escape CSS selectors', () => { it('on ID value', () => { expect(getSelector('
')).toBe('#\\#bar') }) it('on attribute value', () => { expect(getSelector('
')).toBe('DIV[data-testid="\\"foo\\ bar\\""]') }) it('on class name', () => { expect(getSelector('
')).toBe('BODY>DIV.\\#bar') }) it('on tag name', () => { expect(getSelector('>')).toBe('BODY>DIV\\&NBSP\\;SPAN') }) }) describe('attribute selector', () => { it('uses a stable attribute if the element has one', () => { expect(getSelector('
')).toBe('DIV[data-testid="foo"]') }) it('attribute selector with the custom action name attribute takes precedence over other stable attribute selectors', () => { expect(getSelector('
', 'action-name')).toBe( 'DIV[action-name="foo"]' ) }) it('stable attribute selector should take precedence over class selector', () => { expect(getSelector('
')).toBe('DIV[data-testid="foo"]') }) it('stable attribute selector should take precedence over ID selector', () => { expect(getSelector('
')).toBe('DIV[data-testid="foo"]') }) it("uses a stable attribute selector and continue recursing if it's not unique globally", () => { expect( getSelector(`
`) ).toBe('BODY>BUTTON[data-testid="foo"]') }) }) it('should compute a CSS selector on SVG elements', () => { const element = appendElement('') expect(getSelector(element)).toBe('BODY>svg.foo') }) function getSelector(htmlOrElement: string | Element, actionNameAttribute?: string): string | undefined { return getSelectorFromElement( typeof htmlOrElement === 'string' ? appendElement(htmlOrElement) : htmlOrElement, actionNameAttribute ) } }) describe('isSelectorUniqueAmongSiblings', () => { it('returns true when the element is alone', () => { const element = appendElement('
') expect(isSelectorUniqueAmongSiblings(element, 'DIV', undefined)).toBeTrue() }) it('returns false when a sibling element matches the element selector', () => { const element = appendElement(`
`) expect(isSelectorUniqueAmongSiblings(element, 'DIV', undefined)).toBeFalse() }) it('returns true when the element selector does not match any sibling', () => { const element = appendElement(`
`) expect(isSelectorUniqueAmongSiblings(element, 'DIV', undefined)).toBeTrue() }) it('returns false when the child selector matches an element in a sibling', () => { const element = appendElement(`


`) expect(isSelectorUniqueAmongSiblings(element, 'DIV', 'HR')).toBeFalse() }) it('returns true when the current element selector does not match the sibling', () => { const element = appendElement(`


`) expect(isSelectorUniqueAmongSiblings(element, 'DIV', 'HR')).toBeTrue() }) it('the selector should not consider elements deep in the tree', () => { const element = appendElement(`


`) expect(isSelectorUniqueAmongSiblings(element, 'DIV', 'HR')).toBeTrue() }) })