/** * 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('