UNPKG

@furystack/shades-common-components

Version:

Common UI components for FuryStack Shades

254 lines 11.7 kB
import { createInjector } from '@furystack/inject'; import { createComponent, initializeShadeRoot, Shade } from '@furystack/shades'; import { ObservableValue, sleepAsync, usingAsync } from '@furystack/utils'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { ThemeProviderService } from '../services/theme-provider-service.js'; import { LinearProgress } from './linear-progress.js'; const ProgressWrapper = Shade({ customElementName: 'test-linear-progress-wrapper', render: ({ props, useObservable }) => { const [value] = useObservable('value', props.obs); return createComponent(LinearProgress, { variant: "determinate", value: value }); }, }); describe('LinearProgress', () => { let originalAnimate; beforeEach(() => { document.body.innerHTML = '<div id="root"></div>'; originalAnimate = Element.prototype.animate; Element.prototype.animate = vi.fn((_keyframes, _options) => { const mockAnimation = { onfinish: null, oncancel: null, cancel: vi.fn(), play: vi.fn(), pause: vi.fn(), finish: vi.fn(), addEventListener: vi.fn(), removeEventListener: vi.fn(), }; return mockAnimation; }); }); afterEach(() => { document.body.innerHTML = ''; Element.prototype.animate = originalAnimate; vi.restoreAllMocks(); }); it('should render as custom element', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, null), }); await sleepAsync(50); const el = document.querySelector('shade-linear-progress'); expect(el).not.toBeNull(); }); }); it('should render the progress bar element', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, null), }); await sleepAsync(50); const bar = document.querySelector('shade-linear-progress .progress-bar'); expect(bar).not.toBeNull(); }); }); it('should set role="progressbar"', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, null), }); await sleepAsync(50); const el = document.querySelector('shade-linear-progress'); expect(el.getAttribute('role')).toBe('progressbar'); }); }); describe('determinate variant', () => { it('should set aria-valuenow for determinate variant', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, { variant: "determinate", value: 50 }), }); await sleepAsync(50); const el = document.querySelector('shade-linear-progress'); expect(el.getAttribute('aria-valuenow')).toBe('50'); expect(el.getAttribute('aria-valuemin')).toBe('0'); expect(el.getAttribute('aria-valuemax')).toBe('100'); }); }); it('should set bar width based on value', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, { variant: "determinate", value: 75 }), }); await sleepAsync(50); const bar = document.querySelector('shade-linear-progress .progress-bar'); expect(bar.style.width).toBe('75%'); }); }); it('should clamp value to 0-100 range', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, { variant: "determinate", value: 150 }), }); await sleepAsync(50); const bar = document.querySelector('shade-linear-progress .progress-bar'); expect(bar.style.width).toBe('100%'); }); }); it('should clamp negative values to 0', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, { variant: "determinate", value: -20 }), }); await sleepAsync(50); const bar = document.querySelector('shade-linear-progress .progress-bar'); expect(bar.style.width).toBe('0%'); }); }); it('should update bar width when value prop changes', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const obs = new ObservableValue(20); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(ProgressWrapper, { obs: obs }), }); await sleepAsync(50); const bar = document.querySelector('shade-linear-progress .progress-bar'); expect(bar.style.width).toBe('20%'); obs.setValue(80); await sleepAsync(50); expect(bar.style.width).toBe('80%'); }); }); it('should update aria-valuenow when value prop changes', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); const obs = new ObservableValue(30); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(ProgressWrapper, { obs: obs }), }); await sleepAsync(50); const el = document.querySelector('shade-linear-progress'); expect(el.getAttribute('aria-valuenow')).toBe('30'); obs.setValue(90); await sleepAsync(50); expect(el.getAttribute('aria-valuenow')).toBe('90'); }); }); }); describe('indeterminate variant', () => { it('should default to indeterminate variant', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, null), }); await sleepAsync(50); const bar = document.querySelector('shade-linear-progress .progress-bar'); expect(bar.hasAttribute('data-indeterminate')).toBe(true); }); }); it('should not set aria-valuenow for indeterminate variant', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, null), }); await sleepAsync(50); const el = document.querySelector('shade-linear-progress'); expect(el.hasAttribute('aria-valuenow')).toBe(false); }); }); }); describe('size', () => { it('should set data-size="small" when size is small', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, { size: "small" }), }); await sleepAsync(50); const el = document.querySelector('shade-linear-progress'); expect(el.getAttribute('data-size')).toBe('small'); }); }); it('should not set data-size when size is medium (default)', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, null), }); await sleepAsync(50); const el = document.querySelector('shade-linear-progress'); expect(el.hasAttribute('data-size')).toBe(false); }); }); }); describe('theme integration', () => { it('should set CSS color variable from theme', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, null), }); await sleepAsync(50); const el = document.querySelector('shade-linear-progress'); const themeService = injector.get(ThemeProviderService); expect(el.style.getPropertyValue('--progress-color')).toBe(themeService.theme.palette.primary.main); }); }); it('should use custom color from color prop', async () => { await usingAsync(createInjector(), async (injector) => { const rootElement = document.getElementById('root'); initializeShadeRoot({ injector, rootElement, jsxElement: createComponent(LinearProgress, { color: "error" }), }); await sleepAsync(50); const el = document.querySelector('shade-linear-progress'); const themeService = injector.get(ThemeProviderService); expect(el.style.getPropertyValue('--progress-color')).toBe(themeService.theme.palette.error.main); }); }); }); }); //# sourceMappingURL=linear-progress.spec.js.map