diff --git a/backend/tests/test_items.py b/backend/tests/test_items.py index 7081ec32..440ee756 100644 --- a/backend/tests/test_items.py +++ b/backend/tests/test_items.py @@ -2,6 +2,232 @@ import pytest from fastapi import status +class TestItemSearch: + """Test item search functionality.""" + + def test_search_items_by_name_exact_match(self, test_client, test_db, user_token): + """Test exact name match in search.""" + from backend.models import Item + + item = Item( + name="Resistor 10K", + category="Electronics", + barcode="RES-10K-001", + part_number="R-10K", + quantity=100 + ) + test_db.add(item) + test_db.commit() + + response = test_client.get( + "/items/search?q=Resistor 10K", + headers={"Authorization": f"Bearer {user_token}"} + ) + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert len(data) >= 1 + assert data[0]["name"] == "Resistor 10K" + + def test_search_items_by_part_number(self, test_client, test_db, user_token): + """Test search by part number.""" + from backend.models import Item + + item = Item( + name="Capacitor", + category="Electronics", + barcode="CAP-100U-001", + part_number="CAP-100UF", + quantity=50 + ) + test_db.add(item) + test_db.commit() + + response = test_client.get( + "/items/search?q=CAP-100UF", + headers={"Authorization": f"Bearer {user_token}"} + ) + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert len(data) >= 1 + assert any(item["part_number"] == "CAP-100UF" for item in data) + + def test_search_items_by_barcode(self, test_client, test_db, user_token): + """Test search by barcode.""" + from backend.models import Item + + item = Item( + name="Diode", + category="Electronics", + barcode="BAR-123456789", + part_number="D-1N4007", + quantity=200 + ) + test_db.add(item) + test_db.commit() + + response = test_client.get( + "/items/search?q=BAR-123456789", + headers={"Authorization": f"Bearer {user_token}"} + ) + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert len(data) >= 1 + assert any(item["barcode"] == "BAR-123456789" for item in data) + + def test_search_items_by_category(self, test_client, test_db, user_token): + """Test search by category.""" + from backend.models import Item + + item = Item( + name="Test Item", + category="Networking", + barcode="NET-001", + part_number="NET-PN", + quantity=10 + ) + test_db.add(item) + test_db.commit() + + response = test_client.get( + "/items/search?q=Networking", + headers={"Authorization": f"Bearer {user_token}"} + ) + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert len(data) >= 1 + + def test_search_items_partial_match(self, test_client, test_db, user_token): + """Test substring matching in search.""" + from backend.models import Item + + item = Item( + name="Power Supply 500W", + category="Power", + barcode="PSU-500W", + part_number="PSU-500", + quantity=5 + ) + test_db.add(item) + test_db.commit() + + response = test_client.get( + "/items/search?q=Power", + headers={"Authorization": f"Bearer {user_token}"} + ) + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert len(data) >= 1 + + def test_search_items_no_results(self, test_client, test_db, user_token): + """Test search with no matching results.""" + response = test_client.get( + "/items/search?q=NonexistentItemXYZ", + headers={"Authorization": f"Bearer {user_token}"} + ) + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert len(data) == 0 + + def test_search_items_empty_query(self, test_client, test_db, user_token): + """Test search with empty query returns empty list.""" + response = test_client.get( + "/items/search?q=", + headers={"Authorization": f"Bearer {user_token}"} + ) + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert len(data) == 0 + + def test_search_items_max_length_query(self, test_client, test_db, user_token): + """Test search with query exceeding max length returns empty.""" + long_query = "x" * 101 + response = test_client.get( + f"/items/search?q={long_query}", + headers={"Authorization": f"Bearer {user_token}"} + ) + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert len(data) == 0 + + def test_search_items_case_insensitive(self, test_client, test_db, user_token): + """Test that search is case-insensitive.""" + from backend.models import Item + + item = Item( + name="Transistor", + category="Electronics", + barcode="TRN-001", + part_number="TRN-2N2222", + quantity=75 + ) + test_db.add(item) + test_db.commit() + + response = test_client.get( + "/items/search?q=transistor", + headers={"Authorization": f"Bearer {user_token}"} + ) + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert len(data) >= 1 + + def test_search_items_relevance_ordering(self, test_client, test_db, user_token): + """Test that results are ordered by relevance (name match first).""" + from backend.models import Item + + # Create items where query matches different fields + item1 = Item( + name="Resistor", + category="Electronics", + barcode="RES-100", + part_number="R-100K", + quantity=100 + ) + item2 = Item( + name="Component", + category="Resistor Components", + barcode="RES-200", + part_number="R-200K", + quantity=50 + ) + test_db.add_all([item1, item2]) + test_db.commit() + + response = test_client.get( + "/items/search?q=Resistor", + headers={"Authorization": f"Bearer {user_token}"} + ) + assert response.status_code == status.HTTP_200_OK + data = response.json() + # Name match should be first + assert len(data) >= 1 + assert data[0]["name"] == "Resistor" + + def test_search_items_max_50_results(self, test_client, test_db, user_token): + """Test that search returns max 50 results.""" + from backend.models import Item + + # Create 60 items with same category + for i in range(60): + item = Item( + name=f"Item {i}", + category="Test", + barcode=f"TEST-{i}", + part_number=f"P-{i}", + quantity=i + ) + test_db.add(item) + test_db.commit() + + response = test_client.get( + "/items/search?q=Test", + headers={"Authorization": f"Bearer {user_token}"} + ) + assert response.status_code == status.HTTP_200_OK + data = response.json() + assert len(data) <= 50 + + class TestItemCRUD: """Test item creation, read, update, delete."""