/**
* Tests for services/ui.js
*
* Tests UI utility functions: progress bars, spinners, error display,
* inline errors, escapeHtmlFallback, and notification system.
*/
import '@js/security/xss-protection.js';
import '@js/services/ui.js';
const ui = window.ui;
describe('ui service', () => {
describe('updateProgressBar', () => {
let fill, pct;
beforeEach(() => {
fill = document.createElement('div');
fill.id = 'test-fill';
pct = document.createElement('span');
pct.id = 'test-pct';
document.body.appendChild(fill);
document.body.appendChild(pct);
});
afterEach(() => {
fill.remove();
pct.remove();
});
it('sets width and text for percentage', () => {
ui.updateProgressBar(fill, pct, 42);
expect(fill.style.width).toBe('42%');
expect(pct.textContent).toBe('42%');
});
it('clamps percentage to 0-100', () => {
ui.updateProgressBar(fill, pct, -10);
expect(fill.style.width).toBe('0%');
expect(pct.textContent).toBe('0%');
ui.updateProgressBar(fill, pct, 150);
expect(fill.style.width).toBe('100%');
expect(pct.textContent).toBe('100%');
});
it('handles null/undefined percentage as 0', () => {
ui.updateProgressBar(fill, pct, null);
expect(fill.style.width).toBe('0%');
});
it('adds ldr-complete class at 100%', () => {
ui.updateProgressBar(fill, pct, 100);
expect(fill.classList.contains('ldr-complete')).toBe(true);
});
it('removes ldr-complete class when below 100%', () => {
fill.classList.add('ldr-complete');
ui.updateProgressBar(fill, pct, 50);
expect(fill.classList.contains('ldr-complete')).toBe(false);
});
it('accepts string IDs instead of elements', () => {
ui.updateProgressBar('test-fill', 'test-pct', 75);
expect(fill.style.width).toBe('75%');
expect(pct.textContent).toBe('75%');
});
it('rounds percentage text', () => {
ui.updateProgressBar(fill, pct, 33.7);
expect(pct.textContent).toBe('34%');
});
});
describe('showSpinner / hideSpinner', () => {
let container;
beforeEach(() => {
container = document.createElement('div');
container.id = 'spinner-container';
document.body.appendChild(container);
});
afterEach(() => {
container.remove();
});
it('creates a spinner element in the container', () => {
ui.showSpinner(container, 'Loading data...');
expect(container.querySelector('.ldr-loading-spinner')).not.toBeNull();
});
it('displays the message text', () => {
ui.showSpinner(container, 'Please wait');
expect(container.textContent).toContain('Please wait');
});
it('escapes HTML in the message', () => {
ui.showSpinner(container, '');
expect(container.innerHTML).not.toContain('');
const span = el.querySelector('span');
expect(span.textContent).toBe('');
expect(span.innerHTML).not.toContain('