Files
blog.pyaqa.ru/tests/e2e/test_likes.py
Sergey Vanyushkin 30d9e287a7
All checks were successful
ci/woodpecker/pr/pipeline Pipeline was successful
feat: add e2e tests for likes and fix like_count propagation in DTO mapping
- Write 3 e2e tests (TC-E2E-106-108): like/unlike flow, multi-user like, guest redirect
- Add get_like_count() and click_like() to PostDetailPage object
- Fix _map_to_dto in 5 use cases (create, get, list, publish, update) to include like_count
- Fix pre-existing mypy issues in page object (evaluate returns Any)
- Update FEATURE_LIKES.md with verified E2E status
2026-05-10 21:11:28 +03:00

184 lines
5.8 KiB
Python

"""End-to-end tests for post likes via web UI.
Tests the like/unlike toggle flow, multi-user like isolation,
and guest authentication redirect.
"""
from __future__ import annotations
import uuid
import pytest
from playwright.sync_api import Page, expect
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_like_unlike_flow(
user_page: Page,
base_url: str,
) -> None:
"""Test like/unlike toggle through the web UI.
Steps:
1. Create and publish a post.
2. Verify initial like count is 0.
3. Click the like button.
4. Verify like count becomes 1.
5. Click the like button again.
6. Verify like count returns to 0.
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
# Initial like count should be 0 for a new post
assert detail.get_like_count() == 0
# Like the post
detail.click_like()
expect(user_page.locator("#like-count")).to_have_text("1", timeout=15000)
# Unlike the post
detail.click_like()
expect(user_page.locator("#like-count")).to_have_text("0", timeout=15000)
@pytest.mark.e2e
def test_multiple_users_can_like(
user_page: Page,
user2_page: Page,
base_url: str,
) -> None:
"""Test that two users can independently like the same post.
Steps:
1. User creates and publishes a post.
2. User likes the post (count becomes 1).
3. User2 opens the same post (sees count=1).
4. User2 clicks like (count becomes 2).
Args:
user_page: Playwright page authenticated as first regular user.
user2_page: Playwright page authenticated as 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
# User likes the post
assert detail.get_like_count() == 0
detail.click_like()
expect(user_page.locator("#like-count")).to_have_text("1", timeout=15000)
# Verify like_count persists after page reload
user_page.reload(wait_until="networkidle")
user_page.wait_for_selector('[data-testid="post-detail-title"]')
assert detail.get_like_count() == 1
# User2 opens same post and likes
user2_detail = PostDetailPage(user2_page, base_url, slug)
user2_detail.open()
user2_page.wait_for_selector('[data-testid="post-detail-title"]')
assert user2_detail.get_like_count() == 1
user2_detail.click_like()
expect(user2_page.locator("#like-count")).to_have_text("2", timeout=15000)
@pytest.mark.e2e
def test_guest_redirect_on_like(
user_page: Page,
guest_page: Page,
base_url: str,
) -> None:
"""Test that unauthenticated guests are redirected to login when liking.
Steps:
1. User creates and publishes a post.
2. Guest opens the post detail page.
3. Guest clicks the like button.
4. Guest is redirected to the development login page.
Args:
user_page: Playwright page authenticated as regular user.
guest_page: Unauthenticated Playwright page.
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]
# Guest opens the published post
guest_detail = PostDetailPage(guest_page, base_url, slug)
guest_detail.open()
guest_page.wait_for_selector('[data-testid="post-detail-title"]')
# Guest clicks like -> should be redirected to dev login page
with guest_page.expect_navigation(wait_until="networkidle", timeout=15000):
guest_detail.click_like()
assert "dev-login" in guest_page.url