Files
TimeTracker/tests/test_new_features.py
T
Dries Peeters f7becfa946 test(models): create Client/User rows to satisfy FK enforcement
With foreign keys enforced in tests, hard-coded client_id=1 and
user_id=1 references no longer work because no such rows exist in the
isolated test database. Create the required parent rows (Client for
inventory project tests, Client + User for the burndown/SavedFilter
smoke tests) before inserting the children.
2026-05-14 06:22:53 +02:00

130 lines
4.8 KiB
Python

import pytest
from app import db
from app.models import Project, User, SavedFilter, Task, Client
@pytest.mark.smoke
@pytest.mark.api
def test_burndown_endpoint_available(client, app):
"""Test that burndown endpoint is available."""
# Minimal entities (create client first so FK enforcement is satisfied).
u = User(username="admin")
u.role = "admin"
u.is_active = True
db.session.add(u)
c = Client(name="X Client")
db.session.add(c)
db.session.flush()
p = Project(name="X", client_id=c.id, billable=False)
db.session.add(p)
db.session.commit()
# Just ensure route exists; not full auth flow here
# This is a placeholder smoke test to be expanded in integration tests
assert True
@pytest.mark.smoke
@pytest.mark.models
def test_saved_filter_model_roundtrip(app):
"""Test that SavedFilter can be created and serialized."""
# Create a user so SavedFilter's user_id FK is satisfied.
u = User(username="sf_user", role="user")
u.is_active = True
db.session.add(u)
db.session.flush()
sf = SavedFilter(user_id=u.id, name="My Filter", scope="time", payload={"project_id": 1, "tag": "deep"})
db.session.add(sf)
db.session.commit()
as_dict = sf.to_dict()
assert as_dict["name"] == "My Filter"
assert as_dict["scope"] == "time"
@pytest.mark.api
@pytest.mark.integration
def test_inline_client_creation_json_flow(admin_authenticated_client):
"""Creating a client via AJAX JSON should return 201 and client payload."""
resp = admin_authenticated_client.post(
"/clients/create",
data={"name": "Inline Modal Client", "default_hourly_rate": "123.45"},
headers={"X-Requested-With": "XMLHttpRequest"},
)
assert resp.status_code in (201, 400, 403)
if resp.status_code == 201:
data = resp.get_json()
assert data["name"] == "Inline Modal Client"
assert data["id"] > 0
@pytest.mark.api
@pytest.mark.integration
@pytest.mark.models
def test_inline_task_creation_json_flow(authenticated_client, project, user, app):
"""Creating a task via AJAX JSON should return 201 and task payload with defaults."""
with app.app_context():
from app.models import Task
resp = authenticated_client.post(
"/api/tasks/create",
json={"name": "Inline Timer Task", "project_id": project.id},
headers={"X-Requested-With": "XMLHttpRequest", "Content-Type": "application/json"},
)
assert resp.status_code in (201, 400, 404)
if resp.status_code == 201:
data = resp.get_json()
assert data["success"] is True
assert data["name"] == "Inline Timer Task"
assert data["id"] > 0
assert "task" in data
# Verify task was created with defaults
task = Task.query.get(data["id"])
assert task is not None
assert task.name == "Inline Timer Task"
assert task.project_id == project.id
assert task.assigned_to == user.id # Assigned to current user
assert task.priority == "medium" # Default priority
assert task.due_date is None # No due date
assert task.created_by == user.id
@pytest.mark.smoke
@pytest.mark.api
@pytest.mark.integration
def test_start_timer_with_new_task_creation(authenticated_client, project, user, app):
"""Smoke test: Start timer with new task creation flow."""
with app.app_context():
from app.models import TimeEntry
# Simulate the flow: create task inline, then start timer
# Step 1: Create task via AJAX
task_resp = authenticated_client.post(
"/api/tasks/create",
json={"name": "Quick Task for Timer", "project_id": project.id},
headers={"X-Requested-With": "XMLHttpRequest", "Content-Type": "application/json"},
)
if task_resp.status_code == 201:
task_data = task_resp.get_json()
task_id = task_data["id"]
# Step 2: Start timer with the created task
timer_resp = authenticated_client.post(
"/timer/start",
data={"project_id": project.id, "task_id": task_id},
follow_redirects=False,
)
# Timer start should redirect or succeed
assert timer_resp.status_code in (200, 302, 400, 404)
# Verify timer was created
if timer_resp.status_code in (200, 302):
timer = TimeEntry.query.filter_by(
user_id=user.id,
project_id=project.id,
task_id=task_id,
end_time=None # Active timer
).first()
assert timer is not None, "Timer should be created"