feat: 9.0 - Frontend - Display habits list
This commit is contained in:
173
dashboard/test_habits_display.py
Normal file
173
dashboard/test_habits_display.py
Normal file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Tests for Story 9.0: Frontend - Display habits list
|
||||
"""
|
||||
import re
|
||||
|
||||
def read_file(path):
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
return f.read()
|
||||
|
||||
def test_loading_state_structure():
|
||||
"""Test loading state HTML structure exists"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert 'id="loadingState"' in html, "Loading state element missing"
|
||||
assert 'class="loading-state"' in html, "Loading state class missing"
|
||||
assert 'data-lucide="loader"' in html, "Loading state loader icon missing"
|
||||
assert 'Se încarcă obiceiurile' in html, "Loading state message missing"
|
||||
print("✓ Loading state structure exists")
|
||||
|
||||
def test_error_state_structure():
|
||||
"""Test error state HTML structure exists"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert 'id="errorState"' in html, "Error state element missing"
|
||||
assert 'class="error-state"' in html, "Error state class missing"
|
||||
assert 'data-lucide="alert-circle"' in html, "Error state alert icon missing"
|
||||
assert 'Eroare la încărcarea obiceiurilor' in html, "Error state message missing"
|
||||
assert 'onclick="loadHabits()"' in html, "Retry button missing"
|
||||
print("✓ Error state structure exists")
|
||||
|
||||
def test_empty_state_has_id():
|
||||
"""Test empty state has id for JavaScript access"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert 'id="emptyState"' in html, "Empty state id missing"
|
||||
print("✓ Empty state has id attribute")
|
||||
|
||||
def test_habits_list_container():
|
||||
"""Test habits list container exists"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert 'id="habitsList"' in html, "Habits list container missing"
|
||||
assert 'class="habits-list"' in html, "Habits list class missing"
|
||||
print("✓ Habits list container exists")
|
||||
|
||||
def test_loadhabits_function_exists():
|
||||
"""Test loadHabits function is implemented"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert 'async function loadHabits()' in html, "loadHabits function not implemented"
|
||||
assert 'await fetch(\'/api/habits\')' in html, "API fetch call missing"
|
||||
print("✓ loadHabits function exists and fetches API")
|
||||
|
||||
def test_sorting_by_streak():
|
||||
"""Test habits are sorted by streak descending"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert 'habits.sort(' in html, "Sorting logic missing"
|
||||
assert 'streak' in html and '.sort(' in html, "Sort by streak missing"
|
||||
# Check for descending order (b.streak - a.streak pattern)
|
||||
assert re.search(r'b\.streak.*-.*a\.streak', html), "Descending sort pattern missing"
|
||||
print("✓ Habits sorted by streak descending")
|
||||
|
||||
def test_frequency_icons():
|
||||
"""Test frequency icons (calendar for daily, clock for weekly)"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert 'calendar' in html, "Calendar icon for daily habits missing"
|
||||
assert 'clock' in html, "Clock icon for weekly habits missing"
|
||||
# Check icon assignment logic
|
||||
assert 'daily' in html and 'calendar' in html, "Daily -> calendar mapping missing"
|
||||
assert 'weekly' in html and 'clock' in html, "Weekly -> clock mapping missing"
|
||||
print("✓ Frequency icons implemented (calendar/clock)")
|
||||
|
||||
def test_streak_display_with_flame():
|
||||
"""Test streak display includes flame emoji"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert '🔥' in html, "Flame emoji missing from streak display"
|
||||
assert 'habit-streak' in html, "Habit streak class missing"
|
||||
print("✓ Streak displays with flame emoji 🔥")
|
||||
|
||||
def test_show_hide_states():
|
||||
"""Test state management (loading, error, empty, list)"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
# Check for state toggling logic
|
||||
assert 'loadingState.classList.add(\'active\')' in html or \
|
||||
'loadingState.classList.add("active")' in html, "Loading state show missing"
|
||||
assert 'errorState.classList.remove(\'active\')' in html or \
|
||||
'errorState.classList.remove("active")' in html, "Error state hide missing"
|
||||
assert 'emptyState.style.display' in html, "Empty state toggle missing"
|
||||
assert 'habitsList.style.display' in html, "Habits list toggle missing"
|
||||
print("✓ State management implemented")
|
||||
|
||||
def test_error_handling():
|
||||
"""Test error handling shows error state"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert 'catch' in html, "Error handling missing"
|
||||
assert 'errorState.classList.add(\'active\')' in html or \
|
||||
'errorState.classList.add("active")' in html, "Error state activation missing"
|
||||
print("✓ Error handling implemented")
|
||||
|
||||
def test_createhabitcard_function():
|
||||
"""Test createHabitCard function exists"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert 'function createHabitCard(' in html, "createHabitCard function missing"
|
||||
assert 'habit.name' in html, "Habit name rendering missing"
|
||||
assert 'habit.frequency' in html, "Habit frequency rendering missing"
|
||||
assert 'habit.streak' in html, "Habit streak rendering missing"
|
||||
print("✓ createHabitCard function exists")
|
||||
|
||||
def test_page_load_trigger():
|
||||
"""Test loadHabits is called on page load"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert 'DOMContentLoaded' in html, "DOMContentLoaded listener missing"
|
||||
assert 'loadHabits()' in html, "loadHabits call missing"
|
||||
print("✓ loadHabits called on page load")
|
||||
|
||||
def test_habit_card_css():
|
||||
"""Test habit card CSS styling exists"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert '.habit-card' in html, "Habit card CSS missing"
|
||||
assert '.habit-icon' in html, "Habit icon CSS missing"
|
||||
assert '.habit-info' in html, "Habit info CSS missing"
|
||||
assert '.habit-name' in html, "Habit name CSS missing"
|
||||
assert '.habit-frequency' in html, "Habit frequency CSS missing"
|
||||
assert '.habit-streak' in html, "Habit streak CSS missing"
|
||||
print("✓ Habit card CSS styling exists")
|
||||
|
||||
def test_lucide_icons_reinitialized():
|
||||
"""Test Lucide icons are reinitialized after rendering"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert 'lucide.createIcons()' in html, "Lucide icons initialization missing"
|
||||
# Check it's called after rendering habits
|
||||
assert html.index('habitsList.appendChild') < html.rindex('lucide.createIcons()'), \
|
||||
"Lucide icons not reinitialized after rendering"
|
||||
print("✓ Lucide icons reinitialized after rendering")
|
||||
|
||||
def test_xss_protection():
|
||||
"""Test HTML escaping for XSS protection"""
|
||||
html = read_file('dashboard/habits.html')
|
||||
assert 'escapeHtml' in html, "HTML escaping function missing"
|
||||
assert 'textContent' in html or 'innerText' in html, "Text content method missing"
|
||||
print("✓ XSS protection implemented")
|
||||
|
||||
if __name__ == '__main__':
|
||||
tests = [
|
||||
test_loading_state_structure,
|
||||
test_error_state_structure,
|
||||
test_empty_state_has_id,
|
||||
test_habits_list_container,
|
||||
test_loadhabits_function_exists,
|
||||
test_sorting_by_streak,
|
||||
test_frequency_icons,
|
||||
test_streak_display_with_flame,
|
||||
test_show_hide_states,
|
||||
test_error_handling,
|
||||
test_createhabitcard_function,
|
||||
test_page_load_trigger,
|
||||
test_habit_card_css,
|
||||
test_lucide_icons_reinitialized,
|
||||
test_xss_protection,
|
||||
]
|
||||
|
||||
failed = 0
|
||||
for test in tests:
|
||||
try:
|
||||
test()
|
||||
except AssertionError as e:
|
||||
print(f"✗ {test.__name__}: {e}")
|
||||
failed += 1
|
||||
except Exception as e:
|
||||
print(f"✗ {test.__name__}: Unexpected error: {e}")
|
||||
failed += 1
|
||||
|
||||
print(f"\n{'='*50}")
|
||||
print(f"Tests: {len(tests)} total, {len(tests)-failed} passed, {failed} failed")
|
||||
if failed == 0:
|
||||
print("✓ All Story 9.0 tests passed!")
|
||||
exit(failed)
|
||||
Reference in New Issue
Block a user