Files
clawd/dashboard/test_habits_get_enhanced.py

253 lines
8.8 KiB
Python

#!/usr/bin/env python3
"""
Tests for enhanced GET /api/habits endpoint with streak and checkedToday fields.
"""
import json
import sys
import urllib.request
from pathlib import Path
from datetime import datetime, timedelta
BASE_URL = 'http://localhost:8088'
KANBAN_DIR = Path(__file__).parent
def test_habits_get_includes_streak_field():
"""Test that each habit includes a 'streak' field."""
# Create test habit with completions
today = datetime.now().date()
yesterday = today - timedelta(days=1)
two_days_ago = today - timedelta(days=2)
test_data = {
'habits': [
{
'id': 'habit-test1',
'name': 'Test Habit',
'frequency': 'daily',
'createdAt': '2026-02-01T10:00:00Z',
'completions': [
two_days_ago.isoformat(),
yesterday.isoformat(),
today.isoformat()
]
}
],
'lastUpdated': datetime.now().isoformat()
}
habits_file = KANBAN_DIR / 'habits.json'
habits_file.write_text(json.dumps(test_data, indent=2), encoding='utf-8')
# Test GET
req = urllib.request.Request(f'{BASE_URL}/api/habits')
with urllib.request.urlopen(req) as response:
result = json.loads(response.read().decode('utf-8'))
assert 'habits' in result, "Response should contain habits array"
assert len(result['habits']) == 1, "Should have one habit"
habit = result['habits'][0]
assert 'streak' in habit, "Habit should include 'streak' field"
assert isinstance(habit['streak'], int), "Streak should be an integer"
assert habit['streak'] == 3, f"Expected streak of 3, got {habit['streak']}"
print("✓ Each habit includes 'streak' field")
def test_habits_get_includes_checked_today_field():
"""Test that each habit includes a 'checkedToday' field."""
today = datetime.now().date().isoformat()
test_data = {
'habits': [
{
'id': 'habit-test1',
'name': 'Checked Today',
'frequency': 'daily',
'createdAt': '2026-02-01T10:00:00Z',
'completions': [today]
},
{
'id': 'habit-test2',
'name': 'Not Checked Today',
'frequency': 'daily',
'createdAt': '2026-02-01T10:00:00Z',
'completions': ['2026-02-01']
}
],
'lastUpdated': datetime.now().isoformat()
}
habits_file = KANBAN_DIR / 'habits.json'
habits_file.write_text(json.dumps(test_data, indent=2), encoding='utf-8')
# Test GET
req = urllib.request.Request(f'{BASE_URL}/api/habits')
with urllib.request.urlopen(req) as response:
result = json.loads(response.read().decode('utf-8'))
assert len(result['habits']) == 2, "Should have two habits"
habit1 = result['habits'][0]
assert 'checkedToday' in habit1, "Habit should include 'checkedToday' field"
assert isinstance(habit1['checkedToday'], bool), "checkedToday should be boolean"
assert habit1['checkedToday'] is True, "Habit checked today should have checkedToday=True"
habit2 = result['habits'][1]
assert 'checkedToday' in habit2, "Habit should include 'checkedToday' field"
assert habit2['checkedToday'] is False, "Habit not checked today should have checkedToday=False"
print("✓ Each habit includes 'checkedToday' boolean field")
def test_habits_get_calculates_streak_correctly():
"""Test that streak is calculated using the streak utility function."""
today = datetime.now().date()
yesterday = today - timedelta(days=1)
two_days_ago = today - timedelta(days=2)
three_days_ago = today - timedelta(days=3)
four_days_ago = today - timedelta(days=4)
test_data = {
'habits': [
{
'id': 'habit-daily',
'name': 'Daily Habit',
'frequency': 'daily',
'createdAt': '2026-02-01T10:00:00Z',
'completions': [
four_days_ago.isoformat(),
three_days_ago.isoformat(),
two_days_ago.isoformat(),
yesterday.isoformat(),
today.isoformat()
]
},
{
'id': 'habit-broken',
'name': 'Broken Streak',
'frequency': 'daily',
'createdAt': '2026-02-01T10:00:00Z',
'completions': [
four_days_ago.isoformat(),
three_days_ago.isoformat()
# Missing two_days_ago - streak broken
]
},
{
'id': 'habit-weekly',
'name': 'Weekly Habit',
'frequency': 'weekly',
'createdAt': '2026-02-01T10:00:00Z',
'completions': [
today.isoformat(),
(today - timedelta(days=7)).isoformat(),
(today - timedelta(days=14)).isoformat()
]
}
],
'lastUpdated': datetime.now().isoformat()
}
habits_file = KANBAN_DIR / 'habits.json'
habits_file.write_text(json.dumps(test_data, indent=2), encoding='utf-8')
# Test GET
req = urllib.request.Request(f'{BASE_URL}/api/habits')
with urllib.request.urlopen(req) as response:
result = json.loads(response.read().decode('utf-8'))
assert len(result['habits']) == 3, "Should have three habits"
daily_habit = result['habits'][0]
assert daily_habit['streak'] == 5, f"Expected daily streak of 5, got {daily_habit['streak']}"
broken_habit = result['habits'][1]
assert broken_habit['streak'] == 0, f"Expected broken streak of 0, got {broken_habit['streak']}"
weekly_habit = result['habits'][2]
assert weekly_habit['streak'] == 3, f"Expected weekly streak of 3, got {weekly_habit['streak']}"
print("✓ Streak is calculated correctly using utility function")
def test_habits_get_empty_habits_array():
"""Test GET with empty habits array."""
test_data = {
'habits': [],
'lastUpdated': datetime.now().isoformat()
}
habits_file = KANBAN_DIR / 'habits.json'
habits_file.write_text(json.dumps(test_data, indent=2), encoding='utf-8')
# Test GET
req = urllib.request.Request(f'{BASE_URL}/api/habits')
with urllib.request.urlopen(req) as response:
result = json.loads(response.read().decode('utf-8'))
assert result['habits'] == [], "Should return empty array"
assert 'lastUpdated' in result, "Should include lastUpdated"
print("✓ Empty habits array handled correctly")
def test_habits_get_preserves_original_fields():
"""Test that all original habit fields are preserved."""
today = datetime.now().date().isoformat()
test_data = {
'habits': [
{
'id': 'habit-test1',
'name': 'Test Habit',
'frequency': 'daily',
'createdAt': '2026-02-01T10:00:00Z',
'completions': [today]
}
],
'lastUpdated': '2026-02-10T10:00:00Z'
}
habits_file = KANBAN_DIR / 'habits.json'
habits_file.write_text(json.dumps(test_data, indent=2), encoding='utf-8')
# Test GET
req = urllib.request.Request(f'{BASE_URL}/api/habits')
with urllib.request.urlopen(req) as response:
result = json.loads(response.read().decode('utf-8'))
habit = result['habits'][0]
assert habit['id'] == 'habit-test1', "Original id should be preserved"
assert habit['name'] == 'Test Habit', "Original name should be preserved"
assert habit['frequency'] == 'daily', "Original frequency should be preserved"
assert habit['createdAt'] == '2026-02-01T10:00:00Z', "Original createdAt should be preserved"
assert habit['completions'] == [today], "Original completions should be preserved"
assert 'streak' in habit, "Should add streak field"
assert 'checkedToday' in habit, "Should add checkedToday field"
print("✓ All original habit fields are preserved")
if __name__ == '__main__':
try:
print("\n=== Testing Enhanced GET /api/habits ===\n")
test_habits_get_includes_streak_field()
test_habits_get_includes_checked_today_field()
test_habits_get_calculates_streak_correctly()
test_habits_get_empty_habits_array()
test_habits_get_preserves_original_fields()
print("\n=== All Enhanced GET Tests Passed ✓ ===\n")
sys.exit(0)
except AssertionError as e:
print(f"\n❌ Test failed: {e}\n")
sys.exit(1)
except Exception as e:
print(f"\n❌ Error: {e}\n")
import traceback
traceback.print_exc()
sys.exit(1)