Skip to main content

max / balanced_breakfast

4.7 KB · 119 lines History Blame Raw
1 const { describe, test, beforeEach } = require('node:test');
2 const assert = require('node:assert');
3 const { BB, resetMockElement, apiCalls, resetItemFixtures } = require('./setup');
4
5 // The item mocks write back to their fixtures, so each test starts from the
6 // same two items rather than from whatever the last toggle left behind.
7 beforeEach(() => {
8 resetItemFixtures();
9 apiCalls.length = 0;
10 });
11
12 describe('BB.items.load', () => {
13 test('populates state with items', async () => {
14 await BB.items.load();
15 assert.strictEqual(BB.state.items.length, 2);
16 assert.strictEqual(BB.state.items[0].title, 'First');
17 assert.strictEqual(BB.state.hasMore, true);
18 });
19
20 test('appends items when append=true', async () => {
21 BB.state.set('items', [{ id: 'old', title: 'Old' }]);
22 await BB.items.load(true);
23 assert.strictEqual(BB.state.items.length, 3);
24 assert.strictEqual(BB.state.items[0].id, 'old');
25 });
26 });
27
28 describe('BB.items.selectItem', () => {
29 test('sets selectedItemId', async () => {
30 BB.state.set('items', [{ id: 'i1', title: 'T', isRead: false, isStarred: false }]);
31 await BB.items.selectItem('i1');
32 assert.strictEqual(BB.state.selectedItemId, 'i1');
33 });
34
35 test('marks item as read via API', async () => {
36 BB.state.set('items', [{ id: 'i1', title: 'T', isRead: false, isStarred: false }]);
37 await BB.items.selectItem('i1');
38 assert.ok(apiCalls.some(c => c.cmd === 'markRead' && c.id === 'i1'));
39 });
40 });
41
42 describe('BB.items.toggleStar', () => {
43 test('unstars a starred item', async () => {
44 BB.state.set('items', [{ id: 'i1', title: 'T', isRead: true, isStarred: true }]);
45 await BB.items.toggleStar('i1', true);
46 assert.ok(apiCalls.some(c => c.cmd === 'unstar'));
47 assert.strictEqual(BB.state.items[0].isStarred, false);
48 });
49
50 test('stars an unstarred item', async () => {
51 BB.state.set('items', [{ id: 'i1', title: 'T', isRead: true, isStarred: false }]);
52 await BB.items.toggleStar('i1', false);
53 assert.ok(apiCalls.some(c => c.cmd === 'star'));
54 assert.strictEqual(BB.state.items[0].isStarred, true);
55 });
56 });
57
58 describe('BB.items.toggleRead', () => {
59 test('marks read item as unread', async () => {
60 BB.state.set('items', [{ id: 'i1', title: 'T', isRead: true, isStarred: false }]);
61 await BB.items.toggleRead('i1', true);
62 assert.ok(apiCalls.some(c => c.cmd === 'markUnread'));
63 assert.strictEqual(BB.state.items[0].isRead, false);
64 });
65
66 test('marks unread item as read', async () => {
67 BB.state.set('items', [{ id: 'i1', title: 'T', isRead: false, isStarred: false }]);
68 await BB.items.toggleRead('i1', false);
69 assert.ok(apiCalls.some(c => c.cmd === 'markRead' && c.id === 'i1'));
70 assert.strictEqual(BB.state.items[0].isRead, true);
71 });
72 });
73
74 describe('BB.items.loadMore', () => {
75 test('increments page', async () => {
76 BB.state.set('currentPage', 0);
77 await BB.items.loadMore();
78 assert.strictEqual(BB.state.currentPage, 1);
79 });
80 });
81
82 describe('BB.items.render', () => {
83 test('empty items array renders placeholder message', () => {
84 resetMockElement('items-list');
85 BB.state.set('sources', [{ id: 's1', name: 'F' }]);
86 BB.items.render([]);
87 const list = document.getElementById('items-list');
88 assert.ok(list.innerHTML.includes('empty-state'), 'Should show empty state');
89 });
90
91 test('item with isStarred=true has starred class', () => {
92 resetMockElement('items-list');
93 BB.items.render([
94 { id: 'i1', title: 'T', author: 'A', isRead: false, isStarred: true, timeAgo: '1m' },
95 ]);
96 const list = document.getElementById('items-list');
97 const item = list.children[0];
98 assert.ok(item.innerHTML.includes('starred'), 'Should have starred class');
99 });
100
101 test('item with isRead=true has read class', () => {
102 resetMockElement('items-list');
103 BB.items.render([
104 { id: 'i1', title: 'T', author: 'A', isRead: true, isStarred: false, timeAgo: '1m' },
105 ]);
106 const list = document.getElementById('items-list');
107 const item = list.children[0];
108 assert.ok(item.className.includes('read'), 'Should have read class');
109 });
110
111 test('loadMore with hasMore=false is a no-op for display', () => {
112 resetMockElement('items-list');
113 BB.state.set('hasMore', false);
114 const loadMoreEl = document.getElementById('load-more');
115 BB.items.render([{ id: 'i1', title: 'T', author: 'A', isRead: false, isStarred: false, timeAgo: '1m' }]);
116 assert.strictEqual(loadMoreEl.style.display, 'none');
117 });
118 });
119