mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-01-05 19:20:21 -06:00
- Normalize line endings from CRLF to LF across all files to match .editorconfig - Standardize quote style from single quotes to double quotes - Normalize whitespace and formatting throughout codebase - Apply consistent code style across 372 files including: * Application code (models, routes, services, utils) * Test files * Configuration files * CI/CD workflows This ensures consistency with the project's .editorconfig settings and improves code maintainability.
297 lines
9.6 KiB
Python
297 lines
9.6 KiB
Python
"""
|
|
Comprehensive API testing suite.
|
|
Tests API endpoints to improve coverage.
|
|
"""
|
|
|
|
import pytest
|
|
from datetime import datetime, timedelta, date
|
|
from decimal import Decimal
|
|
import json
|
|
|
|
|
|
# ============================================================================
|
|
# Timer API Tests
|
|
# ============================================================================
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_start_timer_api(authenticated_client, project):
|
|
"""Test starting a timer via API."""
|
|
response = authenticated_client.post(
|
|
"/api/timer/start", json={"project_id": project.id, "notes": "Working on feature"}
|
|
)
|
|
|
|
# Should succeed or return appropriate status
|
|
assert response.status_code in [200, 201, 404, 405]
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_timer_status(authenticated_client):
|
|
"""Test getting timer status."""
|
|
response = authenticated_client.get("/api/timer/status")
|
|
|
|
# Should return status or appropriate error
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
# ============================================================================
|
|
# Project API Tests
|
|
# ============================================================================
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_projects_list(authenticated_client):
|
|
"""Test getting list of projects."""
|
|
response = authenticated_client.get("/api/projects")
|
|
|
|
# Should return projects list or appropriate error
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_project_details(authenticated_client, project):
|
|
"""Test getting project details."""
|
|
response = authenticated_client.get(f"/api/projects/{project.id}")
|
|
|
|
# Should return project details or appropriate error
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
# ============================================================================
|
|
# Time Entry API Tests
|
|
# ============================================================================
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_time_entries(authenticated_client):
|
|
"""Test getting time entries list."""
|
|
response = authenticated_client.get("/api/time-entries")
|
|
|
|
# Should return time entries or appropriate error
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_time_entry_details(authenticated_client, time_entry):
|
|
"""Test getting time entry details."""
|
|
response = authenticated_client.get(f"/api/time-entries/{time_entry.id}")
|
|
|
|
# Should return time entry details or appropriate error
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
# ============================================================================
|
|
# Client API Tests
|
|
# ============================================================================
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_clients_list(authenticated_client):
|
|
"""Test getting list of clients."""
|
|
response = authenticated_client.get("/api/clients")
|
|
|
|
# Should return clients list or appropriate error
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_client_details(authenticated_client, test_client):
|
|
"""Test getting client details."""
|
|
response = authenticated_client.get(f"/api/clients/{test_client.id}")
|
|
|
|
# Should return client details or appropriate error
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
# ============================================================================
|
|
# Invoice API Tests
|
|
# ============================================================================
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_invoices_list(authenticated_client):
|
|
"""Test getting list of invoices."""
|
|
response = authenticated_client.get("/api/invoices")
|
|
|
|
# Should return invoices list or appropriate error
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_invoice_details(authenticated_client, invoice):
|
|
"""Test getting invoice details."""
|
|
response = authenticated_client.get(f"/api/invoices/{invoice.id}")
|
|
|
|
# Should return invoice details or appropriate error
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
# ============================================================================
|
|
# Report API Tests
|
|
# ============================================================================
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_time_report(authenticated_client):
|
|
"""Test getting time report."""
|
|
response = authenticated_client.get(
|
|
"/api/reports/time",
|
|
query_string={
|
|
"start_date": (datetime.utcnow() - timedelta(days=7)).strftime("%Y-%m-%d"),
|
|
"end_date": datetime.utcnow().strftime("%Y-%m-%d"),
|
|
},
|
|
)
|
|
|
|
# Should return report or appropriate error
|
|
assert response.status_code in [200, 404, 500]
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_project_report(authenticated_client, project):
|
|
"""Test getting project report."""
|
|
response = authenticated_client.get(f"/api/reports/projects/{project.id}")
|
|
|
|
# Should return report or appropriate error
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
# ============================================================================
|
|
# Task API Tests
|
|
# ============================================================================
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_tasks_list(authenticated_client):
|
|
"""Test getting list of tasks."""
|
|
response = authenticated_client.get("/api/tasks")
|
|
|
|
# Should return tasks list or appropriate error (400 is also valid if params are required)
|
|
assert response.status_code in [200, 400, 404]
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_task_details(authenticated_client, task):
|
|
"""Test getting task details."""
|
|
response = authenticated_client.get(f"/api/tasks/{task.id}")
|
|
|
|
# Should return task details or appropriate error
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_project_tasks_excludes_done_and_cancelled(authenticated_client, project, user, app):
|
|
"""Test that /api/projects/<project_id>/tasks excludes done and cancelled tasks."""
|
|
from app.models import Task
|
|
from app import db
|
|
|
|
# Create tasks with different statuses
|
|
active_task = Task(name="Active Task", project_id=project.id, status="todo", created_by=user.id)
|
|
in_progress_task = Task(name="In Progress Task", project_id=project.id, status="in_progress", created_by=user.id)
|
|
review_task = Task(name="Review Task", project_id=project.id, status="review", created_by=user.id)
|
|
done_task = Task(name="Done Task", project_id=project.id, status="done", created_by=user.id)
|
|
cancelled_task = Task(name="Cancelled Task", project_id=project.id, status="cancelled", created_by=user.id)
|
|
|
|
db.session.add_all([active_task, in_progress_task, review_task, done_task, cancelled_task])
|
|
db.session.commit()
|
|
|
|
# Get tasks for the project
|
|
response = authenticated_client.get(f"/api/projects/{project.id}/tasks")
|
|
|
|
assert response.status_code == 200
|
|
data = json.loads(response.data)
|
|
assert "tasks" in data
|
|
assert data["success"] is True
|
|
|
|
# Verify only active tasks are returned
|
|
task_names = [t["name"] for t in data["tasks"]]
|
|
assert "Active Task" in task_names
|
|
assert "In Progress Task" in task_names
|
|
assert "Review Task" in task_names
|
|
assert "Done Task" not in task_names
|
|
assert "Cancelled Task" not in task_names
|
|
|
|
# Verify we got exactly 3 tasks
|
|
assert len(data["tasks"]) == 3
|
|
|
|
|
|
# ============================================================================
|
|
# Settings API Tests
|
|
# ============================================================================
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_settings(authenticated_client):
|
|
"""Test getting application settings."""
|
|
response = authenticated_client.get("/api/settings")
|
|
|
|
# Should return settings or appropriate error
|
|
assert response.status_code in [200, 404]
|
|
|
|
|
|
# ============================================================================
|
|
# Analytics API Tests
|
|
# ============================================================================
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_get_dashboard_stats(authenticated_client):
|
|
"""Test getting dashboard statistics."""
|
|
response = authenticated_client.get("/api/analytics/dashboard")
|
|
|
|
# Should return stats or appropriate error
|
|
assert response.status_code in [200, 404, 500]
|
|
|
|
|
|
# ============================================================================
|
|
# Search API Tests
|
|
# ============================================================================
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_search_api(authenticated_client):
|
|
"""Test search API endpoint."""
|
|
response = authenticated_client.get("/api/search", query_string={"q": "test"})
|
|
|
|
# Should return search results or appropriate error
|
|
assert response.status_code in [200, 400, 404]
|
|
|
|
|
|
# ============================================================================
|
|
# Export API Tests
|
|
# ============================================================================
|
|
|
|
|
|
@pytest.mark.api
|
|
@pytest.mark.integration
|
|
def test_export_time_entries(authenticated_client):
|
|
"""Test exporting time entries."""
|
|
response = authenticated_client.get(
|
|
"/api/export/time-entries",
|
|
query_string={
|
|
"format": "csv",
|
|
"start_date": (datetime.utcnow() - timedelta(days=7)).strftime("%Y-%m-%d"),
|
|
"end_date": datetime.utcnow().strftime("%Y-%m-%d"),
|
|
},
|
|
)
|
|
|
|
# Should return export or appropriate error
|
|
assert response.status_code in [200, 404, 500]
|