diff options
Diffstat (limited to 'frontend')
| -rw-r--r-- | frontend/src/components/Login.test.tsx | 12 | ||||
| -rw-r--r-- | frontend/src/components/Login.tsx | 11 | ||||
| -rw-r--r-- | frontend/tests/auth.spec.ts | 11 |
3 files changed, 29 insertions, 5 deletions
diff --git a/frontend/src/components/Login.test.tsx b/frontend/src/components/Login.test.tsx index cf69eb1..47f37e3 100644 --- a/frontend/src/components/Login.test.tsx +++ b/frontend/src/components/Login.test.tsx @@ -23,6 +23,7 @@ describe('Login Component', () => { it('renders login form', () => { renderLogin(); + expect(screen.getByLabelText(/username/i)).toBeInTheDocument(); expect(screen.getByLabelText(/password/i)).toBeInTheDocument(); expect(screen.getByRole('button', { name: /login/i })).toBeInTheDocument(); }); @@ -34,6 +35,7 @@ describe('Login Component', () => { renderLogin(); + fireEvent.change(screen.getByLabelText(/username/i), { target: { value: 'testuser' } }); fireEvent.change(screen.getByLabelText(/password/i), { target: { value: 'secret' } }); fireEvent.click(screen.getByRole('button', { name: /login/i })); @@ -42,9 +44,17 @@ describe('Login Component', () => { '/api/login', expect.objectContaining({ method: 'POST', + body: expect.any(URLSearchParams), }) ); }); + + // Check if params contained username and password + const callArgs = vi.mocked(global.fetch).mock.calls[0][1]; + const body = callArgs?.body as URLSearchParams; + expect(body.get('username')).toBe('testuser'); + expect(body.get('password')).toBe('secret'); + // Navigation assertion is tricky without mocking useNavigate, // but if no error is shown, we assume success path was taken expect(screen.queryByText(/login failed/i)).not.toBeInTheDocument(); @@ -58,6 +68,7 @@ describe('Login Component', () => { renderLogin(); + fireEvent.change(screen.getByLabelText(/username/i), { target: { value: 'testuser' } }); fireEvent.change(screen.getByLabelText(/password/i), { target: { value: 'wrong' } }); fireEvent.click(screen.getByRole('button', { name: /login/i })); @@ -71,6 +82,7 @@ describe('Login Component', () => { renderLogin(); + fireEvent.change(screen.getByLabelText(/username/i), { target: { value: 'testuser' } }); fireEvent.change(screen.getByLabelText(/password/i), { target: { value: 'secret' } }); fireEvent.click(screen.getByRole('button', { name: /login/i })); diff --git a/frontend/src/components/Login.tsx b/frontend/src/components/Login.tsx index b62acea..87694cb 100644 --- a/frontend/src/components/Login.tsx +++ b/frontend/src/components/Login.tsx @@ -5,6 +5,7 @@ import './Login.css'; import { apiFetch } from '../utils'; export default function Login() { + const [username, setUsername] = useState('neko'); const [password, setPassword] = useState(''); const [error, setError] = useState(''); const navigate = useNavigate(); @@ -16,6 +17,7 @@ export default function Login() { try { // Use URLSearchParams to send as form-urlencoded, matching backend expectation const params = new URLSearchParams(); + params.append('username', username); params.append('password', password); const res = await apiFetch('/api/login', { @@ -39,6 +41,15 @@ export default function Login() { <form onSubmit={handleSubmit} className="login-form"> <h1>neko rss mode</h1> <div className="form-group"> + <label htmlFor="username">username</label> + <input + id="username" + type="text" + value={username} + onChange={(e) => setUsername(e.target.value)} + /> + </div> + <div className="form-group"> <label htmlFor="password">password</label> <input id="password" diff --git a/frontend/tests/auth.spec.ts b/frontend/tests/auth.spec.ts index 4161a83..33ada85 100644 --- a/frontend/tests/auth.spec.ts +++ b/frontend/tests/auth.spec.ts @@ -26,11 +26,8 @@ test.describe('Authentication - No Password Required', () => { // Visit login page await page.goto('/v2/login'); - // Submit with empty password - const passwordInput = page.getByLabel(/password/i); - await expect(passwordInput).toBeVisible(); - - // Leave password empty and submit + // Fill username and submit with empty password + await page.fill('input[id="username"]', 'neko'); await page.click('button[type="submit"]'); // Should redirect to dashboard @@ -68,6 +65,7 @@ test.describe('Authentication - Password Required', () => { await page.goto('/v2/login'); // Enter wrong password + await page.fill('input[id="username"]', 'neko'); await page.fill('input[type="password"]', 'wrongpassword'); await page.click('button[type="submit"]'); @@ -82,6 +80,7 @@ test.describe('Authentication - Password Required', () => { await page.goto('/v2/login'); // Enter correct password (must match what the server was started with) + await page.fill('input[id="username"]', 'neko'); await page.fill('input[type="password"]', 'testpass'); await page.click('button[type="submit"]'); @@ -94,6 +93,7 @@ test.describe('Authentication - Password Required', () => { test.skip('should persist authentication across page reloads', async ({ page }) => { // Login first await page.goto('/v2/login'); + await page.fill('input[id="username"]', 'neko'); await page.fill('input[type="password"]', 'testpass'); await page.click('button[type="submit"]'); await expect(page).toHaveURL(/.*\/v2\/?$/); @@ -109,6 +109,7 @@ test.describe('Authentication - Password Required', () => { test.skip('should logout and redirect to login page', async ({ page }) => { // Login first await page.goto('/v2/login'); + await page.fill('input[id="username"]', 'neko'); await page.fill('input[type="password"]', 'testpass'); await page.click('button[type="submit"]'); await expect(page).toHaveURL(/.*\/v2\/?$/); |
