253 lines
8.8 KiB
Python
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)
|