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