aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src/components/Settings.test.tsx
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-13 07:13:18 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-13 07:13:18 -0800
commita5cd9538b0db731a0d0e10e58804ef8ad32211b7 (patch)
tree0b46b0f43965de9df03b023abc40d869224e38d8 /frontend/src/components/Settings.test.tsx
parente31b68197ec16d2805ec14c2bf532a03f4739e92 (diff)
downloadneko-a5cd9538b0db731a0d0e10e58804ef8ad32211b7.tar.gz
neko-a5cd9538b0db731a0d0e10e58804ef8ad32211b7.tar.bz2
neko-a5cd9538b0db731a0d0e10e58804ef8ad32211b7.zip
Implement Frontend Settings with tests
Diffstat (limited to 'frontend/src/components/Settings.test.tsx')
-rw-r--r--frontend/src/components/Settings.test.tsx92
1 files changed, 92 insertions, 0 deletions
diff --git a/frontend/src/components/Settings.test.tsx b/frontend/src/components/Settings.test.tsx
new file mode 100644
index 0000000..a15192d
--- /dev/null
+++ b/frontend/src/components/Settings.test.tsx
@@ -0,0 +1,92 @@
+import React from 'react';
+import '@testing-library/jest-dom';
+import { render, screen, waitFor, fireEvent } from '@testing-library/react';
+import { describe, it, expect, vi, beforeEach } from 'vitest';
+import Settings from './Settings';
+
+describe('Settings Component', () => {
+ beforeEach(() => {
+ vi.resetAllMocks();
+ global.fetch = vi.fn();
+ // Mock confirm
+ global.confirm = vi.fn(() => true);
+ });
+
+ it('renders feed list', async () => {
+ const mockFeeds = [
+ { _id: 1, title: 'Tech News', url: 'http://tech.com/rss', category: 'tech' },
+ { _id: 2, title: 'Gaming', url: 'http://gaming.com/rss', category: 'gaming' },
+ ];
+
+ (global.fetch as any).mockResolvedValueOnce({
+ ok: true,
+ json: async () => mockFeeds,
+ });
+
+ render(<Settings />);
+
+ await waitFor(() => {
+ expect(screen.getByText('Tech News')).toBeInTheDocument();
+ expect(screen.getByText('http://tech.com/rss')).toBeInTheDocument();
+ expect(screen.getByText('Gaming')).toBeInTheDocument();
+ });
+ });
+
+ it('adds a new feed', async () => {
+ (global.fetch as any)
+ .mockResolvedValueOnce({ ok: true, json: async () => [] }) // Initial load
+ .mockResolvedValueOnce({ ok: true, json: async () => ({}) }) // Add feed
+ .mockResolvedValueOnce({ ok: true, json: async () => [{ _id: 3, title: 'New Feed', url: 'http://new.com/rss' }] }); // Refresh load
+
+ render(<Settings />);
+
+ // Wait for initial load to finish
+ await waitFor(() => {
+ expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
+ });
+
+ const input = screen.getByPlaceholderText('https://example.com/feed.xml');
+ const button = screen.getByText('Add Feed');
+
+ fireEvent.change(input, { target: { value: 'http://new.com/rss' } });
+ fireEvent.click(button);
+
+ await waitFor(() => {
+ expect(global.fetch).toHaveBeenCalledWith('/api/feed/', expect.objectContaining({
+ method: 'POST',
+ body: JSON.stringify({ url: 'http://new.com/rss' }),
+ }));
+ });
+
+ // Wait for refresh
+ await waitFor(() => {
+ expect(screen.getByText('New Feed')).toBeInTheDocument();
+ });
+ });
+
+ it('deletes a feed', async () => {
+ const mockFeeds = [
+ { _id: 1, title: 'Tech News', url: 'http://tech.com/rss', category: 'tech' },
+ ];
+
+ (global.fetch as any)
+ .mockResolvedValueOnce({ ok: true, json: async () => mockFeeds }) // Initial load
+ .mockResolvedValueOnce({ ok: true }); // Delete
+
+ render(<Settings />);
+
+ await waitFor(() => {
+ expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
+ expect(screen.getByText('Tech News')).toBeInTheDocument();
+ });
+
+ const deleteBtn = screen.getByTitle('Delete Feed');
+ fireEvent.click(deleteBtn);
+
+ await waitFor(() => {
+ expect(global.confirm).toHaveBeenCalled();
+ expect(global.fetch).toHaveBeenCalledWith('/api/feed/1', expect.objectContaining({ method: 'DELETE' }));
+ expect(screen.queryByText('Tech News')).not.toBeInTheDocument();
+ });
+ });
+});