feat: add clickable activity cards with comment anchor links to profile tab

Add `url` field to profile activity items so post cards link to `/posts/{slug}` and comment cards link to the parent post with a `#comment-{uid}` anchor, matching notification click behavior. Include the shared `_card_link.html` overlay in the template, fix XP bar rendering for missing `xp` key, and add API + e2e tests verifying the link structure and navigation.
This commit is contained in:
2026-07-04 20:24:59 +00:00
parent c79dfd0291
commit 7002b23eeb
11 changed files with 213 additions and 13 deletions
+4 -1
View File
@@ -93,5 +93,8 @@ def test_admin_user_ai_usage_endpoint_returns_data(alice, seeded_db):
def test_member_forbidden_from_user_ai_usage_endpoint(bob, seeded_db):
page, _ = bob
bob_uid = get_table("users").find_one(username=seeded_db["bob"]["username"])["uid"]
resp = page.request.get(f"{BASE_URL}/admin/users/{bob_uid}/ai-usage")
resp = page.request.get(
f"{BASE_URL}/admin/users/{bob_uid}/ai-usage",
headers={"Accept": "application/json"},
)
assert resp.status == 403
+1 -1
View File
@@ -63,7 +63,7 @@ def test_game_page_loads(alice):
assert page.locator(".game-header h1").is_visible()
expect(page.locator("[data-hud-coins]")).to_have_text("100000")
expect(page.locator("[data-game-grid] [data-slot]")).to_have_count(4)
expect(page.locator(".perk-card")).to_have_count(4)
expect(page.locator(".perk-card:not(.legacy-card)")).to_have_count(4)
expect(page.locator(".quest-item")).to_have_count(3)
+66
View File
@@ -4,6 +4,72 @@ from tests.conftest import BASE_URL
FOLLOW = "form[action='/follow/bob_test'] button"
UNFOLLOW = "form[action='/follow/unfollow/bob_test'] button"
from playwright.sync_api import expect
from tests.e2e.post import create_post
def _post_comment(page, body):
textarea = page.locator(".comment-form textarea[name='content']")
textarea.fill(body)
page.locator(".comment-form button:has-text('Post')").click()
expect(page.locator(f".comment-text:has-text('{body}')")).to_be_visible()
def test_activity_comment_card_links_to_parent_post(alice):
page, user = alice
create_post(page, "devlog", "Post for activity comment link")
post_url = page.url
_post_comment(page, "Activity clickable comment body")
page.goto(
f"{BASE_URL}/profile/{user['username']}?tab=activity",
wait_until="domcontentloaded",
)
card_link = page.locator(
".activity-card.card-link-host a.card-link[href*='#comment-']"
).first
expect(card_link).to_have_count(1)
href = card_link.get_attribute("href")
assert "/posts/" in href and "#comment-" in href
card_link.click()
page.wait_for_url("**/posts/**", wait_until="domcontentloaded")
expect(
page.locator(".comment-text:has-text('Activity clickable comment body')")
).to_be_visible()
def test_activity_post_card_links_to_post(alice):
page, user = alice
create_post(page, "showcase", "Post for activity post link", title="Activity Post Title")
page.goto(
f"{BASE_URL}/profile/{user['username']}?tab=activity",
wait_until="domcontentloaded",
)
post_link = page.locator(
".activity-card.card-link-host a.card-link[href^='/posts/']:not([href*='#comment-'])"
).first
expect(post_link).to_have_count(1)
post_link.click()
page.wait_for_url("**/posts/**", wait_until="domcontentloaded")
expect(page.locator(".post-detail-title:has-text('Activity Post Title')")).to_be_visible()
def test_activity_inner_content_link_stays_clickable(alice, bob):
page, user = alice
create_post(page, "random", "Post for activity mention comment")
_post_comment(page, "Ping @bob_test in activity")
page.goto(
f"{BASE_URL}/profile/{user['username']}?tab=activity",
wait_until="domcontentloaded",
)
mention = page.locator(
".activity-card.card-link-host .activity-content a[href='/profile/bob_test']"
).first
expect(mention).to_have_count(1)
mention.click()
page.wait_for_url("**/profile/bob_test", wait_until="domcontentloaded")
def test_follow_then_unfollow(alice):
+5 -5
View File
@@ -22,9 +22,9 @@ def test_regenerate_avatar_updates_preview(alice):
def test_regenerate_button_hidden_for_other_user(alice, bob):
page, _ = alice
bob_page, bob_user = bob
page.goto(
f"{BASE_URL}/profile/{bob_user['username']}", wait_until="domcontentloaded"
alice_page, alice_user = alice
bob_page, _ = bob
bob_page.goto(
f"{BASE_URL}/profile/{alice_user['username']}", wait_until="domcontentloaded"
)
expect(page.locator("[data-regenerate-avatar]")).to_have_count(0)
expect(bob_page.locator("[data-regenerate-avatar]")).to_have_count(0)