Sistem web pentru rezervarea de birouri și săli de ședință cu flux de aprobare administrativă. Stack: FastAPI + Vue.js 3 + SQLite + TypeScript Features implementate: - Autentificare JWT + Self-registration cu email verification - CRUD Spații, Utilizatori, Settings (Admin) - Calendar interactiv (FullCalendar) cu drag-and-drop - Creare rezervări cu validare (durată, program, overlap, max/zi) - Rezervări recurente (săptămânal) - Admin: aprobare/respingere/anulare cereri - Admin: creare directă rezervări (bypass approval) - Admin: editare orice rezervare - User: editare/anulare rezervări proprii - Notificări in-app (bell icon + dropdown) - Notificări email (async SMTP cu BackgroundTasks) - Jurnal acțiuni administrative (audit log) - Rapoarte avansate (utilizare, top users, approval rate) - Șabloane rezervări (booking templates) - Atașamente fișiere (upload/download) - Conflict warnings (verificare disponibilitate real-time) - Integrare Google Calendar (OAuth2) - Suport timezone (UTC storage + user preference) - 225+ teste backend Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
128 lines
3.9 KiB
Python
128 lines
3.9 KiB
Python
"""Tests for Google Calendar API endpoints."""
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.main import app
|
|
from app.models.google_calendar_token import GoogleCalendarToken
|
|
from app.models.user import User
|
|
|
|
client = TestClient(app)
|
|
|
|
|
|
@pytest.fixture
|
|
def auth_headers(db: Session, test_user: User) -> dict[str, str]:
|
|
"""Get auth headers for test user."""
|
|
# Login to get token
|
|
response = client.post(
|
|
"/api/auth/login",
|
|
json={"email": test_user.email, "password": "testpassword"},
|
|
)
|
|
token = response.json()["access_token"]
|
|
return {"Authorization": f"Bearer {token}"}
|
|
|
|
|
|
def test_google_status_not_connected(auth_headers: dict[str, str]):
|
|
"""Test Google Calendar status when not connected."""
|
|
response = client.get("/api/integrations/google/status", headers=auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["connected"] is False
|
|
assert data["expires_at"] is None
|
|
|
|
|
|
def test_google_status_connected(
|
|
db: Session, test_user: User, auth_headers: dict[str, str]
|
|
):
|
|
"""Test Google Calendar status when connected."""
|
|
# Create token for user
|
|
token = GoogleCalendarToken(
|
|
user_id=test_user.id, # type: ignore[arg-type]
|
|
access_token="test_token",
|
|
refresh_token="test_refresh",
|
|
token_expiry=None,
|
|
)
|
|
db.add(token)
|
|
db.commit()
|
|
|
|
response = client.get("/api/integrations/google/status", headers=auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["connected"] is True
|
|
|
|
|
|
@patch("app.api.google_calendar.Flow")
|
|
def test_connect_google(mock_flow: MagicMock, auth_headers: dict[str, str]):
|
|
"""Test starting Google OAuth flow."""
|
|
# Setup mock
|
|
mock_flow_instance = MagicMock()
|
|
mock_flow_instance.authorization_url.return_value = (
|
|
"https://accounts.google.com/o/oauth2/auth?...",
|
|
"test_state",
|
|
)
|
|
mock_flow.from_client_config.return_value = mock_flow_instance
|
|
|
|
response = client.get("/api/integrations/google/connect", headers=auth_headers)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "authorization_url" in data
|
|
assert "state" in data
|
|
assert data["state"] == "test_state"
|
|
|
|
|
|
def test_disconnect_google_not_connected(auth_headers: dict[str, str]):
|
|
"""Test disconnecting when not connected."""
|
|
response = client.delete(
|
|
"/api/integrations/google/disconnect", headers=auth_headers
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
assert response.json()["message"] == "Google Calendar disconnected"
|
|
|
|
|
|
def test_disconnect_google_success(
|
|
db: Session, test_user: User, auth_headers: dict[str, str]
|
|
):
|
|
"""Test successful Google Calendar disconnect."""
|
|
# Create token for user
|
|
token = GoogleCalendarToken(
|
|
user_id=test_user.id, # type: ignore[arg-type]
|
|
access_token="test_token",
|
|
refresh_token="test_refresh",
|
|
token_expiry=None,
|
|
)
|
|
db.add(token)
|
|
db.commit()
|
|
|
|
response = client.delete(
|
|
"/api/integrations/google/disconnect", headers=auth_headers
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
assert response.json()["message"] == "Google Calendar disconnected"
|
|
|
|
# Verify token was deleted
|
|
token_in_db = (
|
|
db.query(GoogleCalendarToken)
|
|
.filter(GoogleCalendarToken.user_id == test_user.id)
|
|
.first()
|
|
)
|
|
assert token_in_db is None
|
|
|
|
|
|
def test_google_connect_requires_auth():
|
|
"""Test that Google Calendar endpoints require authentication."""
|
|
response = client.get("/api/integrations/google/connect")
|
|
assert response.status_code == 401
|
|
|
|
response = client.get("/api/integrations/google/status")
|
|
assert response.status_code == 401
|
|
|
|
response = client.delete("/api/integrations/google/disconnect")
|
|
assert response.status_code == 401
|