"""End-to-end tests for post deletion via web UI. Tests that users can delete their own posts, admins can delete any post, and regular users cannot delete posts they do not own. """ from __future__ import annotations import uuid import pytest from playwright.sync_api import Page from pytfm.generators import PostDataGenerator from tests.e2e.pages import HomePage, PostDetailPage, PostFormPage def _unique_title(base: str) -> str: """Append a short UUID to a title to avoid slug collisions.""" return f"{base} {uuid.uuid4().hex[:8]}" @pytest.mark.e2e def test_user_can_delete_own_post( user_page: Page, base_url: str, ) -> None: """Test that a user can delete their own post. Steps: 1. User creates and publishes a post. 2. User opens the post detail page. 3. User clicks delete and confirms. 4. Verify redirect to home page. 5. Verify the post no longer appears in the list. Args: user_page: Playwright page authenticated as regular user. base_url: Application base URL. """ generator = PostDataGenerator() post_data = generator.generate_post() title = _unique_title(str(post_data["title"])) content = str(post_data["content"]) tags = ", ".join(post_data["tags"]) home = HomePage(user_page, base_url) home.open() home.create_post() form = PostFormPage(user_page, base_url) form.fill_form(title, content, tags) with user_page.expect_navigation(wait_until="networkidle"): form.publish() current_url = user_page.url assert "new" not in current_url, f"Still on form page: {current_url}" slug = current_url.rstrip("/").split("/")[-1] user_page.wait_for_selector('[data-testid="post-detail-title"]') detail = PostDetailPage(user_page, base_url, slug) assert detail.get_title() == title assert detail.can_delete() with user_page.expect_navigation(wait_until="networkidle"): detail.delete() current_url = user_page.url assert current_url.rstrip("/").endswith("/web") response = user_page.request.get(f"{base_url}/web/posts/{slug}") assert response.status == 404 @pytest.mark.e2e def test_admin_can_delete_any_post( user_page: Page, admin_page: Page, base_url: str, ) -> None: """Test that admin can delete a post created by another user. Steps: 1. User creates and publishes a post. 2. Admin opens the post detail page. 3. Admin clicks delete and confirms. 4. Verify redirect to home page. 5. Verify the post no longer appears in the list. Args: user_page: Playwright page authenticated as regular user. admin_page: Playwright page authenticated as admin. base_url: Application base URL. """ generator = PostDataGenerator() post_data = generator.generate_post() title = _unique_title(str(post_data["title"])) content = str(post_data["content"]) tags = ", ".join(post_data["tags"]) home = HomePage(user_page, base_url) home.open() home.create_post() form = PostFormPage(user_page, base_url) form.fill_form(title, content, tags) with user_page.expect_navigation(wait_until="networkidle"): form.publish() current_url = user_page.url assert "new" not in current_url, f"Still on form page: {current_url}" slug = current_url.rstrip("/").split("/")[-1] user_page.wait_for_selector('[data-testid="post-detail-title"]') detail = PostDetailPage(user_page, base_url, slug) assert detail.get_title() == title admin_detail = PostDetailPage(admin_page, base_url, slug) admin_detail.open() assert admin_detail.can_delete() with admin_page.expect_navigation(wait_until="networkidle"): admin_detail.delete() current_url = admin_page.url assert current_url.rstrip("/").endswith("/web") response = admin_page.request.get(f"{base_url}/web/posts/{slug}") assert response.status == 404 @pytest.mark.e2e def test_user_cannot_delete_other_users_post( user_page: Page, user2_page: Page, base_url: str, ) -> None: """Test that a regular user cannot delete another user's post. Steps: 1. User creates and publishes a post. 2. User2 opens the post detail page. 3. Verify the delete button is not visible. 4. User2 attempts a direct POST to the delete endpoint. 5. Verify a 403 error page is returned. Args: user_page: Playwright page authenticated as the first regular user. user2_page: Playwright page authenticated as the second regular user. base_url: Application base URL. """ generator = PostDataGenerator() post_data = generator.generate_post() title = _unique_title(str(post_data["title"])) content = str(post_data["content"]) tags = ", ".join(post_data["tags"]) home = HomePage(user_page, base_url) home.open() home.create_post() form = PostFormPage(user_page, base_url) form.fill_form(title, content, tags) with user_page.expect_navigation(wait_until="networkidle"): form.publish() current_url = user_page.url assert "new" not in current_url, f"Still on form page: {current_url}" slug = current_url.rstrip("/").split("/")[-1] user_page.wait_for_selector('[data-testid="post-detail-title"]') detail = PostDetailPage(user_page, base_url, slug) assert detail.get_title() == title user2_detail = PostDetailPage(user2_page, base_url, slug) user2_detail.open() assert not user2_detail.can_delete() response = user2_page.request.post(f"{base_url}/web/posts/{slug}/delete") assert response.status == 403