const { describe, test } = require('node:test'); const assert = require('node:assert'); const { BB, resetMockElement } = require('./setup'); describe('BB.sources.select', () => { test('sets currentSource state', async () => { await BB.sources.select('s1'); assert.strictEqual(BB.state.currentSource, 's1'); }); test('resets pagination', async () => { BB.state.set('currentPage', 5); await BB.sources.select('s2'); assert.strictEqual(BB.state.currentPage, 0); }); test('clears selectedItemId', async () => { BB.state.set('selectedItemId', 'x'); await BB.sources.select(''); assert.strictEqual(BB.state.selectedItemId, null); }); test('clears currentQueryFeed', async () => { BB.state.set('currentQueryFeed', 'qf'); await BB.sources.select('s1'); assert.strictEqual(BB.state.currentQueryFeed, null); }); }); describe('BB.sources.selectTag', () => { test('sets currentTag', async () => { await BB.sources.selectTag('tech'); assert.strictEqual(BB.state.currentTag, 'tech'); }); test('resets pagination', async () => { BB.state.set('currentPage', 3); await BB.sources.selectTag('news'); assert.strictEqual(BB.state.currentPage, 0); }); }); describe('BB.sources.load', () => { test('populates state', async () => { await BB.sources.load(); assert.strictEqual(BB.state.sources.length, 2); assert.deepStrictEqual(BB.state.allTags, ['news', 'tech']); }); }); describe('BB.sources.render', () => { test('renderSourceList creates correct number of source elements', () => { resetMockElement('sources-list'); const sources = [ { id: 's1', name: 'Feed A', totalCount: 10, unreadCount: 3, tags: ['news'], health: 'green' }, { id: 's2', name: 'Feed B', totalCount: 5, unreadCount: 0, tags: [], health: 'yellow', lastError: 'timeout' }, { id: 's3', name: 'Feed C', totalCount: 0, unreadCount: 0, tags: [], health: 'red', lastError: 'dns fail' }, ]; BB.state.set('currentSource', ''); BB.state.set('queryFeeds', []); BB.sources.render(sources); const list = document.getElementById('sources-list'); // 1 All + 3 source items + 1 "+ Query Feed" button assert.strictEqual(list.children.length, 5); }); test('source health indicator shows correct class for yellow', () => { resetMockElement('sources-list'); const sources = [ { id: 's1', name: 'Feed A', totalCount: 5, unreadCount: 0, tags: [], health: 'yellow', lastError: 'timeout' }, ]; BB.state.set('currentSource', ''); BB.state.set('queryFeeds', []); BB.sources.render(sources); const list = document.getElementById('sources-list'); const sourceItem = list.children[1]; // children[0] is "All", sources start at [1] assert.ok(sourceItem.innerHTML.includes('data-health="yellow"'), 'Should have data-health="yellow" attribute'); }); test('source with unreadCount=0 shows total via all-read style (no slash, no checkmark)', () => { resetMockElement('sources-list'); const sources = [ { id: 's1', name: 'Feed A', totalCount: 5, unreadCount: 0, tags: [], health: 'green' }, ]; BB.state.set('currentSource', ''); BB.state.set('queryFeeds', []); BB.sources.render(sources); const list = document.getElementById('sources-list'); const sourceItem = list.children[1]; // children[0] is "All" assert.ok(sourceItem.innerHTML.includes('all-read'), 'Should mark the count all-read (green)'); assert.ok(sourceItem.innerHTML.includes('5'), 'Should show total count'); assert.ok(!sourceItem.innerHTML.includes('0/5'), 'Should not show 0/X format'); assert.ok(!sourceItem.innerHTML.includes('\u2713'), 'Should not show a checkmark'); }); test('source with lastError shows error text in health dot title', () => { resetMockElement('sources-list'); const sources = [ { id: 's1', name: 'Feed A', totalCount: 5, unreadCount: 0, tags: [], health: 'red', lastError: 'dns fail' }, ]; BB.state.set('currentSource', ''); BB.state.set('queryFeeds', []); BB.sources.render(sources); const list = document.getElementById('sources-list'); const sourceItem = list.children[1]; // children[0] is "All" assert.ok(sourceItem.innerHTML.includes('dns fail'), 'Should include error text'); }); test('empty sources array renders All item, onboarding, and + button', () => { resetMockElement('sources-list'); BB.state.set('currentSource', ''); BB.state.set('queryFeeds', []); BB.sources.render([]); const list = document.getElementById('sources-list'); // All item + onboarding message + "+ Query Feed" button assert.strictEqual(list.children.length, 3); assert.ok(list.children[0].innerHTML.includes('All'), 'Should have All entry'); assert.ok(list.children[1].innerHTML.includes('Add your first feed'), 'Should have onboarding message'); }); });