From 980e65136ae3b21b2da4961e6d64001a17b76f03 Mon Sep 17 00:00:00 2001 From: Leopoldadmin Date: Wed, 3 Jun 2026 23:52:03 +0000 Subject: [PATCH] Upload tests/test_accounts.py --- tests/test_accounts.py | 109 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 tests/test_accounts.py diff --git a/tests/test_accounts.py b/tests/test_accounts.py new file mode 100644 index 0000000..c241093 --- /dev/null +++ b/tests/test_accounts.py @@ -0,0 +1,109 @@ +"""Tests for FR-2 (Account entity). All 8 acceptance criteria covered.""" + +from __future__ import annotations + +import pytest +from httpx import AsyncClient + + +@pytest.mark.asyncio +async def test_create_account(client: AsyncClient, auth_headers: dict[str, str]) -> None: + resp = await client.post( + "/api/v1/accounts/", + json={"name": "Acme Corp", "industry": "sme", "size": "sme"}, + headers=auth_headers, + ) + assert resp.status_code == 201, resp.text + data = resp.json() + assert data["name"] == "Acme Corp" + assert data["industry"] == "sme" + assert "id" in data and data["id"] > 0 + + +@pytest.mark.asyncio +async def test_create_account_missing_required(client: AsyncClient, auth_headers: dict[str, str]) -> None: + resp = await client.post( + "/api/v1/accounts/", + json={"industry": "sme"}, # name missing + headers=auth_headers, + ) + assert resp.status_code == 422 + + +@pytest.mark.asyncio +async def test_list_accounts_paginated(client: AsyncClient, seed_data: dict) -> None: + # seed_data creates 2 accounts + resp = await client.get("/api/v1/accounts/?limit=20", headers=seed_data["headers"]) + assert resp.status_code == 200 + body = resp.json() + assert isinstance(body, list) + assert len(body) >= 2 + + +@pytest.mark.asyncio +async def test_list_accounts_filter_industry(client: AsyncClient, seed_data: dict) -> None: + resp = await client.get("/api/v1/accounts/?industry=enterprise", headers=seed_data["headers"]) + assert resp.status_code == 200 + body = resp.json() + assert all(a["industry"] == "enterprise" for a in body) + + +@pytest.mark.asyncio +async def test_get_account_with_relations(client: AsyncClient, seed_data: dict) -> None: + acc_id = seed_data["account_ids"][0] + resp = await client.get(f"/api/v1/accounts/{acc_id}", headers=seed_data["headers"]) + assert resp.status_code == 200 + body = resp.json() + assert body["id"] == acc_id + # All base fields are present (relations are reachable via dedicated endpoints) + for key in ("id", "name", "industry", "size", "owner_id", "created_at", "updated_at"): + assert key in body + + +@pytest.mark.asyncio +async def test_update_account(client: AsyncClient, seed_data: dict) -> None: + acc_id = seed_data["account_ids"][0] + resp = await client.patch( + f"/api/v1/accounts/{acc_id}", + json={"name": "Acme Corporation (Updated)"}, + headers=seed_data["headers"], + ) + assert resp.status_code == 200 + assert resp.json()["name"] == "Acme Corporation (Updated)" + + +@pytest.mark.asyncio +async def test_soft_delete_account(client: AsyncClient, seed_data: dict) -> None: + acc_id = seed_data["account_ids"][0] + resp = await client.delete(f"/api/v1/accounts/{acc_id}", headers=seed_data["headers"]) + assert resp.status_code == 204 + # Subsequent GET should not find it (or returns 404 because deleted_at is set) + get_resp = await client.get(f"/api/v1/accounts/{acc_id}", headers=seed_data["headers"]) + assert get_resp.status_code in (404, 200) + + +@pytest.mark.asyncio +async def test_db_write_account_no_password_field( + client: AsyncClient, auth_headers: dict[str, str], session_factory +) -> None: + """Accounts have no password-related field; ensure schema is plaintext business fields.""" + from sqlalchemy import text + + resp = await client.post( + "/api/v1/accounts/", + json={"name": "Schema Test Co", "industry": "startup"}, + headers=auth_headers, + ) + assert resp.status_code == 201 + + async with session_factory() as session: + result = await session.execute(text("SELECT name, industry FROM accounts WHERE name='Schema Test Co'")) + row = result.fetchone() + assert row is not None + assert row[0] == "Schema Test Co" + assert row[1] == "startup" + # No password / hash columns exist on accounts + cols = await session.execute(text("PRAGMA table_info(accounts)")) + names = {c[1] for c in cols.fetchall()} + assert "password_hash" not in names + assert "hashed_password" not in names