Frontend Features: - Add ProtectedRoute component with token expiry validation - Create AdminDashboardPage with system statistics and user management - Create AuditLogsPage with filtering and pagination - Add admin-only navigation (Shield icon) for ymirliu@panjit.com.tw - Add admin API methods to apiV2 service - Add admin type definitions (SystemStats, AuditLog, etc.) Token Management: - Auto-redirect to login on token expiry - Check authentication on route change - Show loading state during auth check - Admin privilege verification Backend Testing: - Add pytest configuration (pytest.ini) - Create test fixtures (conftest.py) - Add unit tests for auth, tasks, and admin endpoints - Add integration tests for complete workflows - Test user isolation and admin access control Documentation: - Add TESTING.md with comprehensive testing guide - Include test running instructions - Document fixtures and best practices Routes: - /admin - Admin dashboard (admin only) - /admin/audit-logs - Audit logs viewer (admin only) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
76 lines
2.4 KiB
Python
76 lines
2.4 KiB
Python
"""
|
|
Unit tests for authentication endpoints
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
|
|
class TestAuth:
|
|
"""Test authentication endpoints"""
|
|
|
|
def test_login_success(self, client, db):
|
|
"""Test successful login"""
|
|
# Mock external auth service
|
|
with patch('app.routers.auth.external_auth_service.authenticate_user') as mock_auth:
|
|
mock_auth.return_value = (True, {
|
|
'access_token': 'test-token',
|
|
'expires_in': 3600,
|
|
'user_info': {
|
|
'email': 'test@example.com',
|
|
'name': 'Test User'
|
|
}
|
|
}, None)
|
|
|
|
response = client.post('/api/v2/auth/login', json={
|
|
'username': 'test@example.com',
|
|
'password': 'password123'
|
|
})
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert 'access_token' in data
|
|
assert data['token_type'] == 'bearer'
|
|
assert 'user' in data
|
|
|
|
def test_login_invalid_credentials(self, client):
|
|
"""Test login with invalid credentials"""
|
|
with patch('app.routers.auth.external_auth_service.authenticate_user') as mock_auth:
|
|
mock_auth.return_value = (False, None, 'Invalid credentials')
|
|
|
|
response = client.post('/api/v2/auth/login', json={
|
|
'username': 'test@example.com',
|
|
'password': 'wrongpassword'
|
|
})
|
|
|
|
assert response.status_code == 401
|
|
assert 'detail' in response.json()
|
|
|
|
def test_get_me(self, client, auth_token):
|
|
"""Test get current user info"""
|
|
response = client.get(
|
|
'/api/v2/auth/me',
|
|
headers={'Authorization': f'Bearer {auth_token}'}
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert 'email' in data
|
|
assert 'display_name' in data
|
|
|
|
def test_get_me_unauthorized(self, client):
|
|
"""Test get current user without token"""
|
|
response = client.get('/api/v2/auth/me')
|
|
assert response.status_code == 403
|
|
|
|
def test_logout(self, client, auth_token):
|
|
"""Test logout"""
|
|
response = client.post(
|
|
'/api/v2/auth/logout',
|
|
headers={'Authorization': f'Bearer {auth_token}'}
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data['message'] == 'Logged out successfully'
|