""" Tests for admin routes (dashboard, note management) Tests cover: - Authentication requirement for all admin routes - Dashboard rendering with note list - Create note flow - Edit note flow - Delete note flow - Logout functionality """ import pytest from starpunk import create_app from starpunk.notes import create_note from starpunk.auth import create_session @pytest.fixture def app(tmp_path): """Create test application""" # Create test-specific data directory test_data_dir = tmp_path / "data" test_data_dir.mkdir(parents=True, exist_ok=True) test_config = { "TESTING": True, "DATABASE_PATH": test_data_dir / "starpunk.db", "DATA_PATH": test_data_dir, "NOTES_PATH": test_data_dir / "notes", "SESSION_SECRET": "test-secret-key", "ADMIN_ME": "https://test.example.com", "SITE_URL": "http://localhost:5000", "DEV_MODE": False, } app = create_app(config=test_config) yield app @pytest.fixture def client(app): """Test client""" return app.test_client() @pytest.fixture def authenticated_client(app, client): """Client with authenticated session""" with app.test_request_context(): # Create a session for the test user session_token = create_session("https://test.example.com") # Set session cookie client.set_cookie("starpunk_session", session_token) return client @pytest.fixture def sample_notes(app): """Create sample notes""" with app.app_context(): notes = [] for i in range(3): note = create_note( content=f"# Admin Test Note {i}\n\nContent {i}.", published=(i != 1), # Note 1 is draft ) notes.append(note) return notes class TestAuthenticationRequirement: """Test that all admin routes require authentication""" def test_dashboard_requires_auth(self, client): """Test /admin requires authentication""" response = client.get("/admin/", follow_redirects=False) assert response.status_code == 302 assert "/admin/login" in response.location def test_new_note_form_requires_auth(self, client): """Test /admin/new requires authentication""" response = client.get("/admin/new", follow_redirects=False) assert response.status_code == 302 def test_edit_note_form_requires_auth(self, client, sample_notes): """Test /admin/edit/ requires authentication""" with client.application.app_context(): from starpunk.notes import list_notes notes = list_notes() note_id = notes[0].id response = client.get(f"/admin/edit/{note_id}", follow_redirects=False) assert response.status_code == 302 def test_create_note_submit_requires_auth(self, client): """Test POST /admin/new requires authentication""" response = client.post( "/admin/new", data={"content": "Test content", "published": "on"}, follow_redirects=False, ) assert response.status_code == 302 def test_update_note_submit_requires_auth(self, client, sample_notes): """Test POST /admin/edit/ requires authentication""" with client.application.app_context(): from starpunk.notes import list_notes notes = list_notes() note_id = notes[0].id response = client.post( f"/admin/edit/{note_id}", data={"content": "Updated content", "published": "on"}, follow_redirects=False, ) assert response.status_code == 302 def test_delete_note_requires_auth(self, client, sample_notes): """Test POST /admin/delete/ requires authentication""" with client.application.app_context(): from starpunk.notes import list_notes notes = list_notes() note_id = notes[0].id response = client.post( f"/admin/delete/{note_id}", data={"confirm": "yes"}, follow_redirects=False ) assert response.status_code == 302 class TestDashboard: """Test admin dashboard""" def test_dashboard_renders(self, authenticated_client): """Test dashboard renders for authenticated user""" response = authenticated_client.get("/admin/") assert response.status_code == 200 assert b"Dashboard" in response.data or b"Admin" in response.data def test_dashboard_shows_all_notes(self, authenticated_client, sample_notes): """Test dashboard shows both published and draft notes""" response = authenticated_client.get("/admin/") assert response.status_code == 200 # All notes should appear assert b"Admin Test Note 0" in response.data assert b"Admin Test Note 1" in response.data assert b"Admin Test Note 2" in response.data def test_dashboard_shows_note_status(self, authenticated_client, sample_notes): """Test dashboard shows published/draft status""" response = authenticated_client.get("/admin/") assert response.status_code == 200 # Should indicate status assert ( b"published" in response.data.lower() or b"draft" in response.data.lower() ) def test_dashboard_has_new_note_button(self, authenticated_client): """Test dashboard has new note button""" response = authenticated_client.get("/admin/") assert response.status_code == 200 assert b"/admin/new" in response.data or b"New Note" in response.data def test_dashboard_has_edit_links(self, authenticated_client, sample_notes): """Test dashboard has edit links for notes""" response = authenticated_client.get("/admin/") assert response.status_code == 200 assert b"/admin/edit/" in response.data or b"Edit" in response.data def test_dashboard_has_delete_buttons(self, authenticated_client, sample_notes): """Test dashboard has delete buttons""" response = authenticated_client.get("/admin/") assert response.status_code == 200 assert b"delete" in response.data.lower() def test_dashboard_has_logout_link(self, authenticated_client): """Test dashboard has logout link""" response = authenticated_client.get("/admin/") assert response.status_code == 200 assert b"logout" in response.data.lower() def test_dashboard_shows_user_identity(self, authenticated_client): """Test dashboard shows logged in user identity""" response = authenticated_client.get("/admin/") assert response.status_code == 200 assert b"test.example.com" in response.data class TestCreateNote: """Test note creation flow""" def test_new_note_form_renders(self, authenticated_client): """Test new note form renders""" response = authenticated_client.get("/admin/new") assert response.status_code == 200 assert b"