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>
This commit is contained in:
parent
9c88993c13
commit
7a4b3022c2
14 changed files with 3710 additions and 0 deletions
66
tests/test_smoke.py
Normal file
66
tests/test_smoke.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
"""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}"
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue