mirror of
https://github.com/lucide-icons/lucide.git
synced 2026-11-10 13:18:25 +00:00
test(lucide): add tests for replaceElement and edge cases (#5059)
Co-authored-by: grzdev <grzdev@users.noreply.github.com>
This commit is contained in:
@@ -1,8 +1,14 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { getAttrs, getClassNames } from '../src/replaceElement';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import replaceElement, { getAttrs, getClassNames } from '../src/replaceElement';
|
||||
import type { IconNode } from '../src/types';
|
||||
|
||||
describe('getAtts', () => {
|
||||
it('should returns attrbrutes of an element', () => {
|
||||
const testIconNode: IconNode = [
|
||||
['polygon', { points: '11 5 6 9 2 9 2 15 6 15 11 19 11 5' }],
|
||||
['path', { d: 'M15.54 8.46a5 5 0 0 1 0 7.07' }],
|
||||
];
|
||||
|
||||
describe('getAttrs', () => {
|
||||
it('should return attributes of an element', () => {
|
||||
const element = {
|
||||
attributes: [
|
||||
{
|
||||
@@ -10,7 +16,7 @@ describe('getAtts', () => {
|
||||
value: 'item1 item2 item4',
|
||||
},
|
||||
{
|
||||
name: 'date-name',
|
||||
name: 'data-name',
|
||||
value: 'volume',
|
||||
},
|
||||
],
|
||||
@@ -19,25 +25,124 @@ describe('getAtts', () => {
|
||||
const attrs = getAttrs(element as unknown as Element);
|
||||
|
||||
expect(attrs.class).toBe(element.attributes[0].value);
|
||||
expect(attrs['data-name']).toBe('volume');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getClassNames', () => {
|
||||
it('should returns an array when giving class property of string', () => {
|
||||
it('should return an array when given class property of string', () => {
|
||||
const elementAttrs = {
|
||||
class: 'item1 item2 item3',
|
||||
};
|
||||
|
||||
const attrs = getClassNames(elementAttrs);
|
||||
expect(JSON.stringify(attrs)).toBe(JSON.stringify(['item1', 'item2', 'item3']));
|
||||
expect(attrs).toEqual(['item1', 'item2', 'item3']);
|
||||
});
|
||||
|
||||
it('should returns an array when givind class property with an array', () => {
|
||||
it('should return an array when given class property with an array', () => {
|
||||
const elementAttrs = {
|
||||
class: ['item1', 'item2', 'item3'],
|
||||
};
|
||||
|
||||
const attrs = getClassNames(elementAttrs);
|
||||
expect(JSON.stringify(attrs)).toBe(JSON.stringify(['item1', 'item2', 'item3']));
|
||||
expect(attrs).toEqual(['item1', 'item2', 'item3']);
|
||||
});
|
||||
|
||||
it('should return string when given a string directly', () => {
|
||||
expect(getClassNames('custom-class')).toBe('custom-class');
|
||||
});
|
||||
|
||||
it('should return empty string when no class property exists', () => {
|
||||
expect(getClassNames({})).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('replaceElement', () => {
|
||||
it('should return undefined if element lacks the name attribute', () => {
|
||||
const element = document.createElement('i');
|
||||
const result = replaceElement(element, {
|
||||
nameAttr: 'data-lucide',
|
||||
icons: { Volume2: testIconNode },
|
||||
attrs: {},
|
||||
});
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should warn and return undefined when icon is not found in icons object', () => {
|
||||
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
const element = document.createElement('i');
|
||||
element.setAttribute('data-lucide', 'non-existent');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const result = replaceElement(element, {
|
||||
nameAttr: 'data-lucide',
|
||||
icons: {},
|
||||
attrs: {},
|
||||
});
|
||||
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining('icon name was not found in the provided icons object'),
|
||||
);
|
||||
expect(result).toBeUndefined();
|
||||
|
||||
element.remove();
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should replace element with svg in parentNode and forward attributes', () => {
|
||||
const container = document.createElement('div');
|
||||
const element = document.createElement('i');
|
||||
element.setAttribute('data-lucide', 'volume-2');
|
||||
element.setAttribute('class', 'custom-icon');
|
||||
container.appendChild(element);
|
||||
|
||||
const replaced = replaceElement(element, {
|
||||
nameAttr: 'data-lucide',
|
||||
icons: { Volume2: testIconNode },
|
||||
attrs: { stroke: 'red' },
|
||||
});
|
||||
|
||||
expect(replaced).toBe(element);
|
||||
expect(container.querySelector('i')).toBeNull();
|
||||
|
||||
const svg = container.querySelector('svg');
|
||||
expect(svg).not.toBeNull();
|
||||
expect(svg?.getAttribute('data-lucide')).toBe('volume-2');
|
||||
expect(svg?.getAttribute('stroke')).toBe('red');
|
||||
expect(svg?.getAttribute('aria-hidden')).toBe('true');
|
||||
expect(svg?.classList.contains('lucide-volume-2')).toBe(true);
|
||||
expect(svg?.classList.contains('custom-icon')).toBe(true);
|
||||
});
|
||||
|
||||
it('should not add aria-hidden if element has accessibility attributes', () => {
|
||||
const container = document.createElement('div');
|
||||
const element = document.createElement('i');
|
||||
element.setAttribute('data-lucide', 'volume-2');
|
||||
element.setAttribute('aria-label', 'Volume Control');
|
||||
container.appendChild(element);
|
||||
|
||||
replaceElement(element, {
|
||||
nameAttr: 'data-lucide',
|
||||
icons: { Volume2: testIconNode },
|
||||
attrs: {},
|
||||
});
|
||||
|
||||
const svg = container.querySelector('svg');
|
||||
expect(svg?.getAttribute('aria-hidden')).toBeNull();
|
||||
expect(svg?.getAttribute('aria-label')).toBe('Volume Control');
|
||||
});
|
||||
|
||||
it('should handle detached elements without parentNode gracefully', () => {
|
||||
const element = document.createElement('i');
|
||||
element.setAttribute('data-lucide', 'volume-2');
|
||||
|
||||
const result = replaceElement(element, {
|
||||
nameAttr: 'data-lucide',
|
||||
icons: { Volume2: testIconNode },
|
||||
attrs: {},
|
||||
});
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user