- Added `bot_username` to settings for dynamic retrieval of the bot's username. - Implemented `_resolve_bot_username` function to fetch the bot's username if not set, improving user experience in group chats. - Updated `DutyWithUser` schema to include optional `phone` and `username` fields for enhanced duty information. - Enhanced API responses to include contact details for users, ensuring better communication. - Introduced a new current duty view in the web app, displaying active duty information along with contact options. - Updated CSS styles for better presentation of contact information in duty cards. - Added unit tests to verify the inclusion of contact details in API responses and the functionality of the current duty view.
102 lines
3.9 KiB
Python
102 lines
3.9 KiB
Python
"""Tests for duty_teller.api.dependencies (lang, auth error, date validation, private client)."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from fastapi import HTTPException
|
|
|
|
import duty_teller.api.dependencies as deps
|
|
import duty_teller.config as config
|
|
|
|
|
|
class TestLangFromAcceptLanguage:
|
|
"""Tests for _lang_from_accept_language."""
|
|
|
|
def test_none_returns_default(self):
|
|
assert deps._lang_from_accept_language(None) == config.DEFAULT_LANGUAGE
|
|
|
|
def test_empty_string_returns_default(self):
|
|
assert deps._lang_from_accept_language("") == config.DEFAULT_LANGUAGE
|
|
assert deps._lang_from_accept_language(" ") == config.DEFAULT_LANGUAGE
|
|
|
|
def test_ru_ru_returns_ru(self):
|
|
assert deps._lang_from_accept_language("ru-RU,ru;q=0.9") == "ru"
|
|
|
|
def test_en_us_returns_en(self):
|
|
assert deps._lang_from_accept_language("en-US") == "en"
|
|
|
|
def test_invalid_fallback_to_en(self):
|
|
assert deps._lang_from_accept_language("zz") == "en"
|
|
assert deps._lang_from_accept_language("x") == "en"
|
|
|
|
|
|
class TestAuthErrorDetail:
|
|
"""Tests for _auth_error_detail."""
|
|
|
|
def test_hash_mismatch_uses_bad_signature_key(self):
|
|
with patch("duty_teller.api.dependencies.t") as mock_t:
|
|
mock_t.return_value = "Bad signature"
|
|
result = deps._auth_error_detail("hash_mismatch", "en")
|
|
assert result == "Bad signature"
|
|
mock_t.assert_called_once_with("en", "api.auth_bad_signature")
|
|
|
|
def test_other_reason_uses_auth_invalid_key(self):
|
|
with patch("duty_teller.api.dependencies.t") as mock_t:
|
|
mock_t.return_value = "Invalid auth"
|
|
result = deps._auth_error_detail("expired", "ru")
|
|
assert result == "Invalid auth"
|
|
mock_t.assert_called_once_with("ru", "api.auth_invalid")
|
|
|
|
|
|
class TestValidateDutyDates:
|
|
"""Tests for _validate_duty_dates."""
|
|
|
|
def test_valid_range_no_exception(self):
|
|
deps._validate_duty_dates("2025-01-01", "2025-01-31", "en")
|
|
|
|
def test_bad_format_raises_400_with_i18n(self):
|
|
with patch("duty_teller.api.dependencies.t") as mock_t:
|
|
mock_t.return_value = "Bad format message"
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
deps._validate_duty_dates("01-01-2025", "2025-01-31", "en")
|
|
assert exc_info.value.status_code == 400
|
|
assert exc_info.value.detail == "Bad format message"
|
|
mock_t.assert_called_with("en", "dates.bad_format")
|
|
|
|
def test_from_after_to_raises_400_with_i18n(self):
|
|
with patch("duty_teller.api.dependencies.t") as mock_t:
|
|
mock_t.return_value = "From after to message"
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
deps._validate_duty_dates("2025-02-01", "2025-01-01", "ru")
|
|
assert exc_info.value.status_code == 400
|
|
assert exc_info.value.detail == "From after to message"
|
|
mock_t.assert_called_with("ru", "dates.from_after_to")
|
|
|
|
|
|
class TestFetchDutiesResponse:
|
|
"""Tests for fetch_duties_response (DutyWithUser list with phone, username)."""
|
|
|
|
def test_fetch_duties_response_includes_phone_and_username(self):
|
|
"""get_duties returns (Duty, full_name, phone, username); response has phone, username."""
|
|
from types import SimpleNamespace
|
|
|
|
from duty_teller.db.schemas import DutyWithUser
|
|
|
|
duty = SimpleNamespace(
|
|
id=1,
|
|
user_id=10,
|
|
start_at="2025-01-15T09:00:00Z",
|
|
end_at="2025-01-15T18:00:00Z",
|
|
event_type="duty",
|
|
)
|
|
rows = [(duty, "Alice", "+79001234567", "alice_dev")]
|
|
with patch.object(deps, "get_duties", return_value=rows):
|
|
result = deps.fetch_duties_response(
|
|
type("Session", (), {})(), "2025-01-01", "2025-01-31"
|
|
)
|
|
assert len(result) == 1
|
|
assert isinstance(result[0], DutyWithUser)
|
|
assert result[0].full_name == "Alice"
|
|
assert result[0].phone == "+79001234567"
|
|
assert result[0].username == "alice_dev"
|