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>
66 lines
2.8 KiB
Python
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}"
|
|
)
|