diff options
| author | Adam Mathes <adam@adammathes.com> | 2026-02-13 07:01:40 -0800 |
|---|---|---|
| committer | Adam Mathes <adam@adammathes.com> | 2026-02-13 07:01:40 -0800 |
| commit | e31b68197ec16d2805ec14c2bf532a03f4739e92 (patch) | |
| tree | bcda027df5c020ec6d12073ef1b132a6a14c2a86 /frontend/src | |
| parent | bd2508211760edbc1bad1d515587d08fd2ec99c9 (diff) | |
| download | neko-e31b68197ec16d2805ec14c2bf532a03f4739e92.tar.gz neko-e31b68197ec16d2805ec14c2bf532a03f4739e92.tar.bz2 neko-e31b68197ec16d2805ec14c2bf532a03f4739e92.zip | |
Implement Frontend Logout with tests
Diffstat (limited to 'frontend/src')
| -rw-r--r-- | frontend/src/App.css | 16 | ||||
| -rw-r--r-- | frontend/src/App.test.tsx | 21 | ||||
| -rw-r--r-- | frontend/src/App.tsx | 7 |
3 files changed, 42 insertions, 2 deletions
diff --git a/frontend/src/App.css b/frontend/src/App.css index 57800a4..69edabd 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -57,4 +57,20 @@ body { padding: 2rem; overflow-y: auto; background: #fff; +} + +.logout-btn { + background: transparent; + border: 1px solid rgba(255, 255, 255, 0.3); + color: white; + padding: 0.5rem 1rem; + border-radius: 4px; + cursor: pointer; + transition: all 0.2s; + font-size: 0.9rem; +} + +.logout-btn:hover { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.5); }
\ No newline at end of file diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 37a7fab..5614d7d 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import '@testing-library/jest-dom'; -import { render, screen, waitFor } from '@testing-library/react'; +import { render, screen, waitFor, fireEvent } from '@testing-library/react'; import App from './App'; import { describe, it, expect, vi, beforeEach } from 'vitest'; @@ -30,5 +30,24 @@ describe('App', () => { await waitFor(() => { expect(screen.getByText(/neko reader/i)).toBeInTheDocument(); }); + + // Test Logout + const logoutBtn = screen.getByText(/logout/i); + expect(logoutBtn).toBeInTheDocument(); + + // Mock window.location + Object.defineProperty(window, 'location', { + configurable: true, + value: { href: '' }, + }); + + (global.fetch as any).mockResolvedValueOnce({ ok: true }); + + fireEvent.click(logoutBtn); + + await waitFor(() => { + expect(global.fetch).toHaveBeenCalledWith('/api/logout', expect.objectContaining({ method: 'POST' })); + expect(window.location.href).toBe('/login/'); + }); }); }); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index bc4e097..7c9d555 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -40,7 +40,12 @@ function Dashboard() { <header className="dashboard-header"> <h1>Neko Reader</h1> <nav> - {/* Add logout later */} + <button onClick={() => { + fetch('/api/logout', { method: 'POST' }) + .then(() => window.location.href = '/login/'); + }} className="logout-btn"> + Logout + </button> </nav> </header> <div className="dashboard-content"> |
