All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m0s
- Add backend routines management with add, get, update, delete, and list functionalities. - Create models for Routine, RoutineItem, RoutineSchedule, and RoutineExtension. - Develop event types for routine confirmation and modification. - Implement frontend components for routine assignment, confirmation dialog, and routine management views. - Add unit tests for routine API and integration tests for routine CRUD flow. - Create end-to-end test plan for routines feature covering parent and child interactions.
188 lines
5.9 KiB
Python
188 lines
5.9 KiB
Python
from flask import Flask
|
|
from tinydb import Query
|
|
from werkzeug.security import generate_password_hash
|
|
|
|
from tests.conftest import TEST_SECRET_KEY, TEST_REFRESH_TOKEN_EXPIRY_DAYS
|
|
from api.auth_api import auth_api
|
|
from api.routine_api import routine_api
|
|
from api.routine_item_api import routine_item_api
|
|
from api.child_routine_api import child_routine_api
|
|
from api.routine_schedule_api import routine_schedule_api
|
|
from db.db import (
|
|
users_db,
|
|
child_db,
|
|
routine_db,
|
|
routine_items_db,
|
|
routine_schedules_db,
|
|
routine_extensions_db,
|
|
pending_confirmations_db,
|
|
)
|
|
|
|
|
|
TEST_USER_ID = 'routine-user-1'
|
|
TEST_EMAIL = 'routine-user@example.com'
|
|
TEST_PASSWORD = 'testpass'
|
|
|
|
|
|
def add_test_user():
|
|
users_db.remove(Query().email == TEST_EMAIL)
|
|
users_db.insert({
|
|
'id': TEST_USER_ID,
|
|
'first_name': 'Routine',
|
|
'last_name': 'Tester',
|
|
'email': TEST_EMAIL,
|
|
'password': generate_password_hash(TEST_PASSWORD),
|
|
'verified': True,
|
|
'image_id': 'boy01',
|
|
})
|
|
|
|
|
|
def login_and_set_cookie(client):
|
|
resp = client.post('/auth/login', json={'email': TEST_EMAIL, 'password': TEST_PASSWORD})
|
|
assert resp.status_code == 200
|
|
|
|
|
|
def seed_child(child_id: str):
|
|
child_db.remove(Query().id == child_id)
|
|
child_db.insert({
|
|
'id': child_id,
|
|
'name': 'Routine Kid',
|
|
'age': 9,
|
|
'tasks': [],
|
|
'routines': [],
|
|
'rewards': [],
|
|
'points': 0,
|
|
'image_id': 'boy01',
|
|
'user_id': TEST_USER_ID,
|
|
})
|
|
|
|
|
|
def _first_routine_id():
|
|
routines = routine_db.all()
|
|
assert routines
|
|
return routines[0]['id']
|
|
|
|
|
|
def _first_confirmation_id():
|
|
confirmations = pending_confirmations_db.all()
|
|
assert confirmations
|
|
return confirmations[0]['id']
|
|
|
|
|
|
def _make_client():
|
|
app = Flask(__name__)
|
|
app.register_blueprint(auth_api, url_prefix='/auth')
|
|
app.register_blueprint(routine_api)
|
|
app.register_blueprint(routine_item_api)
|
|
app.register_blueprint(child_routine_api)
|
|
app.register_blueprint(routine_schedule_api)
|
|
app.config['TESTING'] = True
|
|
app.config['SECRET_KEY'] = TEST_SECRET_KEY
|
|
app.config['REFRESH_TOKEN_EXPIRY_DAYS'] = TEST_REFRESH_TOKEN_EXPIRY_DAYS
|
|
return app
|
|
|
|
|
|
def setup_function(_):
|
|
routine_db.truncate()
|
|
routine_items_db.truncate()
|
|
routine_schedules_db.truncate()
|
|
routine_extensions_db.truncate()
|
|
pending_confirmations_db.truncate()
|
|
child_db.truncate()
|
|
|
|
|
|
def test_routine_crud_flow():
|
|
app = _make_client()
|
|
with app.test_client() as client:
|
|
add_test_user()
|
|
login_and_set_cookie(client)
|
|
|
|
add_resp = client.put('/routine/add', json={'name': 'Morning Routine', 'points': 8, 'image_id': 'sun'})
|
|
assert add_resp.status_code == 201
|
|
|
|
rid = _first_routine_id()
|
|
|
|
list_resp = client.get('/routine/list')
|
|
assert list_resp.status_code == 200
|
|
routines = list_resp.get_json()['routines']
|
|
assert len(routines) == 1
|
|
assert routines[0]['name'] == 'Morning Routine'
|
|
|
|
edit_resp = client.put(f'/routine/{rid}/edit', json={'points': 10})
|
|
assert edit_resp.status_code == 200
|
|
assert edit_resp.get_json()['points'] == 10
|
|
|
|
delete_resp = client.delete(f'/routine/{rid}')
|
|
assert delete_resp.status_code == 200
|
|
assert routine_db.all() == []
|
|
|
|
|
|
def test_child_routine_assignment_confirmation_and_approval():
|
|
app = _make_client()
|
|
with app.test_client() as client:
|
|
add_test_user()
|
|
login_and_set_cookie(client)
|
|
|
|
seed_child('routine-child-1')
|
|
client.put('/routine/add', json={'name': 'Evening Routine', 'points': 6, 'image_id': 'moon'})
|
|
rid = _first_routine_id()
|
|
|
|
add_item_resp = client.put(f'/routine/{rid}/item/add', json={'name': 'Brush Teeth', 'order': 0})
|
|
assert add_item_resp.status_code == 201
|
|
|
|
assign_resp = client.post('/child/routine-child-1/assign-routine', json={'routine_id': rid})
|
|
assert assign_resp.status_code == 200
|
|
|
|
list_resp = client.get('/child/routine-child-1/list-routines')
|
|
assert list_resp.status_code == 200
|
|
routines = list_resp.get_json()['routines']
|
|
assert len(routines) == 1
|
|
assert routines[0]['id'] == rid
|
|
assert routines[0]['items'][0]['name'] == 'Brush Teeth'
|
|
|
|
confirm_resp = client.post('/child/routine-child-1/confirm-routine', json={'routine_id': rid})
|
|
assert confirm_resp.status_code == 200
|
|
|
|
confirmation_id = _first_confirmation_id()
|
|
approve_resp = client.post(f'/child/routine-child-1/approve-routine/{confirmation_id}')
|
|
assert approve_resp.status_code == 200
|
|
|
|
child = child_db.get(Query().id == 'routine-child-1')
|
|
assert child['points'] == 6
|
|
|
|
|
|
def test_routine_schedule_and_extend_flow():
|
|
app = _make_client()
|
|
with app.test_client() as client:
|
|
add_test_user()
|
|
login_and_set_cookie(client)
|
|
|
|
seed_child('routine-child-2')
|
|
client.put('/routine/add', json={'name': 'School Routine', 'points': 5, 'image_id': 'book'})
|
|
rid = _first_routine_id()
|
|
|
|
client.post('/child/routine-child-2/assign-routine', json={'routine_id': rid})
|
|
|
|
set_resp = client.put(
|
|
f'/child/routine-child-2/routine/{rid}/schedule',
|
|
json={
|
|
'mode': 'days',
|
|
'day_configs': [{'day': 1, 'hour': 8, 'minute': 0}],
|
|
'default_hour': 8,
|
|
'default_minute': 0,
|
|
'default_has_deadline': True,
|
|
},
|
|
)
|
|
assert set_resp.status_code == 200
|
|
|
|
get_resp = client.get(f'/child/routine-child-2/routine/{rid}/schedule')
|
|
assert get_resp.status_code == 200
|
|
assert get_resp.get_json()['mode'] == 'days'
|
|
|
|
extend_resp = client.post(
|
|
f'/child/routine-child-2/routine/{rid}/extend',
|
|
json={'date': '2026-05-04'},
|
|
)
|
|
assert extend_resp.status_code == 200
|
|
assert extend_resp.get_json()['routine_id'] == rid
|