@furystack/shades-common-components
Version:
Common UI components for FuryStack Shades
122 lines • 5.7 kB
JavaScript
import { createInjector } from '@furystack/inject';
import { createComponent, flushUpdates, initializeShadeRoot } from '@furystack/shades';
import { usingAsync } from '@furystack/utils';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { Skeleton } from './skeleton.js';
describe('Skeleton', () => {
let originalAnimate;
let animateCalls;
beforeEach(() => {
document.body.innerHTML = '<div id="root"></div>';
animateCalls = [];
originalAnimate = Element.prototype.animate;
Element.prototype.animate = vi.fn((keyframes, options) => {
animateCalls.push({ 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(),
};
if (Array.isArray(keyframes) && keyframes.some((kf) => 'opacity' in kf)) {
setTimeout(() => {
if (mockAnimation.onfinish) {
mockAnimation.onfinish({});
}
}, 10);
}
return mockAnimation;
});
});
afterEach(() => {
document.body.innerHTML = '';
Element.prototype.animate = originalAnimate;
vi.restoreAllMocks();
});
it('should render with correct initial state and default delay', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: createComponent(Skeleton, null),
});
await flushUpdates();
await new Promise((resolve) => setTimeout(resolve, 0));
const skeleton = document.querySelector('shade-skeleton');
expect(skeleton).not.toBeNull();
const skeletonDiv = document.querySelector('shade-skeleton div');
expect(skeletonDiv).not.toBeNull();
const computedStyle = window.getComputedStyle(skeletonDiv);
expect(computedStyle.opacity).toBe('0');
expect(computedStyle.display).toBe('inline-block');
const fadeInCall = animateCalls.find((call) => Array.isArray(call.keyframes) && call.keyframes.some((kf) => 'opacity' in kf));
expect(fadeInCall).toBeDefined();
expect(fadeInCall?.options?.delay).toBe(1500);
});
});
it('should use custom delay when provided', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: createComponent(Skeleton, { delay: 500 }),
});
await flushUpdates();
await new Promise((resolve) => setTimeout(resolve, 0));
const fadeInCall = animateCalls.find((call) => Array.isArray(call.keyframes) && call.keyframes.some((kf) => 'opacity' in kf));
expect(fadeInCall).toBeDefined();
expect(fadeInCall?.options?.delay).toBe(500);
});
});
it('should start fade-in animation with correct parameters', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: createComponent(Skeleton, { delay: 100 }),
});
await flushUpdates();
await new Promise((resolve) => setTimeout(resolve, 0));
const fadeInCall = animateCalls.find((call) => Array.isArray(call.keyframes) &&
call.keyframes.length === 2 &&
call.keyframes[0].opacity === 0 &&
call.keyframes[1].opacity === 1);
expect(fadeInCall).toBeDefined();
const options = fadeInCall?.options;
expect(options.fill).toBe('forwards');
expect(options.duration).toBe(300);
expect(options.easing).toBe('ease-out');
expect(options.delay).toBe(100);
});
});
it('should start background animation with correct keyframes after fade-in completes', async () => {
await usingAsync(createInjector(), async (injector) => {
const rootElement = document.getElementById('root');
initializeShadeRoot({
injector,
rootElement,
jsxElement: createComponent(Skeleton, { delay: 0 }),
});
await flushUpdates();
await new Promise((resolve) => setTimeout(resolve, 50));
const backgroundAnimation = animateCalls.find((call) => Array.isArray(call.keyframes) && call.keyframes.some((kf) => 'backgroundPosition' in kf));
expect(backgroundAnimation).toBeDefined();
const options = backgroundAnimation?.options;
expect(options.duration).toBe(10000);
expect(options.iterations).toBe(Infinity);
const keyframes = backgroundAnimation?.keyframes;
expect(keyframes).toHaveLength(3);
expect(keyframes[0].backgroundPosition).toBe('0% 50%');
expect(keyframes[1].backgroundPosition).toBe('100% 50%');
expect(keyframes[2].backgroundPosition).toBe('0% 50%');
});
});
});
//# sourceMappingURL=skeleton.spec.js.map