155 lines
5.7 KiB
Python
155 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test script to verify frontend-backend integration for tickets #141 and #143.
|
|
Sends the exact payloads from frontend components and checks API responses.
|
|
"""
|
|
|
|
import requests
|
|
import json
|
|
import sys
|
|
|
|
BASE_URL = "http://sf_api:8000/api/v1"
|
|
LOGIN_URL = f"{BASE_URL}/auth/login"
|
|
|
|
def get_auth_token():
|
|
"""Login with admin credentials and return JWT token."""
|
|
payload = {
|
|
"username": "admin@servicefinder.hu",
|
|
"password": "Admin123!"
|
|
}
|
|
try:
|
|
resp = requests.post(LOGIN_URL, json=payload, timeout=10)
|
|
resp.raise_for_status()
|
|
data = resp.json()
|
|
token = data.get("access_token")
|
|
if not token:
|
|
print("ERROR: No access_token in login response")
|
|
print(f"Response: {data}")
|
|
sys.exit(1)
|
|
print(f"SUCCESS: Obtained token (first 20 chars): {token[:20]}...")
|
|
return token
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"ERROR: Login failed: {e}")
|
|
if hasattr(e, 'response') and e.response is not None:
|
|
print(f"Response status: {e.response.status_code}")
|
|
print(f"Response body: {e.response.text}")
|
|
sys.exit(1)
|
|
|
|
def test_vehicle_creation(token):
|
|
"""Test POST /api/v1/assets/vehicles with frontend payload."""
|
|
url = f"{BASE_URL}/assets/vehicles"
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
# Payload from AddVehicle.vue saveVehicle()
|
|
payload = {
|
|
"vin": None,
|
|
"license_plate": "N/A",
|
|
"catalog_id": None,
|
|
"organization_id": 1
|
|
}
|
|
print("\n--- Testing Vehicle Creation ---")
|
|
print(f"URL: {url}")
|
|
print(f"Payload: {json.dumps(payload, indent=2)}")
|
|
try:
|
|
resp = requests.post(url, json=payload, headers=headers, timeout=10)
|
|
print(f"Response status: {resp.status_code}")
|
|
print(f"Response body: {resp.text}")
|
|
resp.raise_for_status()
|
|
print("✅ Vehicle creation successful")
|
|
return resp.json()
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"❌ Vehicle creation failed: {e}")
|
|
if hasattr(e, 'response') and e.response is not None:
|
|
print(f"Response details: {e.response.text}")
|
|
return None
|
|
|
|
def test_expense_creation(token, asset_id=None):
|
|
"""Test POST /api/v1/expenses/ with frontend payload."""
|
|
url = f"{BASE_URL}/expenses/"
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
# Payload from AddExpense.vue handleSubmit()
|
|
# Note: frontend does NOT include organization_id, which is required by schema.
|
|
# We'll try both with and without.
|
|
payload = {
|
|
"cost_type": "fuel",
|
|
"amount_local": 15000,
|
|
"currency_local": "HUF",
|
|
"mileage_at_cost": 120000,
|
|
"date": "2026-03-26T09:00:00Z",
|
|
"asset_id": asset_id or "00000000-0000-0000-0000-000000000000", # dummy UUID
|
|
"description": None,
|
|
"data": {}
|
|
# organization_id is missing
|
|
}
|
|
print("\n--- Testing Expense Creation (without organization_id) ---")
|
|
print(f"URL: {url}")
|
|
print(f"Payload: {json.dumps(payload, indent=2)}")
|
|
try:
|
|
resp = requests.post(url, json=payload, headers=headers, timeout=10)
|
|
print(f"Response status: {resp.status_code}")
|
|
print(f"Response body: {resp.text}")
|
|
resp.raise_for_status()
|
|
print("✅ Expense creation successful")
|
|
return resp.json()
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"❌ Expense creation failed: {e}")
|
|
if hasattr(e, 'response') and e.response is not None:
|
|
print(f"Response details: {e.response.text}")
|
|
return None
|
|
|
|
def test_expense_with_org(token, asset_id=None):
|
|
"""Test expense creation with organization_id added (as schema requires)."""
|
|
url = f"{BASE_URL}/expenses/"
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
payload = {
|
|
"cost_type": "fuel",
|
|
"amount_local": 15000,
|
|
"currency_local": "HUF",
|
|
"mileage_at_cost": 120000,
|
|
"date": "2026-03-26T09:00:00Z",
|
|
"asset_id": asset_id or "00000000-0000-0000-0000-000000000000",
|
|
"organization_id": 1, # added
|
|
"description": None,
|
|
"data": {}
|
|
}
|
|
print("\n--- Testing Expense Creation (with organization_id) ---")
|
|
print(f"URL: {url}")
|
|
print(f"Payload: {json.dumps(payload, indent=2)}")
|
|
try:
|
|
resp = requests.post(url, json=payload, headers=headers, timeout=10)
|
|
print(f"Response status: {resp.status_code}")
|
|
print(f"Response body: {resp.text}")
|
|
resp.raise_for_status()
|
|
print("✅ Expense creation successful")
|
|
return resp.json()
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"❌ Expense creation failed: {e}")
|
|
if hasattr(e, 'response') and e.response is not None:
|
|
print(f"Response details: {e.response.text}")
|
|
return None
|
|
|
|
def main():
|
|
print("🚀 Starting integration verification for tickets #141 and #143")
|
|
token = get_auth_token()
|
|
|
|
# Test vehicle creation
|
|
vehicle_result = test_vehicle_creation(token)
|
|
asset_id = None
|
|
if vehicle_result and "id" in vehicle_result:
|
|
asset_id = vehicle_result["id"]
|
|
print(f"Created asset ID: {asset_id}")
|
|
else:
|
|
print("WARNING: No asset ID obtained, using dummy UUID for expense test.")
|
|
|
|
# Test expense creation without organization_id (as frontend does)
|
|
test_expense_creation(token, asset_id)
|
|
|
|
# Test expense creation with organization_id (should succeed if schema validation passes)
|
|
test_expense_with_org(token, asset_id)
|
|
|
|
print("\n" + "="*60)
|
|
print("Verification complete. Check outputs above.")
|
|
print("If any test failed with 422/500, the integration is broken.")
|
|
print("="*60)
|
|
|
|
if __name__ == "__main__":
|
|
main() |