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)
This commit is contained in:
parent
ef01a970d5
commit
ca3a08a236
3 changed files with 81 additions and 34 deletions
|
|
@ -769,6 +769,68 @@ class TestAdminCompleteTrade:
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
assert "not yet started" in response.json()["detail"]
|
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:
|
class TestAdminNoShowTrade:
|
||||||
"""Test admin marking trades as no-show."""
|
"""Test admin marking trades as no-show."""
|
||||||
|
|
|
||||||
|
|
@ -462,6 +462,7 @@ export default function ExchangePage() {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
key={dateStr}
|
key={dateStr}
|
||||||
|
data-testid={`date-${dateStr}`}
|
||||||
onClick={() => handleDateSelect(date)}
|
onClick={() => handleDateSelect(date)}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
style={{
|
style={{
|
||||||
|
|
|
||||||
|
|
@ -79,11 +79,17 @@ test.describe("Exchange Page - Regular User Access", () => {
|
||||||
test("clicking buy/sell changes direction", async ({ page }) => {
|
test("clicking buy/sell changes direction", async ({ page }) => {
|
||||||
await page.goto("/exchange");
|
await page.goto("/exchange");
|
||||||
|
|
||||||
// Click Sell BTC
|
// Initially in buy mode - summary shows BTC first: "You buy [sats], you sell €X"
|
||||||
|
// Verify buy mode is initially active
|
||||||
|
const buyButton = page.getByRole("button", { name: "Buy BTC" });
|
||||||
|
await expect(buyButton).toBeVisible();
|
||||||
|
|
||||||
|
// Click Sell BTC to switch direction
|
||||||
await page.getByRole("button", { name: "Sell BTC" }).click();
|
await page.getByRole("button", { name: "Sell BTC" }).click();
|
||||||
|
|
||||||
// The summary should mention "You send" for sell
|
// In sell mode, the summary shows EUR first: "You buy €X, you sell [sats]"
|
||||||
await expect(page.getByText(/You send/)).toBeVisible();
|
// We can verify by checking the summary text contains "You buy €" (EUR comes first)
|
||||||
|
await expect(page.getByText(/You buy €\d/)).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("exchange page shows date selection", async ({ page }) => {
|
test("exchange page shows date selection", async ({ page }) => {
|
||||||
|
|
@ -112,17 +118,9 @@ test.describe("Exchange Page - With Availability", () => {
|
||||||
test("shows available slots when availability is set", async ({ page }) => {
|
test("shows available slots when availability is set", async ({ page }) => {
|
||||||
await page.goto("/exchange");
|
await page.goto("/exchange");
|
||||||
|
|
||||||
// Get tomorrow's display name to click the correct button
|
// Use data-testid for reliable date selection
|
||||||
const tomorrow = new Date();
|
const tomorrowStr = getTomorrowDateStr();
|
||||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
const dateButton = page.getByTestId(`date-${tomorrowStr}`);
|
||||||
const weekday = tomorrow.toLocaleDateString("en-US", { weekday: "short" });
|
|
||||||
|
|
||||||
// Click tomorrow's date using the weekday name
|
|
||||||
// Wait for the button to be enabled (availability loading must complete)
|
|
||||||
const dateButton = page
|
|
||||||
.locator("button")
|
|
||||||
.filter({ hasText: new RegExp(`^${weekday}`) })
|
|
||||||
.first();
|
|
||||||
await expect(dateButton).toBeEnabled({ timeout: 15000 });
|
await expect(dateButton).toBeEnabled({ timeout: 15000 });
|
||||||
await dateButton.click();
|
await dateButton.click();
|
||||||
|
|
||||||
|
|
@ -140,16 +138,9 @@ test.describe("Exchange Page - With Availability", () => {
|
||||||
test("clicking slot shows confirmation form", async ({ page }) => {
|
test("clicking slot shows confirmation form", async ({ page }) => {
|
||||||
await page.goto("/exchange");
|
await page.goto("/exchange");
|
||||||
|
|
||||||
// Get tomorrow's display name
|
// Use data-testid for reliable date selection
|
||||||
const tomorrow = new Date();
|
const tomorrowStr = getTomorrowDateStr();
|
||||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
const dateButton = page.getByTestId(`date-${tomorrowStr}`);
|
||||||
const weekday = tomorrow.toLocaleDateString("en-US", { weekday: "short" });
|
|
||||||
|
|
||||||
// Click tomorrow's date - wait for button to be enabled first
|
|
||||||
const dateButton = page
|
|
||||||
.locator("button")
|
|
||||||
.filter({ hasText: new RegExp(`^${weekday}`) })
|
|
||||||
.first();
|
|
||||||
await expect(dateButton).toBeEnabled({ timeout: 15000 });
|
await expect(dateButton).toBeEnabled({ timeout: 15000 });
|
||||||
await dateButton.click();
|
await dateButton.click();
|
||||||
|
|
||||||
|
|
@ -169,16 +160,9 @@ test.describe("Exchange Page - With Availability", () => {
|
||||||
test("confirmation shows trade details", async ({ page }) => {
|
test("confirmation shows trade details", async ({ page }) => {
|
||||||
await page.goto("/exchange");
|
await page.goto("/exchange");
|
||||||
|
|
||||||
// Get tomorrow's display name
|
// Use data-testid for reliable date selection
|
||||||
const tomorrow = new Date();
|
const tomorrowStr = getTomorrowDateStr();
|
||||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
const dateButton = page.getByTestId(`date-${tomorrowStr}`);
|
||||||
const weekday = tomorrow.toLocaleDateString("en-US", { weekday: "short" });
|
|
||||||
|
|
||||||
// Click tomorrow's date - wait for button to be enabled first
|
|
||||||
const dateButton = page
|
|
||||||
.locator("button")
|
|
||||||
.filter({ hasText: new RegExp(`^${weekday}`) })
|
|
||||||
.first();
|
|
||||||
await expect(dateButton).toBeEnabled({ timeout: 15000 });
|
await expect(dateButton).toBeEnabled({ timeout: 15000 });
|
||||||
await dateButton.click();
|
await dateButton.click();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue