From e3c379d069ffa9661561d25cdbf2f5894a2f8ee8 Mon Sep 17 00:00:00 2001
From: Adam Mathes <adam@adammathes.com>
Date: Sat, 14 Feb 2026 08:58:38 -0800
Subject: Refactor: project structure, implement dependency injection, and
 align v2 UI with v1

---
 frontend/src/components/FeedList.test.tsx | 200 ++++++++++++++++--------------
 1 file changed, 106 insertions(+), 94 deletions(-)

(limited to 'frontend/src/components/FeedList.test.tsx')

diff --git a/frontend/src/components/FeedList.test.tsx b/frontend/src/components/FeedList.test.tsx
index d5f49b7..daa4d69 100644
--- a/frontend/src/components/FeedList.test.tsx
+++ b/frontend/src/components/FeedList.test.tsx
@@ -7,114 +7,126 @@ import FeedList from './FeedList';
 import { BrowserRouter } from 'react-router-dom';
 
 describe('FeedList Component', () => {
-    beforeEach(() => {
-        vi.resetAllMocks();
-        global.fetch = vi.fn();
-    });
-
-    it('renders loading state initially', () => {
-        (global.fetch as any).mockImplementation(() => new Promise(() => { }));
-        render(
-            <BrowserRouter>
-                {/* @ts-ignore */}
-                <FeedList theme="light" setTheme={() => { }} />
-            </BrowserRouter>
-        );
-        expect(screen.getByText(/loading feeds/i)).toBeInTheDocument();
-    });
-
-    it('renders list of feeds', async () => {
-        const mockFeeds = [
-            { _id: 1, title: 'Feed One', url: 'http://example.com/rss', web_url: 'http://example.com', category: 'Tech' },
-            { _id: 2, title: 'Feed Two', url: 'http://test.com/rss', web_url: 'http://test.com', category: 'News' },
-        ];
-
-        (global.fetch as any).mockImplementation((url: string) => {
-            if (url.includes('/api/feed/')) {
-                return Promise.resolve({
-                    ok: true,
-                    json: async () => mockFeeds,
-                });
-            }
-            if (url.includes('/api/tag')) {
-                return Promise.resolve({
-                    ok: true,
-                    json: async () => [{ title: 'Tech' }],
-                });
-            }
-            return Promise.reject(new Error(`Unknown URL: ${url}`));
+  beforeEach(() => {
+    vi.resetAllMocks();
+    global.fetch = vi.fn();
+  });
+
+  it('renders loading state initially', () => {
+    (global.fetch as any).mockImplementation(() => new Promise(() => {}));
+    render(
+      <BrowserRouter>
+        {/* @ts-ignore */}
+        <FeedList theme="light" setTheme={() => {}} />
+      </BrowserRouter>
+    );
+    expect(screen.getByText(/loading feeds/i)).toBeInTheDocument();
+  });
+
+  it('renders list of feeds', async () => {
+    const mockFeeds = [
+      {
+        _id: 1,
+        title: 'Feed One',
+        url: 'http://example.com/rss',
+        web_url: 'http://example.com',
+        category: 'Tech',
+      },
+      {
+        _id: 2,
+        title: 'Feed Two',
+        url: 'http://test.com/rss',
+        web_url: 'http://test.com',
+        category: 'News',
+      },
+    ];
+
+    (global.fetch as any).mockImplementation((url: string) => {
+      if (url.includes('/api/feed/')) {
+        return Promise.resolve({
+          ok: true,
+          json: async () => mockFeeds,
         });
+      }
+      if (url.includes('/api/tag')) {
+        return Promise.resolve({
+          ok: true,
+          json: async () => [{ title: 'Tech' }],
+        });
+      }
+      return Promise.reject(new Error(`Unknown URL: ${url}`));
+    });
 
-        render(
-            <BrowserRouter>
-                {/* @ts-ignore */}
-                <FeedList theme="light" setTheme={() => { }} />
-            </BrowserRouter>
-        );
+    render(
+      <BrowserRouter>
+        {/* @ts-ignore */}
+        <FeedList theme="light" setTheme={() => {}} />
+      </BrowserRouter>
+    );
 
-        await waitFor(() => {
-            expect(screen.queryByText(/loading feeds/i)).not.toBeInTheDocument();
-        });
+    await waitFor(() => {
+      expect(screen.queryByText(/loading feeds/i)).not.toBeInTheDocument();
+    });
 
-        // Expand feeds
-        fireEvent.click(screen.getByText(/feeds/i, { selector: 'h2' }));
+    // Expand feeds
+    fireEvent.click(screen.getByText(/feeds/i, { selector: 'h2' }));
 
-        await waitFor(() => {
-            expect(screen.getByText('Feed One')).toBeInTheDocument();
-            expect(screen.getByText('Feed Two')).toBeInTheDocument();
-            const techElements = screen.getAllByText('Tech');
-            expect(techElements.length).toBeGreaterThan(0);
-        });
+    await waitFor(() => {
+      expect(screen.getByText('Feed One')).toBeInTheDocument();
+      expect(screen.getByText('Feed Two')).toBeInTheDocument();
+      const techElements = screen.getAllByText('Tech');
+      expect(techElements.length).toBeGreaterThan(0);
     });
+  });
 
-    it('handles fetch error', async () => {
-        (global.fetch as any).mockImplementation(() => Promise.reject(new Error('API Error')));
+  it('handles fetch error', async () => {
+    (global.fetch as any).mockImplementation(() => Promise.reject(new Error('API Error')));
 
-        render(
-            <BrowserRouter>
-                {/* @ts-ignore */}
-                <FeedList theme="light" setTheme={() => { }} />
-            </BrowserRouter>
-        );
+    render(
+      <BrowserRouter>
+        {/* @ts-ignore */}
+        <FeedList theme="light" setTheme={() => {}} />
+      </BrowserRouter>
+    );
 
-        await waitFor(() => {
-            expect(screen.getByText(/error: api error/i)).toBeInTheDocument();
-        });
+    await waitFor(() => {
+      expect(screen.getByText(/error: api error/i)).toBeInTheDocument();
     });
-
-    it('handles empty feed list', async () => {
-        (global.fetch as any).mockImplementation((url: string) => {
-            if (url.includes('/api/feed/')) {
-                return Promise.resolve({
-                    ok: true,
-                    json: async () => [],
-                });
-            }
-            if (url.includes('/api/tag')) {
-                return Promise.resolve({
-                    ok: true,
-                    json: async () => [],
-                });
-            }
-            return Promise.reject(new Error(`Unknown URL: ${url}`));
+  });
+
+  it('handles empty feed list', async () => {
+    (global.fetch as any).mockImplementation((url: string) => {
+      if (url.includes('/api/feed/')) {
+        return Promise.resolve({
+          ok: true,
+          json: async () => [],
+        });
+      }
+      if (url.includes('/api/tag')) {
+        return Promise.resolve({
+          ok: true,
+          json: async () => [],
         });
+      }
+      return Promise.reject(new Error(`Unknown URL: ${url}`));
+    });
 
-        render(
-            <BrowserRouter>
-                {/* @ts-ignore */}
-                <FeedList theme="light" setTheme={() => { }} />
-            </BrowserRouter>
-        );
+    render(
+      <BrowserRouter>
+        {/* @ts-ignore */}
+        <FeedList theme="light" setTheme={() => {}} />
+      </BrowserRouter>
+    );
 
-        await waitFor(() => {
-            expect(screen.queryByText(/loading feeds/i)).not.toBeInTheDocument();
-        });
+    await waitFor(() => {
+      expect(screen.queryByText(/loading feeds/i)).not.toBeInTheDocument();
+    });
 
-        // Expand feeds
-        fireEvent.click(screen.getByText(/feeds/i, { selector: 'h2' }));
+    // Expand feeds
+    fireEvent.click(screen.getByText(/feeds/i, { selector: 'h2' }));
 
-        await waitFor(() => {
-            expect(screen.getByText(/no feeds found/i)).toBeInTheDocument();
-        });
+    await waitFor(() => {
+      expect(screen.getByText(/no feeds found/i)).toBeInTheDocument();
     });
+  });
 });
-- 
cgit v1.2.3

