59 lines
3.0 KiB
Python
59 lines
3.0 KiB
Python
"""Operator feedback distinguishes read failures and partially committed saves."""
|
|
import pytest
|
|
from streamlit.testing.v1 import AppTest
|
|
|
|
from jarca_ledger_mcp import service as s
|
|
from jarca_ledger_mcp.adapters.streamlit import settlement_gateway
|
|
from jarca_ledger_mcp.db import init_db
|
|
|
|
|
|
def panel(monkeypatch, path):
|
|
monkeypatch.setenv('JARCA_LEDGER_DB_PATH', str(path))
|
|
app = AppTest.from_string('from dashboard.page_views.settlement_drafts import render_settlement_drafts\nrender_settlement_drafts()\n').run(timeout=20)
|
|
assert not app.exception
|
|
return app
|
|
|
|
|
|
def control(elements, label):
|
|
return next(element for element in elements if element.label == label)
|
|
|
|
|
|
def test_panel_shows_safe_error_when_draft_listing_fails(tmp_path, monkeypatch):
|
|
path = tmp_path / 'missing.sqlite3'
|
|
monkeypatch.setattr(settlement_gateway, 'list_settlement_drafts', lambda *args, **kwargs: {
|
|
'success': False, 'error_code': 'storage_error', 'message': 'SYNTHETIC_PRIVATE_DIAGNOSTIC',
|
|
})
|
|
app = panel(monkeypatch, path)
|
|
assert app.error and 'storage_error' in ' '.join(element.value for element in app.error)
|
|
assert not any('초안이 없습니다' in element.value for element in app.info)
|
|
visible = ' '.join(element.value for elements in (app.error, app.info, app.caption) for element in elements)
|
|
assert 'SYNTHETIC_PRIVATE_DIAGNOSTIC' not in visible
|
|
assert not path.exists()
|
|
|
|
|
|
def test_panel_reports_partial_save_when_item_update_fails(tmp_path, monkeypatch):
|
|
path = str(tmp_path / 'partial.sqlite3')
|
|
init_db(path)
|
|
account = s.create_ledger_account('Synthetic cash', db_path=path)['account']['id']
|
|
assert s.register_account_valuation(account, '2026-09-30', 10, verification_status='verified',
|
|
idempotency_key='synthetic-value', db_path=path)['success']
|
|
app = panel(monkeypatch, path)
|
|
control(app.button, '초안 생성 / 정정 초안').click().run(timeout=20)
|
|
control(app.button, '검토 / 새로고침 대상').click().run(timeout=20)
|
|
draft = s.list_settlement_drafts('2026-09', db_path=path)['drafts'][0]
|
|
review_key = f"review_result_{draft['id']}"
|
|
assert app.session_state[review_key]['success']
|
|
control(app.text_input, '초안 메모 저장').set_value('Synthetic persisted memo')
|
|
control(app.text_input, '대상 ID').set_value('synthetic-nonexistent-target')
|
|
control(app.button, '저장 / 지정 / 포함·제외').click().run(timeout=20)
|
|
assert not app.exception
|
|
current = s.get_settlement_draft(draft['id'], db_path=path)
|
|
assert current['draft']['memo'] == 'Synthetic persisted memo'
|
|
assert current['draft']['version'] == draft['version'] + 1
|
|
assert len(current['items']) == 1 and current['items'][0]['source_id'] == account
|
|
assert app.error
|
|
assert any('메모는 저장되었지만 항목 변경은 실패했습니다' in element.value for element in app.warning)
|
|
with pytest.raises(KeyError):
|
|
app.session_state[review_key]
|
|
assert not any(element.label in {'검토 결과 승인', '최종 마감'} for element in app.button)
|