libra/tests/test_smoke.py
Padreug 7a4b3022c2 Add integration test suite
113 passing tests + 3 skipped + 8 xfailed across 10 files, covering user
expense and income flow, admin receivable/revenue, settings + auth gates,
void/reject, manual payment requests, balance display, Lightning auth
paths, reconciliation API, and pure-function units. Runs against a real
Fava subprocess and full LNbits app via asgi_lifespan; the harness
captures the auth-flow / settings / env-var disciplines surfaced during
build-out (see tests/README.md and tests/conftest.py docstring).

Eight xfailed/skipped tests carry full implementations gated behind issues
#38, #39, #40 — they flip back on automatically when those land.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-07 15:39:45 +02:00

66 lines
2.8 KiB
Python

"""Smoke test: validates the test harness end-to-end.
If this passes, the rest of the test files can be trusted to actually exercise
real code paths (Fava up, app up, Libra activated, FavaClient pointed at the
test instance, BQL round-trips working, libra wallet configured, user wallet
configured, account exists, permission granted).
If this fails, no point running anything else — fix the harness first.
"""
import pytest
from .helpers import approve_entry, get_balance, post_expense
@pytest.mark.anyio
async def test_smoke_submit_approve_and_see_balance(
client, super_user_headers, configured_user, standard_accounts,
):
"""Full stack round-trip: user submits an expense, admin approves it,
balance reflects it.
Exercises: libra wallet config (session fixture), user wallet config
(configured_user fixture), permission grant (configured_user fixture),
Beancount entry construction, Fava add_entries HTTP call, pending→cleared
flag transition via the source-slice mutation path, BQL balance query
(which filters by flag = '*' so the approve step is load-bearing).
"""
_, wallet = configured_user
# User pays 50 EUR for groceries — entry posted with flag `!` (pending).
entry = await post_expense(
client,
wallet_inkey=wallet.inkey,
user_wallet_id=wallet.id,
amount="50.00",
currency="EUR",
description="Smoke test expense",
expense_account=standard_accounts["expense_food"]["name"],
)
entry_id = entry.get("id")
assert entry_id, f"expense response missing id: {entry}"
# Pending entries are excluded from the cleared-only balance query —
# confirm balance is still zero at this point.
pending_balance = await get_balance(client, wallet_inkey=wallet.inkey)
pending_eur = pending_balance.get("fiat_balances", {}).get("EUR")
assert pending_eur in (None, 0, "0", "0.00"), (
f"pending expense should not affect cleared balance, got {pending_eur}"
)
# Admin approves the pending entry, flipping its flag from `!` to `*`.
await approve_entry(
client, super_user_headers=super_user_headers, entry_id=entry_id,
)
# Balance now reflects the 50 EUR Libra owes the user.
# Sign convention (per get_user_balance_bql docstring): the API returns
# the balance from libra's perspective — negative on Liabilities:Payable
# means libra owes the user. So a 50 EUR expense surfaces as -50 EUR.
balance = await get_balance(client, wallet_inkey=wallet.inkey)
fiat = balance.get("fiat_balances", {})
eur = fiat.get("EUR")
assert eur is not None, f"expected EUR in fiat_balances after approve, got {balance}"
assert float(eur) == pytest.approx(-50.0), (
f"expected EUR balance of -50.00 (libra-owes-user) after approve, got {eur}"
)