feat: Space Booking System - MVP complet
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>
This commit is contained in:
127
backend/tests/test_google_calendar_api.py
Normal file
127
backend/tests/test_google_calendar_api.py
Normal file
@@ -0,0 +1,127 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user