import time from datetime import datetime, timedelta, timezone import requests from tests.conftest import BASE_URL from devplacepy.database import get_table, get_activity_calendar, get_streaks, get_activity_heatmap from devplacepy.utils import generate_uid, check_milestone_badges _counter = [0] def _make_user(): _counter[0] += 1 uid = generate_uid() name = f"stk{int(time.time() * 1000)}{_counter[0]}" get_table("users").insert({ "uid": uid, "username": name, "email": f"{name}@t.dev", "role": "Member", "is_active": True, "xp": 0, "level": 1, "created_at": datetime.now(timezone.utc).isoformat(), }) return uid def _insert_post(user_uid, dt): uid = generate_uid() get_table("posts").insert({ "uid": uid, "user_uid": user_uid, "slug": f"{uid[:8]}-streak", "title": None, "content": "streak activity", "topic": "random", "project_uid": None, "image": None, "stars": 0, "created_at": dt.isoformat(), }) return uid def _insert_comment(user_uid, post_uid, dt): uid = generate_uid() get_table("comments").insert({ "uid": uid, "target_type": "post", "target_uid": post_uid, "post_uid": post_uid, "user_uid": user_uid, "content": "streak comment", "parent_uid": None, "created_at": dt.isoformat(), }) return uid def test_consecutive_days_build_streak(app_server): uid = _make_user() today = datetime.now(timezone.utc) for offset in (0, 1, 2): _insert_post(uid, today - timedelta(days=offset)) streaks = get_streaks(uid) assert streaks["current"] == 3 assert streaks["longest"] >= 3 def test_gap_resets_current_streak(app_server): uid = _make_user() today = datetime.now(timezone.utc) _insert_post(uid, today) _insert_post(uid, today - timedelta(days=3)) streaks = get_streaks(uid) assert streaks["current"] == 1 def test_yesterday_only_counts_as_current(app_server): uid = _make_user() yesterday = datetime.now(timezone.utc) - timedelta(days=1) _insert_post(uid, yesterday) assert get_streaks(uid)["current"] == 1 def test_calendar_sums_across_sources(app_server): uid = _make_user() today = datetime.now(timezone.utc) post_uid = _insert_post(uid, today) _insert_comment(uid, post_uid, today) calendar = get_activity_calendar(uid) assert calendar.get(today.date().isoformat()) == 2 def test_heatmap_shape(app_server): uid = _make_user() weeks = get_activity_heatmap(uid) assert 52 <= len(weeks) <= 54 assert all(len(week) <= 7 for week in weeks) def test_seven_day_streak_awards_on_fire_badge(app_server): uid = _make_user() today = datetime.now(timezone.utc) for offset in range(7): _insert_post(uid, today - timedelta(days=offset)) check_milestone_badges(uid) assert get_table("badges").count(user_uid=uid, badge_name="On Fire") == 1 def test_profile_renders_heatmap_and_streak(app_server): _counter[0] += 1 name = f"stkp{int(time.time() * 1000)}{_counter[0]}" s = requests.Session() s.post(f"{BASE_URL}/auth/signup", data={ "username": name, "email": f"{name}@t.dev", "password": "secret123", "confirm_password": "secret123", }, allow_redirects=True) s.post(f"{BASE_URL}/posts/create", data={ "content": "A post created today for the streak heatmap.", "title": "Streak heatmap post", "topic": "devlog", }, allow_redirects=True) html = s.get(f"{BASE_URL}/profile/{name}").text assert "heatmap-grid" in html assert "1 day streak" in html