@serenity-is/corelib
Version:
Serenity Core Library
1,251 lines (962 loc) • 44 kB
text/typescript
import { Fluent } from './fluent';
describe('Fluent instance methods', () => {
let element: HTMLElement;
let fluent: Fluent<HTMLElement>;
beforeEach(() => {
element = document.createElement('div');
fluent = Fluent(element);
});
describe('addClass', () => {
it('should add class to the element', () => {
fluent.addClass('test-class');
expect(element.classList.contains('test-class')).toBe(true);
});
it('should add multiple classes to the element', () => {
fluent.addClass(['class1', 'class2']);
expect(element.classList.contains('class1')).toBe(true);
expect(element.classList.contains('class2')).toBe(true);
});
it('ignores existing classes', () => {
element.classList.add("test");
fluent.addClass(['class1', 'class2', 'test']);
expect(element.classList.contains('class1')).toBe(true);
expect(element.classList.contains('class2')).toBe(true);
expect(element.classList.contains('test')).toBe(true);
});
it('ignores falsy classes', () => {
fluent.addClass(['class1', false && 'class2']);
expect(element.classList.contains('class1')).toBe(true);
expect(element.classList.contains('class2')).toBe(false);
});
});
describe('after', () => {
let parent: HTMLElement;
beforeEach(() => {
parent = document.createElement('div');
fluent.appendTo(parent);
});
it('should ignore null', () => {
fluent.after(null);
expect(element.previousSibling).toBe(null);
expect(element.nextSibling).toBe(null);
expect(element.parentElement).toBe(parent);
expect(element.parentElement.childNodes.length).toBe(1);
});
it('should ignore empty Fluent', () => {
fluent.before(Fluent(null));
expect(element.previousSibling).toBe(null);
expect(element.nextSibling).toBe(null);
expect(element.parentElement).toBe(parent);
expect(element.parentElement.childNodes.length).toBe(1);
});
it('should insert the content node after itself', () => {
const after = document.createElement('span');
fluent.after(after);
expect(element.nextSibling).toBe(after);
expect(after.parentElement).toBe(parent);
expect(element.parentElement).toBe(parent);
expect(element.parentElement.childNodes.length).toBe(2);
});
it('should insert the text after itself', () => {
fluent.after("test");
expect(element.nextSibling instanceof Text).toBe(true);
expect(element.nextSibling.textContent).toBe("test");
expect(element.parentElement).toBe(parent);
expect(element.parentElement.childNodes.length).toBe(2);
});
it('can insert fragment contents', () => {
const fragment = new DocumentFragment();
const span = fragment.appendChild(document.createElement("span"));
const input = fragment.appendChild(document.createElement("input"));
fluent.after(fragment);
expect(element.nextSibling).toBe(span);
expect(element.nextSibling.nextSibling).toBe(input);
expect(element.parentElement).toBe(parent);
expect(element.parentElement.childNodes.length).toBe(3);
});
});
describe('append', () => {
it('should append child to the element', () => {
const child = document.createElement('span');
fluent.append(child);
expect(element.lastChild).toBe(child);
});
it('should append string as text child to the element', () => {
const child = '<span>Test</span>';
fluent.append(child);
expect((element.lastChild as HTMLElement)?.textContent).toBe(child);
});
it('should append Fluent instance as child to the element', () => {
const childElement = document.createElement('span');
const childFluent = Fluent(childElement);
fluent.append(childFluent);
expect(element.lastChild).toBe(childElement);
});
});
describe('appendTo', () => {
let parent: HTMLElement;
beforeEach(() => {
parent = document.createElement('div');
});
it('should append the element to the parent', () => {
fluent.appendTo(parent);
expect(parent.lastChild).toBe(element);
});
it('should remove the element if parent is null', () => {
fluent.appendTo(null);
expect(element.parentNode).toBe(null);
});
it('should remove the element if parent is undefined', () => {
fluent.appendTo(undefined);
expect(element.parentNode).toBe(null);
});
});
describe('attr', () => {
it('should get the attribute value', () => {
element.setAttribute('data-test', 'value');
const value = fluent.attr('data-test');
expect(value).toBe('value');
});
it('should set the attribute value', () => {
fluent.attr('data-test', 'value');
expect(element.getAttribute('data-test')).toBe('value');
});
it('should remove the attribute if value is null', () => {
element.setAttribute('data-test', 'value');
fluent.attr('data-test', null);
expect(element.hasAttribute('data-test')).toBe(false);
});
it('should remove the attribute if value is undefined', () => {
element.setAttribute('data-test', 'value');
fluent.attr('data-test', undefined);
expect(element.hasAttribute('data-test')).toBe(false);
});
it('should set the attribute value to empty string if value is false', () => {
fluent.attr('data-test', false);
expect(element.getAttribute('data-test')).toBe(null);
});
it('should set the attribute value to "true" if value is true', () => {
fluent.attr('data-test', true);
expect(element.getAttribute('data-test')).toBe('true');
});
it('should convert number value to string', () => {
fluent.attr('data-test', 123);
expect(element.getAttribute('data-test')).toBe('123');
});
});
describe('before', () => {
let parent: HTMLElement;
beforeEach(() => {
parent = document.createElement('div');
fluent.appendTo(parent);
});
it('should ignore null', () => {
fluent.before(null);
expect(element.previousSibling).toBe(null);
expect(element.nextSibling).toBe(null);
expect(element.parentElement).toBe(parent);
expect(element.parentElement.childNodes.length).toBe(1);
});
it('should ignore empty Fluent', () => {
fluent.before(Fluent(null));
expect(element.previousSibling).toBe(null);
expect(element.nextSibling).toBe(null);
expect(element.parentElement).toBe(parent);
expect(element.parentElement.childNodes.length).toBe(1);
});
it('should insert the content node before itself', () => {
const before = document.createElement('span');
fluent.before(before);
expect(element.previousSibling).toBe(before);
expect(before.parentElement).toBe(parent);
expect(element.parentElement).toBe(parent);
expect(element.parentElement.childNodes.length).toBe(2);
});
it('should insert the text before itself', () => {
fluent.before("test");
expect(element.previousSibling instanceof Text).toBe(true);
expect(element.previousSibling.textContent).toBe("test");
expect(element.parentElement).toBe(parent);
expect(element.parentElement.childNodes.length).toBe(2);
});
it('can insert fragment contents', () => {
const fragment = new DocumentFragment();
const span = fragment.appendChild(document.createElement("span"));
const input = fragment.appendChild(document.createElement("input"));
fluent.before(fragment);
expect(element.previousSibling).toBe(input);
expect(element.previousSibling.previousSibling).toBe(span);
expect(element.parentElement).toBe(parent);
expect(element.parentElement.childNodes.length).toBe(3);
});
});
describe('children', () => {
beforeEach(() => {
element.innerHTML = `<div class="child"></div><span class="child"></span><div></div>`;
});
it('should return all children of the element', () => {
const children = fluent.children();
expect(children.length).toBe(3);
expect(children[0].classList.contains('child')).toBe(true);
expect(children[1].classList.contains('child')).toBe(true);
});
it('should return children matching the selector', () => {
const children = fluent.children('.child');
expect(children.length).toBe(2);
expect(children[0].classList.contains('child')).toBe(true);
expect(children[1].classList.contains('child')).toBe(true);
});
});
describe("click", () => {
it('should ignore null element', () => {
Fluent(null).click();
});
it('should trigger click event with no arguments', () => {
const onClickSpy = vi.fn();
fluent.getNode().addEventListener("click", onClickSpy);
fluent.click();
expect(onClickSpy).toHaveBeenCalledTimes(1);
});
it("should call elements click method with no arguments", () => {
const clickSpy = vi.spyOn(fluent.getNode(), "click");
fluent.click();
expect(clickSpy).toHaveBeenCalledTimes(1);
});
it("should ignore if element has no click method", () => {
const onClickSpy = vi.fn();
fluent.getNode().addEventListener("click", onClickSpy);
fluent.getNode().click = null;
fluent.click();
expect(onClickSpy).not.toHaveBeenCalled();
});
it('should add click event handler', () => {
const clickSpy = vi.fn();
fluent.click(clickSpy);
fluent.getNode().click();
expect(clickSpy).toHaveBeenCalledTimes(1);
});
});
describe('closest', () => {
it('should return closest matching element', () => {
const parentElement = document.createElement('div');
parentElement.id = 'parent';
const childElement = document.createElement('p');
childElement.id = 'child';
parentElement.appendChild(childElement);
fluent = Fluent(childElement);
const closestElement = fluent.closest('#parent').getNode();
expect(closestElement).toBe(parentElement);
});
it('should return null if no matching element is found', () => {
document.body.innerHTML = `<div id="test"></div>`;
fluent = Fluent(document.getElementById("test"));
const closestElement = fluent.closest('.not-existing');
expect(closestElement.getNode()).toBeNull();
});
it('should return the element itself if it matches the selector', () => {
document.body.innerHTML = '<div id="test"></div>';
fluent = Fluent(document.getElementById("test"));
const closestElement = fluent.closest('#test');
expect(closestElement.getNode()).toBe(fluent.getNode());
});
});
describe('empty', () => {
it('ignores if el is null', () => {
const f = Fluent(null);
const result = f.empty();
expect(f).toBe(result);
});
it('should return the Fluent instance', () => {
const result = fluent.empty();
expect(result).toBe(fluent);
});
it('should remove all child elements', () => {
const child1 = document.createElement('span');
const child2 = document.createElement('span');
child1.append(child2);
fluent.append(child1);
fluent.empty();
expect(fluent.getNode().children.length).toBe(0);
});
it('uses jQuery.remove if available', () => {
const empty = vi.fn();
(window as any).jQuery = vi.fn().mockReturnValue({ empty });
try {
fluent.append(document.createElement('span'));
fluent.empty();
expect(empty).toHaveBeenCalledTimes(1);
expect(fluent.getNode().children.length).toBe(1);
}
finally {
delete (window as any).jQuery;
}
});
});
describe('findAll', () => {
it('should find all elements that match the specified selector within the element', () => {
element.innerHTML = `
<span class="item">Item 1</span>
<span class="item">Item 2</span>
<span class="item">Item 3</span>
`;
const result = fluent.findAll('.item');
expect(result.length).toBe(3);
expect(result[0].textContent).toBe('Item 1');
expect(result[1].textContent).toBe('Item 2');
expect(result[2].textContent).toBe('Item 3');
});
it('should return an empty array if no elements match the specified selector', () => {
element.innerHTML = `
<span class="item">Item 1</span>
<span class="item">Item 2</span>
<span class="item">Item 3</span>
`;
const result = fluent.findAll('.non-existent');
expect(result.length).toBe(0);
});
});
describe('findEach', () => {
it('should find each element that matches the specified selector within the element and execute a callback function for each found element', () => {
element.innerHTML = `
<span class="item">Item 1</span>
<span class="item">Item 2</span>
<span class="item">Item 3</span>
`;
const callback = vi.fn();
fluent.findEach('.item', callback);
expect(callback).toHaveBeenCalledTimes(3);
expect(callback.mock.calls[0][0].getNode().textContent).toBe('Item 1');
expect(callback.mock.calls[1][0].getNode().textContent).toBe('Item 2');
expect(callback.mock.calls[2][0].getNode().textContent).toBe('Item 3');
});
it('should not execute the callback function if no elements match the specified selector', () => {
element.innerHTML = `
<span class="item">Item 1</span>
<span class="item">Item 2</span>
<span class="item">Item 3</span>
`;
const callback = vi.fn();
fluent.findEach('.non-existent', callback);
expect(callback).not.toHaveBeenCalled();
});
});
describe('findFirst', () => {
it('should find the first element that matches the specified selector within the element', () => {
element.innerHTML = `
<span class="item">Item 1</span>
<span class="item">Item 2</span>
<span class="item">Item 3</span>
`;
const result = fluent.findFirst('.item');
expect(result.getNode().textContent).toBe('Item 1');
});
it('should return null if no elements match the specified selector', () => {
element.innerHTML = `
<span class="item">Item 1</span>
<span class="item">Item 2</span>
<span class="item">Item 3</span>
`;
const result = fluent.findFirst('.non-existent');
expect(result.getNode()).toBeNull();
});
});
describe("focus", () => {
it('should ignore null element', () => {
Fluent(null).focus();
});
it("should call elements focus method", () => {
const focusSpy = vi.spyOn(fluent.getNode(), "focus");
fluent.focus();
expect(focusSpy).toHaveBeenCalledTimes(1);
});
it("should ignore if element has no focus method", () => {
fluent.getNode().focus = null;
fluent.focus();
});
});
describe('nextSibling', () => {
it('should return the next sibling of the element', () => {
document.createElement("div").appendChild(element);
const nextElement = document.createElement('span');
element.parentNode.insertBefore(nextElement, element.nextSibling);
expect(fluent.nextSibling().getNode()).toBe(nextElement);
});
it('should not return the prev sibling of the element', () => {
document.createElement("div").appendChild(element);
const nextElement = document.createElement('span');
element.parentNode.prepend(document.createElement("span"));
element.parentNode.append(nextElement, element.nextSibling);
expect(fluent.nextSibling().getNode()).toBe(nextElement);
});
it('should return the next sibling matching the selector', () => {
document.createElement("div").appendChild(element);
const nextElement = document.createElement('span');
nextElement.classList.add("test");
element.parentNode.append(document.createElement("span"));
element.parentNode.append(nextElement);
expect(fluent.nextSibling(".test").getNode()).toBe(nextElement);
});
it('should return null if no next element', () => {
document.createElement("div").appendChild(element);
element.parentNode.prepend(document.createElement("span"));
expect(fluent.nextSibling().getNode()).toBe(null);
});
it('should return null if no next matching element', () => {
document.createElement("div").appendChild(element);
element.parentNode.append(document.createElement("span"));
expect(fluent.nextSibling(".test").getNode()).toBe(null);
});
});
describe('parent', () => {
it('should return parent element of current element', () => {
document.body.appendChild(element);
expect(fluent.parent().getNode()).toBe(document.body);
});
it('should return null if current element has no parent', () => {
expect(fluent.parent().getNode()).toBeNull();
});
});
describe('prepend', () => {
it('should prepend child to the element', () => {
const child = document.createElement('span');
fluent.prepend(child);
expect(element.firstChild).toBe(child);
});
it('should prepend string as text child to the element', () => {
const child = '<span>Test</span>';
fluent.prepend(child);
expect((element.firstChild as HTMLElement)?.textContent).toBe(child);
});
it('should prepend Fluent instance as child to the element', () => {
const childElement = document.createElement('span');
const childFluent = Fluent(childElement);
fluent.prepend(childFluent);
expect(element.firstChild).toBe(childElement);
});
});
describe('prevSibling', () => {
it('should return the previous sibling of the element', () => {
document.createElement("div").appendChild(element);
const prevElement = document.createElement('span');
element.parentNode?.insertBefore(prevElement, element);
expect(fluent.prevSibling().getNode()).toBe(prevElement);
});
it('should not return the next sibling of the element', () => {
document.createElement("div").appendChild(element);
const prevElement = document.createElement('span');
element.parentNode.append(document.createElement("span"));
element.parentNode.prepend(prevElement);
expect(fluent.prevSibling().getNode()).toBe(prevElement);
});
it('should return the prev sibling matching the selector', () => {
document.createElement("div").appendChild(element);
const prevElement = document.createElement('span');
prevElement.classList.add("test");
element.parentNode.prepend(document.createElement("span"));
element.parentNode.prepend(prevElement);
expect(fluent.prevSibling(".test").getNode()).toBe(prevElement);
});
it('should return null if no prev element', () => {
document.createElement("div").appendChild(element);
element.parentNode.prepend(document.createElement("span"));
expect(fluent.nextSibling().getNode()).toBe(null);
});
it('should return null if no prev matching element', () => {
document.createElement("div").appendChild(element);
element.parentNode.prepend(document.createElement("span"));
expect(fluent.prevSibling(".test").getNode()).toBe(null);
});
});
describe('removeClass', () => {
beforeEach(() => {
element.classList.add('test-class');
element.classList.add('another-class');
});
it('should remove a single class from the element', () => {
fluent.removeClass('test-class');
expect(element.classList.contains('test-class')).toBe(false);
expect(element.classList.contains('another-class')).toBe(true);
});
it('should remove multiple classes from the element via an array', () => {
fluent.removeClass(['test-class', 'another-class']);
expect(element.classList.contains('test-class')).toBe(false);
expect(element.classList.contains('another-class')).toBe(false);
});
it('ignores false and null values in an array', () => {
fluent.removeClass([false && 'test-class', true && 'another-class', null]);
expect(element.classList.contains('test-class')).toBe(true);
expect(element.classList.contains('another-class')).toBe(false);
});
it('should remove multiple classes from the element via space-separated string', () => {
fluent.removeClass('test-class another-class');
expect(element.classList.contains('test-class')).toBe(false);
expect(element.classList.contains('another-class')).toBe(false);
});
it('should not throw an error if the class does not exist', () => {
fluent.removeClass('non-existent-class');
expect(element.classList.contains('test-class')).toBe(true);
expect(element.classList.contains('another-class')).toBe(true);
});
});
describe('show', () => {
beforeEach(() => {
fluent = Fluent(element);
});
it('should ignore null element', () => {
fluent = Fluent(null);
const result = fluent.show();
expect(result).toBe(fluent);
});
it('should set the display property to the default value', () => {
element.style.display = 'none';
const result = fluent.show();
expect(element.style.display).toBe('');
expect(result).toBe(fluent);
});
});
describe('style', () => {
it('should apply styles to the element', () => {
const callback = (css: CSSStyleDeclaration) => {
css.setProperty('color', 'red');
css.setProperty('font-size', '16px');
};
fluent.style(callback);
expect(element.style.color).toBe('red');
expect(element.style.fontSize).toBe('16px');
});
it('should override existing styles', () => {
element.style.color = 'blue';
element.style.fontSize = '14px';
const callback = (css: CSSStyleDeclaration) => {
css.setProperty('color', 'red');
css.setProperty('font-size', '16px');
};
fluent.style(callback);
expect(element.style.color).toBe('red');
expect(element.style.fontSize).toBe('16px');
});
it('should keep styles when callback is empty', () => {
element.style.color = 'blue';
element.style.fontSize = '14px';
fluent.style(() => { });
expect(element.style.color).toBe('blue');
expect(element.style.fontSize).toBe('14px');
});
it('should ignore when element is null', () => {
fluent = Fluent(null);
const callback = vi.fn();
fluent.style(callback);
expect(callback).not.toHaveBeenCalled();
});
});
describe('text', () => {
it('should set the text content of the element', () => {
fluent.text('Hello, world!');
expect(element.textContent).toBe('Hello, world!');
});
it('should return the text content of the element', () => {
element.textContent = 'Hello, world!';
const result = fluent.text();
expect(result).toBe('Hello, world!');
});
it('should return undefined for null element', () => {
fluent = Fluent(null);
const result = fluent.text();
expect(result).toBeUndefined();
});
it('should return fluent instance for null element', () => {
fluent = Fluent(null);
const result = fluent.text("test");
expect(result).toBe(fluent);
});
});
describe('toggle', () => {
beforeEach(() => {
document.body.appendChild(element);
});
afterEach(() => {
document.body.removeChild(element);
});
it('should hide the element if it is visible', () => {
fluent.toggle();
expect(element.style.display).toBe('none');
});
it('should show the element if it is hidden', () => {
element.style.display = 'none';
fluent.toggle();
expect(element.style.display).toBe('');
});
it('should hide the element if the flag is false', () => {
fluent.toggle(false);
expect(element.style.display).toBe('none');
});
it('should show the element if the flag is true', () => {
element.style.display = 'none';
fluent.toggle(true);
expect(element.style.display).toBe('');
});
it('should hide the element if the flag is not provided and it is visible', () => {
element.style.display = 'block';
fluent.toggle();
expect(element.style.display).toBe('none');
});
it('should show the element if the flag is not provided and it is hidden', () => {
element.style.display = 'none';
fluent.toggle();
expect(element.style.display).toBe('');
});
});
describe('toggleClass', () => {
beforeEach(() => {
element.classList.add('test-class');
element.classList.add('another-class');
});
it('should add the class if it does not exist', () => {
fluent.toggleClass('new-class');
expect(element.classList.contains('new-class')).toBe(true);
});
it('should remove the class if it exists', () => {
fluent.toggleClass('test-class');
expect(element.classList.contains('test-class')).toBe(false);
});
it('should add the class if the add parameter is true', () => {
fluent.toggleClass('test-class', true);
expect(element.classList.contains('test-class')).toBe(true);
});
it('should remove the class if the add parameter is false', () => {
fluent.toggleClass('test-class', false);
expect(element.classList.contains('test-class')).toBe(false);
});
it('should add multiple classes if provided as an array', () => {
fluent.toggleClass(['new-class', 'another-new-class']);
expect(element.classList.contains('new-class')).toBe(true);
expect(element.classList.contains('another-new-class')).toBe(true);
});
it('should remove multiple classes if provided as an array', () => {
fluent.toggleClass(['test-class', 'another-class']);
expect(element.classList.contains('test-class')).toBe(false);
expect(element.classList.contains('another-class')).toBe(false);
});
it('should add multiple classes if provided as a space-separated string', () => {
fluent.toggleClass('new-class another-new-class');
expect(element.classList.contains('new-class')).toBe(true);
expect(element.classList.contains('another-new-class')).toBe(true);
});
it('should remove multiple classes if provided as a space-separated string', () => {
fluent.toggleClass('test-class another-class');
expect(element.classList.contains('test-class')).toBe(false);
expect(element.classList.contains('another-class')).toBe(false);
});
it('should ignore false values', () => {
fluent.toggleClass(['test-class', false && 'another-class']);
expect(element.classList.contains('test-class')).toBe(false);
expect(element.classList.contains('another-class')).toBe(true);
});
});
describe('val', () => {
let element: HTMLInputElement;
let fluent: Fluent<HTMLInputElement>;
beforeEach(() => {
element = document.createElement('input');
fluent = Fluent(element);
});
it('should return the current value of the input element', () => {
element.value = 'Hello World';
const result = fluent.val();
expect(result).toBe('Hello World');
});
it('should set the value of the input element', () => {
fluent.val('New Value');
expect(element.value).toBe('New Value');
});
it('should chain the fluent object', () => {
const result = fluent.val('New Value');
expect(result).toBe(fluent);
});
});
});
describe('Fluent static methods', () => {
let element: HTMLElement;
beforeEach(() => {
element = document.createElement('div');
});
afterEach(() => {
element.remove();
});
describe('byId', () => {
it('should return a Fluent object with the specified element', () => {
const elementId = 'myElementId';
const element = document.createElement('div');
element.id = elementId;
document.body.appendChild(element);
const fluent = Fluent.byId(elementId);
expect(fluent.length).toBe(1);
expect(fluent.getNode()).toBe(element);
});
it('should return an empty Fluent object if the element does not exist', () => {
const elementId = 'nonExistentElementId';
const fluent = Fluent.byId(elementId);
expect(fluent.length).toBe(0);
});
});
describe('empty', () => {
it('ignores if el is null', () => {
Fluent.empty(null);
});
it('should remove all child elements', () => {
const child1 = document.createElement('span');
const child2 = document.createElement('span');
child1.append(child2);
element.appendChild(child1);
Fluent.empty(element);
expect(element.children.length).toBe(0);
});
it('uses jQuery.remove if available', () => {
const empty = vi.fn();
(window as any).jQuery = vi.fn().mockReturnValue({ empty });
try {
element.appendChild(document.createElement('span'));
Fluent.empty(element);
expect(empty).toHaveBeenCalledTimes(1);
expect(element.children.length).toBe(1);
}
finally {
delete (window as any).jQuery;
}
});
});
describe('eventProp', () => {
it('should return the value of the specified property from the event object', () => {
const event = { value: 'Hello, World!' };
const result = Fluent.eventProp(event, 'value');
expect(result).toBe('Hello, World!');
});
it('should return undefined if the specified property does not exist in the event object', () => {
const event = { value: 'Hello, World!' };
const result = Fluent.eventProp(event, 'invalidProperty');
expect(result).toBeUndefined();
});
it('should return undefined if the event object is null', () => {
const event = null as any;
const result = Fluent.eventProp(event, 'value');
expect(result).toBeUndefined();
});
it('should return undefined if the event object is undefined', () => {
const event = undefined as any;
const result = Fluent.eventProp(event, 'value');
expect(result).toBeUndefined();
});
it('should return value from the originalEvent if it is an object with that prop', () => {
const event = { originalEvent: { value: 5 } }
const result = Fluent.eventProp(event, 'value');
expect(result).toBe(5);
});
it('should return value from the detail if it is an object with that prop', () => {
const event = { detail: { value: 5 } }
const result = Fluent.eventProp(event, 'value');
expect(result).toBe(5);
});
});
describe('findAll', () => {
it('should find all elements that match the specified selector within the element', () => {
document.body.append(element);
element.innerHTML = `
<span class="item">Item 1</span>
<span class="item">Item 2</span>
<span class="item">Item 3</span>
`;
const result = Fluent.findAll('.item');
expect(result.length).toBe(3);
expect(result[0].textContent).toBe('Item 1');
expect(result[1].textContent).toBe('Item 2');
expect(result[2].textContent).toBe('Item 3');
});
it('should return an empty array if no elements match the specified selector', () => {
document.body.append(element);
element.innerHTML = `
<span class="item">Item 1</span>
<span class="item">Item 2</span>
<span class="item">Item 3</span>
`;
const result = Fluent.findAll('.non-existent');
expect(result.length).toBe(0);
});
});
describe('findEach', () => {
it('should find each element that matches the specified selector within the element and execute a callback function for each found element', () => {
document.body.append(element);
element.innerHTML = `
<span class="item">Item 1</span>
<span class="item">Item 2</span>
<span class="item">Item 3</span>
`;
const callback = vi.fn();
Fluent.findEach('.item', callback);
expect(callback).toHaveBeenCalledTimes(3);
expect(callback.mock.calls[0][0].getNode().textContent).toBe('Item 1');
expect(callback.mock.calls[1][0].getNode().textContent).toBe('Item 2');
expect(callback.mock.calls[2][0].getNode().textContent).toBe('Item 3');
});
it('should not execute the callback function if no elements match the specified selector', () => {
document.body.append(element);
element.innerHTML = `
<span class="item">Item 1</span>
<span class="item">Item 2</span>
<span class="item">Item 3</span>
`;
const callback = vi.fn();
Fluent.findEach('.non-existent', callback);
expect(callback).not.toHaveBeenCalled();
});
});
describe('findFirst', () => {
it('should find the first element that matches the specified selector within the element', () => {
document.body.appendChild(element);
element.innerHTML = `
<span class="item">Item 1</span>
<span class="item">Item 2</span>
<span class="item">Item 3</span>
`;
const result = Fluent.findFirst('.item');
expect(result.getNode().textContent).toBe('Item 1');
});
it('should return null if no elements match the specified selector', () => {
document.body.appendChild(element);
element.innerHTML = `
<span class="item">Item 1</span>
<span class="item">Item 2</span>
<span class="item">Item 3</span>
`;
const result = Fluent.findFirst('.non-existent');
expect(result.getNode()).toBeNull();
});
});
describe('isInputLike', () => {
it('should return true for input element', () => {
const inputElement = document.createElement('input');
const result = Fluent.isInputLike(inputElement);
expect(result).toBe(true);
});
it('should return true for select element', () => {
const selectElement = document.createElement('select');
const result = Fluent.isInputLike(selectElement);
expect(result).toBe(true);
});
it('should return true for textarea element', () => {
const textareaElement = document.createElement('textarea');
const result = Fluent.isInputLike(textareaElement);
expect(result).toBe(true);
});
it('should return true for button element', () => {
const buttonElement = document.createElement('button');
const result = Fluent.isInputLike(buttonElement);
expect(result).toBe(true);
});
it('should return false for div element', () => {
const divElement = document.createElement('div');
const result = Fluent.isInputLike(divElement);
expect(result).toBe(false);
});
it('should return false for null element', () => {
expect(Fluent.isInputLike(null)).toBe(false);
});
});
describe("isInputTag", () => {
it("should return true for input tag", () => {
const result = Fluent.isInputTag("input");
expect(result).toBe(true);
});
it("should return true for select tag", () => {
const result = Fluent.isInputTag("select");
expect(result).toBe(true);
});
it("should return true for textarea tag", () => {
const result = Fluent.isInputTag("textarea");
expect(result).toBe(true);
});
it("should return true for button tag", () => {
const result = Fluent.isInputTag("button");
expect(result).toBe(true);
});
it("should return false for div tag", () => {
const result = Fluent.isInputTag("div");
expect(result).toBe(false);
});
});
describe("isVisibleLike", () => {
it("returns false if el is null", () => {
expect(Fluent.isVisibleLike(null)).toBe(false);
expect(Fluent.isVisibleLike(undefined)).toBe(false);
});
it("returns false if offsetWidth, offsetHeight and getClientRects().length is 0", () => {
Object.defineProperties(element, {
offsetWidth: { get: () => 0 },
offsetHeight: { get: () => 0 },
getClientRects: { get: () => (function () { return { length: 0 } }) }
});
expect(Fluent.isVisibleLike(element)).toBe(false);
});
it("returns true if offsetWidth > 0", () => {
Object.defineProperties(element, {
offsetWidth: { get: () => 1 },
offsetHeight: { get: () => 0 },
getClientRects: { get: () => (function () { return { length: 0 } }) }
});
expect(Fluent.isVisibleLike(element)).toBe(true);
});
it("returns true if offsetHeight > 0", () => {
Object.defineProperties(element, {
offsetWidth: { get: () => 0 },
offsetHeight: { get: () => 1 },
getClientRects: { get: () => (function () { return { length: 0 } }) }
});
expect(Fluent.isVisibleLike(element)).toBe(true);
});
it("returns true if clientRects.length > 0", () => {
Object.defineProperties(element, {
offsetWidth: { get: () => 0 },
offsetHeight: { get: () => 0 },
getClientRects: { get: () => (function () { return { length: 1 } }) }
});
expect(Fluent.isVisibleLike(element)).toBe(true);
});
});
describe("remove", () => {
it("should ignore null and undefined", () => {
Fluent.remove(null);
Fluent.remove(undefined);
});
it("should remove the element from the DOM", () => {
document.body.appendChild(element);
expect(document.body.contains(element)).toBe(true);
Fluent.remove(element);
expect(document.body.contains(element)).toBe(false);
});
it("should remove event listeners", () => {
document.body.appendChild(element);
const listener = vi.fn();
Fluent.on(element, "click", listener);
Fluent.remove(element);
element.click();
expect(listener).not.toHaveBeenCalled();
});
});
describe("toClassName", () => {
it("should convert a string to a valid CSS class name", () => {
const className = Fluent.toClassName("my-class");
expect(className).toBe("my-class");
});
it("should leave a string with spaces as is", () => {
const className = Fluent.toClassName("my class");
expect(className).toBe("my class");
});
it("should convert an empty string to an empty CSS class name", () => {
const className = Fluent.toClassName("");
expect(className).toBe("");
});
it("should convert numbers to string", () => {
const className = Fluent.toClassName(1 as any);
expect(className).toBe("1");
});
});
});