Files
badoHair_be/tests/test_orders.py

123 lines
4.1 KiB
Python

"""Order creation, stock deduction, and webhook handling."""
from unittest.mock import AsyncMock
from tests.conftest import PRODUCT_ID, ORDER_ID
SAMPLE_PRODUCT_ROW = {
"id": PRODUCT_ID,
"name": "Extensions Clip-In Luxe",
"price": 189.0,
"stock_quantity": 10,
}
SAMPLE_ORDER_ROW = {
"id": ORDER_ID,
"user_id": "11111111-1111-1111-1111-111111111111",
"status": "pending",
"total_amount": 189.0,
"stripe_payment_intent_id": "pi_test123",
"shipping_address": None,
"notes": None,
"created_at": "2026-01-01T00:00:00",
"updated_at": "2026-01-01T00:00:00",
}
async def test_create_order_success(auth_client, mock_db):
mock_db.fetchrow = AsyncMock(side_effect=[
SAMPLE_PRODUCT_ROW, # product lookup
{"id": ORDER_ID, **SAMPLE_ORDER_ROW}, # INSERT order RETURNING *
])
mock_db.execute = AsyncMock(return_value="UPDATE 1")
r = await auth_client.post("/api/v1/orders", json={
"items": [{"product_id": PRODUCT_ID, "quantity": 1}],
})
assert r.status_code == 201
body = r.json()
assert body["success"] is True
assert "order_id" in body["data"]
assert body["data"]["amount"] == 189.0
async def test_create_order_requires_auth(anon_client):
r = await anon_client.post("/api/v1/orders", json={
"items": [{"product_id": PRODUCT_ID, "quantity": 1}],
})
assert r.status_code == 401
async def test_create_order_empty_items_rejected(auth_client):
r = await auth_client.post("/api/v1/orders", json={"items": []})
assert r.status_code == 422
async def test_create_order_product_not_found(auth_client, mock_db):
mock_db.fetchrow = AsyncMock(return_value=None)
r = await auth_client.post("/api/v1/orders", json={
"items": [{"product_id": "00000000-0000-0000-0000-000000000000", "quantity": 1}],
})
assert r.status_code == 404
assert r.json()["error"]["code"] == "PRODUCT_NOT_FOUND"
async def test_create_order_out_of_stock(auth_client, mock_db):
low_stock = {**SAMPLE_PRODUCT_ROW, "stock_quantity": 0}
mock_db.fetchrow = AsyncMock(return_value=low_stock)
r = await auth_client.post("/api/v1/orders", json={
"items": [{"product_id": PRODUCT_ID, "quantity": 1}],
})
assert r.status_code == 409
assert r.json()["error"]["code"] == "OUT_OF_STOCK"
async def test_list_my_orders(auth_client, mock_db):
mock_db.fetchval = AsyncMock(return_value=1)
mock_db.fetch = AsyncMock(return_value=[SAMPLE_ORDER_ROW])
r = await auth_client.get("/api/v1/orders")
assert r.status_code == 200
body = r.json()
assert body["meta"]["total"] == 1
async def test_get_order_by_id(auth_client, mock_db):
mock_db.fetchrow = AsyncMock(return_value=SAMPLE_ORDER_ROW)
mock_db.fetch = AsyncMock(return_value=[]) # order items
r = await auth_client.get(f"/api/v1/orders/{ORDER_ID}")
assert r.status_code == 200
async def test_get_order_not_found(auth_client, mock_db):
mock_db.fetchrow = AsyncMock(return_value=None)
r = await auth_client.get(f"/api/v1/orders/00000000-0000-0000-0000-000000000000")
assert r.status_code == 404
# ── Admin order management ────────────────────────────────────────────────────
async def test_admin_list_orders(admin_client, mock_db):
mock_db.fetchval = AsyncMock(return_value=1)
mock_db.fetch = AsyncMock(return_value=[SAMPLE_ORDER_ROW])
r = await admin_client.get("/api/v1/admin/orders")
assert r.status_code == 200
async def test_admin_update_order_status(admin_client, mock_db):
updated = {**SAMPLE_ORDER_ROW, "status": "shipped"}
mock_db.fetchrow = AsyncMock(return_value=updated)
mock_db.execute = AsyncMock(return_value="INSERT 1")
r = await admin_client.patch(f"/api/v1/admin/orders/{ORDER_ID}/status", json={"status": "shipped"})
assert r.status_code == 200
assert r.json()["data"]["status"] == "shipped"
async def test_admin_update_order_invalid_status(admin_client):
r = await admin_client.patch(f"/api/v1/admin/orders/{ORDER_ID}/status", json={"status": "exploded"})
assert r.status_code == 422