Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- Your new feature here.
## [1.2.1] - 2025-08-22

### Fixed
- Your new fix here.

- Corrected and updated the release comparison links in `CHANGELOG.md`.

## [1.2.0] - 2025-08-07

Expand Down Expand Up @@ -137,8 +133,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Flexible database configuration (SQLite/PostgreSQL).


[Unreleased]: https://github.com/PPeitsch/TimeTrack/compare/v1.0.1...HEAD
[1.1.1]: https://github.com/PPeitsch/TimeTrack/compare/v1.1.0....v1.1.1
[1.2.1]: https://github.com/PPeitsch/TimeTrack/compare/v1.2.0...v1.2.1
[1.2.0]: https://github.com/PPeitsch/TimeTrack/compare/v1.1.1...v1.2.0
[1.1.1]: https://github.com/PPeitsch/TimeTrack/compare/v1.1.0...v1.1.1
[1.1.0]: https://github.com/PPeitsch/TimeTrack/compare/v1.0.9...v1.1.0
[1.0.9]: https://github.com/PPeitsch/TimeTrack/compare/v1.0.8...v1.0.9
[1.0.8]: https://github.com/PPeitsch/TimeTrack/compare/v1.0.7...v1.0.8
Expand Down
114 changes: 114 additions & 0 deletions tests/test_routes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import json
import unittest
from datetime import date, datetime
from unittest.mock import patch
from flask import jsonify

from app.db.database import db
from app.models.models import Employee, ScheduleEntry
Expand All @@ -19,6 +21,12 @@ class TestConfig(Config):
self.app = create_app(TestConfig)
self.client = self.app.test_client()

from werkzeug.exceptions import BadRequest

@self.app.errorhandler(BadRequest)
def handle_bad_request(e):
return jsonify(error="Bad Request"), 400

with self.app.app_context():
db.create_all()
# Create a default employee
Expand Down Expand Up @@ -88,6 +96,112 @@ def test_manual_entry_route_post_invalid(self):
data = json.loads(response.data)
self.assertIn("error", data)

def test_manual_entry_post_bad_json(self):
response = self.client.post("/entry", data="{", content_type="application/json")
self.assertEqual(response.status_code, 400)
data = json.loads(response.data)
self.assertEqual(data["error"], "Bad Request")

def test_manual_entry_post_missing_fields(self):
# Test missing date
response = self.client.post("/entry", data=json.dumps({"employee_id": 1}), content_type="application/json")
self.assertEqual(response.status_code, 400)
self.assertEqual(json.loads(response.data)["error"], "Date is required")

# Test missing employee_id
response = self.client.post("/entry", data=json.dumps({"date": "2025-03-16", "entries": [{"entry": "09:00", "exit": "17:00"}]}), content_type="application/json")
self.assertEqual(response.status_code, 400)
self.assertEqual(json.loads(response.data)["error"], "Employee ID is required")

# Test missing entries for work day
response = self.client.post("/entry", data=json.dumps({"date": "2025-03-16", "employee_id": 1, "absence_code": None}), content_type="application/json")
self.assertEqual(response.status_code, 400)
self.assertEqual(json.loads(response.data)["error"], "Entries are required for work day")

def test_manual_entry_post_invalid_date(self):
entry_data = {"date": "invalid-date", "employee_id": 1}
response = self.client.post("/entry", data=json.dumps(entry_data), content_type="application/json")
self.assertEqual(response.status_code, 400)
self.assertEqual(json.loads(response.data)["error"], "Invalid date format")

def test_manual_entry_post_empty_entries(self):
entry_data = {"date": "2025-03-16", "employee_id": 1, "entries": [], "absence_code": None}
response = self.client.post("/entry", data=json.dumps(entry_data), content_type="application/json")
self.assertEqual(response.status_code, 400)
self.assertEqual(json.loads(response.data)["error"], "No time entries provided for work day")

def test_manual_entry_update_existing(self):
# First, create an entry
entry_data = {
"date": "2025-03-18",
"employee_id": 1,
"entries": [{"entry": "09:00", "exit": "12:00"}],
"absence_code": None,
}
self.client.post("/entry", data=json.dumps(entry_data), content_type="application/json")

# Now, update it
update_data = {
"date": "2025-03-18",
"employee_id": 1,
"entries": [{"entry": "09:00", "exit": "13:00"}], # Changed exit time
"absence_code": None,
}
response = self.client.post("/entry", data=json.dumps(update_data), content_type="application/json")
self.assertEqual(response.status_code, 200)

with self.app.app_context():
entry = ScheduleEntry.query.filter_by(date=datetime.strptime("2025-03-18", "%Y-%m-%d").date()).first()
self.assertEqual(len(entry.entries), 1)
self.assertEqual(entry.entries[0]["exit"], "13:00")

def test_get_entry_not_found(self):
response = self.client.get("/entry/2025-01-01")
self.assertEqual(response.status_code, 200)
self.assertEqual(json.loads(response.data), {})

def test_get_entry_found(self):
# Create an entry to find
entry_date = "2025-03-19"
entry_data = {
"date": entry_date,
"employee_id": 1,
"entries": [{"entry": "10:00", "exit": "18:00"}],
"absence_code": None,
}
self.client.post("/entry", data=json.dumps(entry_data), content_type="application/json")

response = self.client.get(f"/entry/{entry_date}")
self.assertEqual(response.status_code, 200)
data = json.loads(response.data)
self.assertEqual(len(data["entries"]), 1)
self.assertEqual(data["entries"][0]["entry"], "10:00")
self.assertEqual(data["hours"], 8.0)

def test_get_entry_invalid_date(self):
response = self.client.get("/entry/invalid-date")
self.assertEqual(response.status_code, 400)
self.assertEqual(json.loads(response.data)["error"], "Invalid date format")

def test_manual_entry_post_absence(self):
entry_data = {
"date": "2025-03-20",
"employee_id": 1,
"entries": [],
"absence_code": "VAC",
}
response = self.client.post("/entry", data=json.dumps(entry_data), content_type="application/json")
self.assertEqual(response.status_code, 200)
data = json.loads(response.data)
self.assertEqual(data["status"], "success")
self.assertNotIn("hours", data) # No hours for absence

with self.app.app_context():
entry = ScheduleEntry.query.filter_by(date=datetime.strptime("2025-03-20", "%Y-%m-%d").date()).first()
self.assertIsNotNone(entry)
self.assertEqual(entry.absence_code, "VAC")
self.assertEqual(entry.entries, [])

def test_time_summary_route(self):
# Test the time summary route
response = self.client.get("/summary/")
Expand Down
Loading