UNPKG

daynitejs

Version:

A lightweight JavaScript library for toggling light and dark themes.

150 lines (140 loc) 4.69 kB
/** * Unit tests for DayniteJs core logic. */ import DayniteJs from '../src/core/DayniteJs.js'; // --- Global Mocks --- let themeAttr = 'light'; let darkClass = false; let customStyles = {}; const mockClassList = { add: jest.fn((cls) => { if (cls === 'dark') darkClass = true; }), remove: jest.fn((cls) => { if (cls === 'dark') darkClass = false; }), contains: jest.fn((cls) => (cls === 'dark' ? darkClass : false)) }; const mockStyle = { setProperty: jest.fn((key, val) => { customStyles[key] = val; }), getPropertyValue: jest.fn((key) => customStyles[key] || '') }; const mockDocumentElement = { setAttribute: jest.fn((attr, val) => { if (attr === 'data-theme') { themeAttr = val; // keep localStorageStore in sync for theme localStorageStore['DayniteJs-theme'] = val; } }), getAttribute: jest.fn((attr) => { if (attr === 'data-theme') return themeAttr; return null; }), classList: mockClassList, style: mockStyle }; Object.defineProperty(document, 'documentElement', { value: mockDocumentElement, configurable: true }); // Mock localStorage globally so all modules use the same reference let localStorageStore = {}; const originalLocalStorage = globalThis.localStorage; globalThis.localStorage = { getItem: (key) => localStorageStore[key] || null, setItem: (key, val) => { localStorageStore[key] = val; }, removeItem: (key) => { delete localStorageStore[key]; }, clear: () => { localStorageStore = {}; } }; // Mock matchMedia const mockMatchMedia = (matches) => ({ matches, addEventListener: jest.fn(), removeEventListener: jest.fn() }); window.matchMedia = jest.fn(() => mockMatchMedia(false)); beforeEach(() => { jest.useFakeTimers(); jest.clearAllMocks(); themeAttr = 'light'; darkClass = false; customStyles = {}; localStorageStore = {}; window.matchMedia.mockImplementation(() => mockMatchMedia(false)); window.requestAnimationFrame = (cb) => cb(); // Ensure themeAttr is reset for each test document.documentElement.setAttribute('data-theme', 'light'); // Reset localStorageStore after each toggle to ensure isolation globalThis.localStorageStore = {}; }); afterAll(() => { globalThis.localStorage = originalLocalStorage; }); test('initializes with default theme', (done) => { jest.setTimeout(10000); jest.runAllTimers(); expect(document.documentElement.getAttribute('data-theme')).toBe('light'); expect(darkClass).toBe(false); done(); }); test('initializes with stored theme', (done) => { jest.setTimeout(10000); globalThis.localStorage.setItem('DayniteJs-theme', 'dark'); // Re-import DayniteJs to ensure it reads the stored theme after localStorage is set const DayniteJsReloaded = require('../src/core/DayniteJs.js').default; const daynite = new DayniteJsReloaded(); jest.runAllTimers(); expect(document.documentElement.getAttribute('data-theme')).toBe('dark'); expect(darkClass).toBe(true); done(); }); test('toggles between themes', (done) => { // Ensure starting state is light document.documentElement.setAttribute('data-theme', 'light'); darkClass = false; const daynite = new DayniteJs({ themes: ['light', 'dark'] }); daynite.toggle(); jest.runAllTimers(); expect(document.documentElement.getAttribute('data-theme')).toBe('dark'); expect(darkClass).toBe(true); daynite.toggle(); jest.runAllTimers(); expect(document.documentElement.getAttribute('data-theme')).toBe('light'); expect(darkClass).toBe(false); done(); }); test('applies custom styles', (done) => { const daynite = new DayniteJs({ customStyles: { dark: { '--bg-color': '#111' } } }); daynite.setTheme('dark'); jest.runAllTimers(); expect(customStyles['--bg-color']).toBe('#111'); done(); }); test('emits theme change events', (done) => { const daynite = new DayniteJs(); let called = false; daynite.onThemeChange((theme) => { if (theme === 'dark' && !called) { expect(theme).toBe('dark'); called = true; done(); } }); daynite.setTheme('dark'); jest.runAllTimers(); }); test('handles invalid theme', (done) => { const consoleWarn = jest.spyOn(console, 'warn').mockImplementation(); const daynite = new DayniteJs(); daynite.setTheme('invalid'); jest.runAllTimers(); expect(document.documentElement.getAttribute('data-theme')).toBe('light'); expect(consoleWarn).toHaveBeenCalled(); consoleWarn.mockRestore(); done(); });