diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..7513c31 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,27 @@ +import os +import pytest + +os.environ["DATABASE_URL"] = "sqlite:///:memory:" + +from app import create_app, db as _db + + +@pytest.fixture() +def app(): + app = create_app() + app.config["TESTING"] = True + with app.app_context(): + _db.create_all() + yield app + _db.session.remove() + _db.drop_all() + + +@pytest.fixture() +def client(app): + return app.test_client() + + +@pytest.fixture() +def db(app): + return _db diff --git a/tests/test_health.py b/tests/test_health.py new file mode 100644 index 0000000..74d01d7 --- /dev/null +++ b/tests/test_health.py @@ -0,0 +1,4 @@ +def test_health(client): + resp = client.get("/health") + assert resp.status_code == 200 + assert resp.get_json() == {"status": "healthy"} diff --git a/tests/test_inventory.py b/tests/test_inventory.py new file mode 100644 index 0000000..fc4be91 --- /dev/null +++ b/tests/test_inventory.py @@ -0,0 +1,85 @@ +ITEM = {"sku": "SKU-001", "name": "Widget", "price": 9.99} + + +def _create(client, data=None): + return client.post("/api/inventory/", json=data or ITEM) + + +class TestCreateItem: + def test_success(self, client): + resp = _create(client) + assert resp.status_code == 201 + body = resp.get_json() + assert body["sku"] == ITEM["sku"] + assert body["name"] == ITEM["name"] + assert body["quantity"] == 0 + + def test_with_optional_fields(self, client): + resp = _create(client, {**ITEM, "quantity": 5, "category": "tools"}) + body = resp.get_json() + assert body["quantity"] == 5 + assert body["category"] == "tools" + + def test_missing_fields(self, client): + assert client.post("/api/inventory/", json={}).status_code == 400 + assert client.post("/api/inventory/", json={"sku": "X", "name": "Y"}).status_code == 400 + + def test_duplicate_sku(self, client): + _create(client) + assert _create(client).status_code == 409 + + +class TestListItems: + def test_empty(self, client): + assert client.get("/api/inventory/").get_json() == [] + + def test_returns_all(self, client): + _create(client, {"sku": "A", "name": "A", "price": 1}) + _create(client, {"sku": "B", "name": "B", "price": 2}) + assert len(client.get("/api/inventory/").get_json()) == 2 + + def test_filter_by_category(self, client): + _create(client, {"sku": "A", "name": "A", "price": 1, "category": "tools"}) + _create(client, {"sku": "B", "name": "B", "price": 2, "category": "parts"}) + _create(client, {"sku": "C", "name": "C", "price": 3, "category": "tools"}) + result = client.get("/api/inventory/?category=tools").get_json() + assert len(result) == 2 + assert all(i["category"] == "tools" for i in result) + + def test_filter_no_match(self, client): + _create(client) + assert client.get("/api/inventory/?category=nope").get_json() == [] + + +class TestGetItem: + def test_found(self, client): + iid = _create(client).get_json()["id"] + resp = client.get(f"/api/inventory/{iid}") + assert resp.status_code == 200 + assert resp.get_json()["sku"] == ITEM["sku"] + + def test_not_found(self, client): + assert client.get("/api/inventory/999").status_code == 404 + + +class TestUpdateItem: + def test_update_fields(self, client): + iid = _create(client).get_json()["id"] + resp = client.put(f"/api/inventory/{iid}", json={"quantity": 10, "price": 19.99}) + assert resp.status_code == 200 + body = resp.get_json() + assert body["quantity"] == 10 + assert body["price"] == "19.99" + + def test_not_found(self, client): + assert client.put("/api/inventory/999", json={"quantity": 1}).status_code == 404 + + +class TestDeleteItem: + def test_success(self, client): + iid = _create(client).get_json()["id"] + assert client.delete(f"/api/inventory/{iid}").status_code == 204 + assert client.get(f"/api/inventory/{iid}").status_code == 404 + + def test_not_found(self, client): + assert client.delete("/api/inventory/999").status_code == 404 diff --git a/tests/test_members.py b/tests/test_members.py new file mode 100644 index 0000000..c729e08 --- /dev/null +++ b/tests/test_members.py @@ -0,0 +1,76 @@ +import pytest + + +MEMBER = {"email": "a@b.com", "name": "Alice"} + + +def _create(client, data=None): + return client.post("/api/members/", json=data or MEMBER) + + +class TestCreateMember: + def test_success(self, client): + resp = _create(client) + assert resp.status_code == 201 + body = resp.get_json() + assert body["email"] == MEMBER["email"] + assert body["name"] == MEMBER["name"] + assert body["tier"] == "basic" + assert body["active"] is True + + def test_custom_tier(self, client): + resp = _create(client, {**MEMBER, "tier": "vip"}) + assert resp.get_json()["tier"] == "vip" + + def test_missing_fields(self, client): + assert client.post("/api/members/", json={}).status_code == 400 + assert client.post("/api/members/", json={"email": "x"}).status_code == 400 + assert client.post("/api/members/", json={"name": "x"}).status_code == 400 + + def test_duplicate_email(self, client): + _create(client) + assert _create(client).status_code == 409 + + +class TestListMembers: + def test_empty(self, client): + assert client.get("/api/members/").get_json() == [] + + def test_returns_all(self, client): + _create(client, {"email": "a@b.com", "name": "A"}) + _create(client, {"email": "b@b.com", "name": "B"}) + assert len(client.get("/api/members/").get_json()) == 2 + + +class TestGetMember: + def test_found(self, client): + mid = _create(client).get_json()["id"] + resp = client.get(f"/api/members/{mid}") + assert resp.status_code == 200 + assert resp.get_json()["email"] == MEMBER["email"] + + def test_not_found(self, client): + assert client.get("/api/members/999").status_code == 404 + + +class TestUpdateMember: + def test_update_fields(self, client): + mid = _create(client).get_json()["id"] + resp = client.put(f"/api/members/{mid}", json={"name": "Bob", "tier": "premium"}) + assert resp.status_code == 200 + body = resp.get_json() + assert body["name"] == "Bob" + assert body["tier"] == "premium" + + def test_not_found(self, client): + assert client.put("/api/members/999", json={"name": "X"}).status_code == 404 + + +class TestDeleteMember: + def test_success(self, client): + mid = _create(client).get_json()["id"] + assert client.delete(f"/api/members/{mid}").status_code == 204 + assert client.get(f"/api/members/{mid}").status_code == 404 + + def test_not_found(self, client): + assert client.delete("/api/members/999").status_code == 404 diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..ab8aa8f --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,57 @@ +from app.models.member import Member +from app.models.inventory import InventoryItem + + +class TestMemberModel: + def test_create_and_defaults(self, db, app): + m = Member(email="a@b.com", name="Alice") + db.session.add(m) + db.session.commit() + assert m.id is not None + assert m.tier == "basic" + assert m.active is True + assert m.created_at is not None + + def test_to_dict(self, db, app): + m = Member(email="a@b.com", name="Alice", tier="vip") + db.session.add(m) + db.session.commit() + d = m.to_dict() + assert d["email"] == "a@b.com" + assert d["tier"] == "vip" + assert "created_at" in d + + def test_unique_email(self, db, app): + import pytest + db.session.add(Member(email="dup@b.com", name="A")) + db.session.commit() + db.session.add(Member(email="dup@b.com", name="B")) + with pytest.raises(Exception): + db.session.commit() + + +class TestInventoryItemModel: + def test_create_and_defaults(self, db, app): + i = InventoryItem(sku="SKU-1", name="Widget", price=9.99) + db.session.add(i) + db.session.commit() + assert i.id is not None + assert i.quantity == 0 + assert i.created_at is not None + + def test_to_dict(self, db, app): + i = InventoryItem(sku="SKU-1", name="Widget", price=9.99, category="tools") + db.session.add(i) + db.session.commit() + d = i.to_dict() + assert d["sku"] == "SKU-1" + assert d["price"] == "9.99" + assert d["category"] == "tools" + + def test_unique_sku(self, db, app): + import pytest + db.session.add(InventoryItem(sku="DUP", name="A", price=1)) + db.session.commit() + db.session.add(InventoryItem(sku="DUP", name="B", price=2)) + with pytest.raises(Exception): + db.session.commit()