✨ Major Features Added: - Complete magical theming and rebranding from LifeRPG to The Wizard's Grimoire - Production-grade React frontend with Tailwind CSS v4 and magical aesthetics - Comprehensive analytics dashboard with Recharts integration (ScryingPortal) - Push notifications system with PWA service worker support - Drag & drop functionality using @dnd-kit for habit reordering - Social features with friends system and leaderboards - Performance optimization tools and monitoring - Mobile app enhancement with PWA installation support 🏗️ Technical Infrastructure: - Advanced service worker with offline support and background sync - Zustand state management for scalable application state - Production-ready UI component system with enhanced Button, Card, Input - Progressive Web App (PWA) with manifest and app installation - FastAPI backend with comprehensive API endpoints - Docker containerization and CI/CD pipeline setup 📱 Progressive Web App Features: - Offline functionality with intelligent caching - Push notification support for habit reminders - App installation on mobile and desktop platforms - Background sync for offline data management - Performance monitoring and optimization tools 🎨 User Experience: - Magical wizard/grimoire theming throughout application - Responsive design optimized for all device sizes - Drag & drop habit management with smooth animations - Interactive analytics with multiple chart types - Social connectivity with friends and competitive features - Comprehensive notification and performance settings 🔧 Developer Experience: - Modern development stack with Vite and React - Comprehensive testing setup and CI/CD pipelines - Code quality tools with pre-commit hooks - Docker development environment - Detailed documentation and implementation guides This represents a complete transformation from prototype to production-ready application with enterprise-grade features and magical user experience.
59 lines
2.1 KiB
Python
59 lines
2.1 KiB
Python
import os
|
|
import json
|
|
import types
|
|
|
|
|
|
class FakeJob:
|
|
def __init__(self, id='job-1'):
|
|
self.id = id
|
|
|
|
|
|
class FakeQueue:
|
|
def enqueue(self, fn, *args, **kwargs):
|
|
return FakeJob()
|
|
|
|
|
|
def test_todoist_connect_and_sync_inline(client, monkeypatch):
|
|
# Ensure no queue so it runs inline
|
|
import modern.backend.app as app
|
|
monkeypatch.setattr(app, 'enqueue_adapter_sync', lambda provider, integration_id: None)
|
|
# stub run_adapter_sync to avoid network
|
|
monkeypatch.setattr(app, 'run_adapter_sync', lambda provider, integration_id: {"ok": True, "count": 2})
|
|
|
|
# create user (id assumed 1 by default DB state; but ensure)
|
|
r = client.post('/api/v1/users', json={'email': 'u@example.com'})
|
|
uid = r.json()['id']
|
|
|
|
# login to get a token cookie
|
|
client.post('/api/v1/auth/signup', json={'email': 'u@example.com', 'password': 'pw'})
|
|
# connect todoist (store token)
|
|
r = client.post('/api/v1/integrations/todoist/connect', json={'user_id': uid, 'api_token': 'x'})
|
|
assert r.status_code == 200
|
|
integ_id = r.json()['id']
|
|
# trigger sync (inline)
|
|
r = client.post(f'/api/v1/integrations/{integ_id}/sync')
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert data['queued'] is False and data['result']['ok'] is True
|
|
|
|
|
|
def test_github_connect_and_sync_enqueued(client, monkeypatch):
|
|
# Patch queue to simulate enqueue
|
|
import modern.backend.app as app
|
|
monkeypatch.setattr(app, 'enqueue_adapter_sync', lambda provider, integration_id: types.SimpleNamespace(id='job-123'))
|
|
|
|
# create user and login
|
|
client.post('/api/v1/users', json={'email': 'g@example.com'})
|
|
client.post('/api/v1/auth/signup', json={'email': 'g@example.com', 'password': 'pw'})
|
|
|
|
# connect github
|
|
r = client.post('/api/v1/integrations/github/connect', json={'user_id': 1, 'token': 'pat'})
|
|
assert r.status_code == 200
|
|
integ_id = r.json()['id']
|
|
|
|
# trigger sync -> should be queued
|
|
r = client.post(f'/api/v1/integrations/{integ_id}/sync')
|
|
assert r.status_code == 200
|
|
j = r.json()
|
|
assert j['queued'] is True and 'job_id' in j
|