Files
blog.pyaqa.ru/tests/e2e/test_post_deletion.py
Sergey Vanyushkin cf4982c0e5 test(e2e): add TC-E2E-003/004/005/007/008/009/010 — delete, pagination, errors, profile, theme
- test_post_deletion.py: user delete own, admin delete any, 403 for other's
- test_pagination.py: navigation across pages, boundary on last page
- test_errors.py: 404 nonexistent post, 404 for other user's draft
- test_post_lifecycle.py: draft-to-publish via edit flow
- test_post_ownership.py: user can edit own post
- test_profile_and_theme.py: profile page rendering, theme toggle with localStorage
- fix(web): remove infinite pagination for USER role (routes.py)
- fix(e2e): stabilize all publish() calls with expect_navigation
- fix(e2e): add _unique_title() to avoid slug collisions at scale
- docs: update FEATURE_POST_LIFECYCLE.md and TEST_MODEL.md coverage
2026-05-08 20:25:01 +03:00

176 lines
5.6 KiB
Python

"""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