UNPKG

@furystack/shades

Version:

A lightweight UI framework for FuryStack with JSX support

184 lines 8.21 kB
import { afterEach, describe, expect, it, vi } from 'vitest'; import { maybeViewTransition, transitionedValue } from './view-transition.js'; describe('maybeViewTransition', () => { afterEach(() => { delete document.startViewTransition; }); const mockStartViewTransition = () => { const spy = vi.fn((optionsOrCallback) => { const update = typeof optionsOrCallback === 'function' ? optionsOrCallback : optionsOrCallback.update; update?.(); return { finished: Promise.resolve(), ready: Promise.resolve(), updateCallbackDone: Promise.resolve(), skipTransition: vi.fn(), }; }); document.startViewTransition = spy; return spy; }; it('should call update directly when config is undefined', () => { const spy = mockStartViewTransition(); const update = vi.fn(); const result = maybeViewTransition(undefined, update); expect(update).toHaveBeenCalledTimes(1); expect(spy).not.toHaveBeenCalled(); expect(result).toBeUndefined(); }); it('should call update directly when config is false', () => { const spy = mockStartViewTransition(); const update = vi.fn(); const result = maybeViewTransition(false, update); expect(update).toHaveBeenCalledTimes(1); expect(spy).not.toHaveBeenCalled(); expect(result).toBeUndefined(); }); it('should call update directly when startViewTransition is not available', () => { const update = vi.fn(); const result = maybeViewTransition(true, update); expect(update).toHaveBeenCalledTimes(1); expect(result).toBeUndefined(); }); it('should call startViewTransition when config is true and API is available', () => { const spy = mockStartViewTransition(); const update = vi.fn(); const result = maybeViewTransition(true, update); expect(spy).toHaveBeenCalledTimes(1); expect(update).toHaveBeenCalledTimes(1); expect(result).toBeInstanceOf(Promise); }); it('should use callback form when config is true', () => { const spy = mockStartViewTransition(); const update = vi.fn(); void maybeViewTransition(true, update); expect(spy).toHaveBeenCalledWith(update); }); it('should pass types when config is an object with types', () => { const spy = mockStartViewTransition(); const update = vi.fn(); const config = { types: ['slide', 'fade'] }; void maybeViewTransition(config, update); expect(spy).toHaveBeenCalledWith({ update, types: ['slide', 'fade'] }); }); it('should use callback form when config object has empty types array', () => { const spy = mockStartViewTransition(); const update = vi.fn(); const config = { types: [] }; void maybeViewTransition(config, update); expect(spy).toHaveBeenCalledWith(update); }); it('should use callback form when config object has no types', () => { const spy = mockStartViewTransition(); const update = vi.fn(); const config = {}; void maybeViewTransition(config, update); expect(spy).toHaveBeenCalledWith(update); }); it('should return updateCallbackDone promise when transition is started', async () => { mockStartViewTransition(); const update = vi.fn(); const result = maybeViewTransition(true, update); expect(result).toBeInstanceOf(Promise); await expect(result).resolves.toBeUndefined(); }); }); describe('transitionedValue', () => { afterEach(() => { delete document.startViewTransition; }); const mockStartViewTransition = () => { const spy = vi.fn((optionsOrCallback) => { const update = typeof optionsOrCallback === 'function' ? optionsOrCallback : optionsOrCallback.update; update?.(); return { finished: Promise.resolve(), ready: Promise.resolve(), updateCallbackDone: Promise.resolve(), skipTransition: vi.fn(), }; }); document.startViewTransition = spy; return spy; }; const createMockUseState = () => { const store = new Map(); const setters = new Map(); const mockUseState = (key, initialValue) => { if (!store.has(key)) { store.set(key, initialValue); } const setValue = (v) => { store.set(key, v); }; setters.set(key, setValue); return [store.get(key), setValue]; }; return { mockUseState, store }; }; it('should return the value when it equals the displayed value', () => { const { mockUseState } = createMockUseState(); const result = transitionedValue(mockUseState, 'key', 'hello', true); expect(result).toBe('hello'); }); it('should not call startViewTransition when value has not changed', () => { const spy = mockStartViewTransition(); const { mockUseState } = createMockUseState(); transitionedValue(mockUseState, 'key', 'hello', true); expect(spy).not.toHaveBeenCalled(); }); it('should call startViewTransition when value changes and config is truthy', () => { const spy = mockStartViewTransition(); const { mockUseState, store } = createMockUseState(); transitionedValue(mockUseState, 'key', 'initial', true); store.set('key', 'initial'); transitionedValue(mockUseState, 'key', 'updated', true); expect(spy).toHaveBeenCalledTimes(1); expect(store.get('key')).toBe('updated'); }); it('should not call startViewTransition when config is falsy', () => { const spy = mockStartViewTransition(); const { mockUseState, store } = createMockUseState(); transitionedValue(mockUseState, 'key', 'initial', undefined); store.set('key', 'initial'); transitionedValue(mockUseState, 'key', 'updated', undefined); expect(spy).not.toHaveBeenCalled(); expect(store.get('key')).toBe('updated'); }); it('should not call startViewTransition when shouldTransition returns false', () => { const spy = mockStartViewTransition(); const { mockUseState, store } = createMockUseState(); transitionedValue(mockUseState, 'key', 'initial', true, () => false); store.set('key', 'initial'); transitionedValue(mockUseState, 'key', 'updated', true, () => false); expect(spy).not.toHaveBeenCalled(); expect(store.get('key')).toBe('updated'); }); it('should call startViewTransition when shouldTransition returns true', () => { const spy = mockStartViewTransition(); const { mockUseState, store } = createMockUseState(); transitionedValue(mockUseState, 'key', 'initial', true, () => true); store.set('key', 'initial'); transitionedValue(mockUseState, 'key', 'updated', true, () => true); expect(spy).toHaveBeenCalledTimes(1); expect(store.get('key')).toBe('updated'); }); it('should pass prev and next values to shouldTransition', () => { mockStartViewTransition(); const { mockUseState, store } = createMockUseState(); const shouldTransition = vi.fn(() => true); transitionedValue(mockUseState, 'key', 'initial', true, shouldTransition); store.set('key', 'initial'); transitionedValue(mockUseState, 'key', 'updated', true, shouldTransition); expect(shouldTransition).toHaveBeenCalledWith('initial', 'updated'); }); it('should default shouldTransition to always true', () => { const spy = mockStartViewTransition(); const { mockUseState, store } = createMockUseState(); transitionedValue(mockUseState, 'key', 'a', true); store.set('key', 'a'); transitionedValue(mockUseState, 'key', 'b', true); expect(spy).toHaveBeenCalledTimes(1); }); }); //# sourceMappingURL=view-transition.spec.js.map