"""Test API routes""" import pytest import json from decimal import Decimal class TestAuthRoutes: """Test authentication routes""" @pytest.mark.auth def test_register_success(self, client): """Test successful user registration""" response = client.post('/api/auth/register', json={ 'email': 'newuser@example.com', 'password': 'password123', 'username': 'newuser', 'first_name': 'New', 'last_name': 'User' }) assert response.status_code == 201 data = response.get_json() assert data['email'] == 'newuser@example.com' assert data['username'] == 'newuser' assert 'password' not in data assert 'password_hash' not in data @pytest.mark.auth def test_register_missing_fields(self, client): """Test registration with missing required fields""" response = client.post('/api/auth/register', json={ 'email': 'newuser@example.com' }) assert response.status_code == 400 data = response.get_json() assert 'error' in data @pytest.mark.auth def test_register_duplicate_email(self, client, regular_user): """Test registration with duplicate email""" response = client.post('/api/auth/register', json={ 'email': regular_user.email, 'password': 'password123' }) assert response.status_code == 400 data = response.get_json() assert 'already exists' in data['error'].lower() @pytest.mark.auth def test_login_success(self, client, regular_user): """Test successful login""" response = client.post('/api/auth/login', json={ 'email': regular_user.email, 'password': 'password123' }) assert response.status_code == 200 data = response.get_json() assert 'access_token' in data assert 'refresh_token' in data assert data['user']['email'] == regular_user.email @pytest.mark.auth @pytest.mark.parametrize("email,password,expected_status", [ ("wrong@example.com", "password123", 401), ("user@example.com", "wrongpassword", 401), (None, "password123", 400), ("user@example.com", None, 400), ]) def test_login_validation(self, client, regular_user, email, password, expected_status): """Test login with various invalid inputs""" login_data = {} if email is not None: login_data['email'] = email if password is not None: login_data['password'] = password response = client.post('/api/auth/login', json=login_data) assert response.status_code == expected_status @pytest.mark.auth def test_login_inactive_user(self, client, inactive_user): """Test login with inactive user""" response = client.post('/api/auth/login', json={ 'email': inactive_user.email, 'password': 'password123' }) assert response.status_code == 401 data = response.get_json() assert 'inactive' in data['error'].lower() @pytest.mark.auth def test_get_current_user(self, client, auth_headers, regular_user): """Test getting current user""" response = client.get('/api/users/me', headers=auth_headers) assert response.status_code == 200 data = response.get_json() assert data['email'] == regular_user.email @pytest.mark.auth def test_get_current_user_unauthorized(self, client): """Test getting current user without authentication""" response = client.get('/api/users/me') assert response.status_code == 401 class TestProductRoutes: """Test product routes""" @pytest.mark.product def test_get_products(self, client, products): """Test getting all products""" response = client.get('/api/products') assert response.status_code == 200 data = response.get_json() assert len(data) == 5 @pytest.mark.product def test_get_products_empty(self, client): """Test getting products when none exist""" response = client.get('/api/products') assert response.status_code == 200 data = response.get_json() assert len(data) == 0 @pytest.mark.product def test_get_single_product(self, client, product): """Test getting a single product""" response = client.get(f'/api/products/{product.id}') assert response.status_code == 200 data = response.get_json() assert data['id'] == product.id assert data['name'] == product.name @pytest.mark.product def test_get_product_not_found(self, client): """Test getting non-existent product""" response = client.get('/api/products/999') assert response.status_code == 404 @pytest.mark.product def test_create_product_admin(self, client, admin_headers): """Test creating product as admin""" response = client.post('/api/products', headers=admin_headers, json={ 'name': 'New Product', 'description': 'A new product', 'price': 29.99, 'stock': 10 }) assert response.status_code == 201 data = response.get_json() assert data['name'] == 'New Product' assert data['price'] == 29.99 @pytest.mark.product def test_create_product_regular_user(self, client, auth_headers): """Test creating product as regular user (should fail)""" response = client.post('/api/products', headers=auth_headers, json={ 'name': 'New Product', 'price': 29.99 }) assert response.status_code == 403 data = response.get_json() assert 'admin' in data['error'].lower() @pytest.mark.product def test_create_product_unauthorized(self, client): """Test creating product without authentication""" response = client.post('/api/products', json={ 'name': 'New Product', 'price': 29.99 }) assert response.status_code == 401 @pytest.mark.product def test_create_product_validation_error(self, client, admin_headers): """Test creating product with invalid data""" response = client.post('/api/products', headers=admin_headers, json={ 'name': 'New Product', 'price': -10.99 }) assert response.status_code == 400 data = response.get_json() assert 'Validation error' in data['error'] @pytest.mark.product def test_create_product_missing_required_fields(self, client, admin_headers): """Test creating product with missing required fields""" response = client.post('/api/products', headers=admin_headers, json={ 'description': 'Missing name and price' }) assert response.status_code == 400 data = response.get_json() assert 'Validation error' in data['error'] @pytest.mark.product def test_create_product_minimal_data(self, client, admin_headers): """Test creating product with minimal valid data""" response = client.post('/api/products', headers=admin_headers, json={ 'name': 'Minimal Product', 'price': 19.99 }) assert response.status_code == 201 data = response.get_json() assert data['name'] == 'Minimal Product' assert data['stock'] == 0 # Default value @pytest.mark.product def test_update_product_admin(self, client, admin_headers, product): """Test updating product as admin""" response = client.put(f'/api/products/{product.id}', headers=admin_headers, json={ 'name': 'Updated Product', 'price': 39.99 }) assert response.status_code == 200 data = response.get_json() assert data['name'] == 'Updated Product' assert data['price'] == 39.99 @pytest.mark.product def test_delete_product_admin(self, client, admin_headers, product): """Test deleting product as admin""" response = client.delete(f'/api/products/{product.id}', headers=admin_headers) assert response.status_code == 200 # Verify product is deleted response = client.get(f'/api/products/{product.id}') assert response.status_code == 404 class TestOrderRoutes: """Test order routes""" @pytest.mark.order def test_get_orders(self, client, auth_headers, order): """Test getting orders for current user""" response = client.get('/api/orders', headers=auth_headers) assert response.status_code == 200 data = response.get_json() assert len(data) >= 1 @pytest.mark.order def test_get_orders_unauthorized(self, client): """Test getting orders without authentication""" response = client.get('/api/orders') assert response.status_code == 401 @pytest.mark.order def test_create_order(self, client, auth_headers, products): """Test creating an order""" response = client.post('/api/orders', headers=auth_headers, json={ 'items': [ {'product_id': products[0].id, 'quantity': 2}, {'product_id': products[1].id, 'quantity': 1} ], 'shipping_address': '123 Test St' }) assert response.status_code == 201 data = response.get_json() assert 'id' in data assert len(data['items']) == 2 @pytest.mark.order def test_create_order_insufficient_stock(self, client, auth_headers, db_session, products): """Test creating order with insufficient stock""" # Set stock to 0 products[0].stock = 0 db_session.commit() response = client.post('/api/orders', headers=auth_headers, json={ 'items': [ {'product_id': products[0].id, 'quantity': 2} ] }) assert response.status_code == 400 data = response.get_json() assert 'insufficient' in data['error'].lower() @pytest.mark.order def test_get_single_order(self, client, auth_headers, order): """Test getting a single order""" response = client.get(f'/api/orders/{order.id}', headers=auth_headers) print('test_get_single_order', response.get_json()) assert response.status_code == 200 data = response.get_json() assert data['id'] == order.id @pytest.mark.order def test_get_other_users_order(self, client, admin_headers, regular_user, products): """Test admin accessing another user's order""" # Create an order for regular_user client.post('/api/auth/login', json={ 'email': regular_user.email, 'password': 'password123' }) # Admin should be able to access any order response = client.get(f'/api/orders/1', headers=admin_headers) # This test assumes order exists, adjust as needed pass