"""End-to-end tests for post ownership and RBAC policies. Tests that admin can edit any post and that regular users cannot edit posts they do not own. """ from __future__ import annotations import pytest from playwright.sync_api import Page from pytfm.generators import PostDataGenerator from tests.e2e.pages import HomePage, PostDetailPage, PostFormPage @pytest.mark.e2e def test_admin_can_edit_any_post( user_page: Page, admin_page: Page, base_url: str, ) -> None: """Test that admin can edit a post created by another user. Steps: 1. User creates and publishes a post. 2. Admin opens the post detail page. 3. Admin clicks edit, changes the title, and saves. 4. Verify the post detail shows the updated title. 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 = 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) form.publish() user_page.wait_for_url( lambda url: "/web/posts/" in url and "new" not in url, timeout=15000, ) 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_edit() admin_detail.edit() admin_page.wait_for_url( lambda url: f"/web/posts/{slug}/edit" in url, timeout=15000, ) new_data = generator.generate_post() new_title = str(new_data["title"]) new_content = str(new_data["content"]) new_tags = ", ".join(new_data["tags"]) admin_form = PostFormPage(admin_page, base_url) admin_form.fill_form(new_title, new_content, new_tags) admin_form.publish() admin_page.wait_for_selector( '[data-testid="post-detail-title"]', timeout=15000, ) updated_title = admin_page.locator('[data-testid="post-detail-title"]').text_content() assert updated_title == new_title updated_status = admin_page.locator('[data-testid="post-detail-status"]').text_content() assert updated_status == "Published" @pytest.mark.e2e def test_user_cannot_edit_other_users_post( user_page: Page, user2_page: Page, base_url: str, ) -> None: """Test that a regular user cannot edit another user's post. Steps: 1. User creates and publishes a post. 2. User2 opens the post detail page. 3. Verify the edit button is not visible. 4. User2 attempts direct access to the edit URL. 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 = 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) form.publish() user_page.wait_for_url( lambda url: "/web/posts/" in url and "new" not in url, timeout=15000, ) 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_edit() user2_page.goto(f"{base_url}/web/posts/{slug}/edit") user2_page.wait_for_selector('[data-testid="error-code"]', timeout=10000) error_code = user2_page.locator('[data-testid="error-code"]').text_content() assert error_code == "403"