From ca3a08a2360299ff0b59bea18c03ba1f1948f986 Mon Sep 17 00:00:00 2001 From: counterweight Date: Tue, 23 Dec 2025 11:00:32 +0100 Subject: [PATCH] test: improve e2e tests and add COMPLETE_EXCHANGE permission tests - Fix E2E test assertion for buy/sell direction change - Add data-testid to date buttons for reliable e2e selection - Update e2e tests to use data-testid instead of fragile weekday matching - Add tests for regular user cannot complete/no-show trades (COMPLETE_EXCHANGE permission) --- backend/tests/test_exchange.py | 62 ++++++++++++++++++++++++++++++++++ frontend/app/exchange/page.tsx | 1 + frontend/e2e/exchange.spec.ts | 52 ++++++++++------------------ 3 files changed, 81 insertions(+), 34 deletions(-) diff --git a/backend/tests/test_exchange.py b/backend/tests/test_exchange.py index 9799bff..5b0a019 100644 --- a/backend/tests/test_exchange.py +++ b/backend/tests/test_exchange.py @@ -769,6 +769,68 @@ class TestAdminCompleteTrade: assert response.status_code == 400 assert "not yet started" in response.json()["detail"] + @pytest.mark.asyncio + async def test_regular_user_cannot_complete_trade( + self, client_factory, regular_user, admin_user + ): + """Regular user cannot complete trades (requires COMPLETE_EXCHANGE permission).""" + # Create a past trade in DB + async with client_factory.get_db_session() as db: + past_time = datetime.now(UTC) - timedelta(hours=1) + exchange = Exchange( + user_id=regular_user["user"]["id"], + slot_start=past_time, + slot_end=past_time + timedelta(minutes=15), + direction=TradeDirection.BUY, + eur_amount=10000, + sats_amount=500000, + market_price_eur=20000.0, + agreed_price_eur=21000.0, + premium_percentage=5, + status=ExchangeStatus.BOOKED, + ) + db.add(exchange) + await db.commit() + await db.refresh(exchange) + trade_id = exchange.id + + # Regular user tries to complete + async with client_factory.create(cookies=regular_user["cookies"]) as client: + response = await client.post(f"/api/admin/trades/{trade_id}/complete") + + assert response.status_code == 403 + + @pytest.mark.asyncio + async def test_regular_user_cannot_mark_no_show( + self, client_factory, regular_user, admin_user + ): + """Regular user cannot mark trades as no-show (requires COMPLETE_EXCHANGE permission).""" + # Create a past trade in DB + async with client_factory.get_db_session() as db: + past_time = datetime.now(UTC) - timedelta(hours=1) + exchange = Exchange( + user_id=regular_user["user"]["id"], + slot_start=past_time, + slot_end=past_time + timedelta(minutes=15), + direction=TradeDirection.BUY, + eur_amount=10000, + sats_amount=500000, + market_price_eur=20000.0, + agreed_price_eur=21000.0, + premium_percentage=5, + status=ExchangeStatus.BOOKED, + ) + db.add(exchange) + await db.commit() + await db.refresh(exchange) + trade_id = exchange.id + + # Regular user tries to mark as no-show + async with client_factory.create(cookies=regular_user["cookies"]) as client: + response = await client.post(f"/api/admin/trades/{trade_id}/no-show") + + assert response.status_code == 403 + class TestAdminNoShowTrade: """Test admin marking trades as no-show.""" diff --git a/frontend/app/exchange/page.tsx b/frontend/app/exchange/page.tsx index f93e938..047644d 100644 --- a/frontend/app/exchange/page.tsx +++ b/frontend/app/exchange/page.tsx @@ -462,6 +462,7 @@ export default function ExchangePage() { return (