/** * @jest-environment jsdom * * Daily-templates sidebar panel tests. */ const { renderDailyTemplatesPanel } = require('../src/sidebar/daily-templates-panel'); function mountPanel(deps = {}) { const container = document.createElement('div'); document.body.appendChild(container); const api = renderDailyTemplatesPanel(container, { listTemplates: deps.listTemplates || jest.fn().mockResolvedValue([]), saveTemplate: deps.saveTemplate || jest.fn().mockResolvedValue({ name: 'x.md', label: 'X', content: '' }), deleteTemplate: deps.deleteTemplate || jest.fn().mockResolvedValue(true), applyTemplate: deps.applyTemplate || jest.fn().mockResolvedValue({ path: '/d/2026-09-14.md', content: '', created: true }), onOpenFile: deps.onOpenFile || jest.fn(), ...deps, }); return { container, api }; } async function flush() { for (let i = 0; i < 5; i++) await Promise.resolve(); } describe('renderDailyTemplatesPanel — mounting', () => { test('mounts the panel structure', () => { const { container } = mountPanel(); expect(container.querySelector('.daily-templates-panel')).not.toBeNull(); expect(container.querySelector('#daily-templates-new')).not.toBeNull(); expect(container.querySelector('#daily-templates-refresh')).not.toBeNull(); }); test('shows the empty state when there are no templates', async () => { const { container } = mountPanel({ listTemplates: jest.fn().mockResolvedValue([]) }); await flush(); expect(container.querySelector('.daily-templates-empty')).not.toBeNull(); }); test('renders one row per template', async () => { const { container } = mountPanel({ listTemplates: jest.fn().mockResolvedValue([ { name: 'morning-pages.md', label: 'Morning Pages', content: '# Morning' }, { name: 'evening.md', label: 'Evening', content: '# Evening' }, ]), }); await flush(); const items = container.querySelectorAll('.daily-templates-item'); expect(items).toHaveLength(2); expect(items[0].textContent).toContain('Morning Pages'); expect(items[1].textContent).toContain('Evening'); }); test('escapeHtml-style safety: a label with ', content: '' }]), }); await flush(); expect(container.querySelector('script')).toBeNull(); // The literal text survives in the row (textContent keeps it visible as // text rather than as a node — the safety we want). expect(container.querySelector('.daily-templates-item').textContent).toContain('