import sys import types from services import brief_service from services.brief_service import brief_repository def _install_fake_resend(monkeypatch): fake = types.ModuleType('resend') fake.api_key = None calls = [] class _Emails: @staticmethod def send(payload): calls.append(payload) fake.Emails = _Emails monkeypatch.setitem(sys.modules, 'resend', fake) return calls def test_send_weekly_brief_renders_and_sends(monkeypatch): # MockBriefRepository keeps its own in-memory tenant store, seeded # explicitly (it isn't wired to tenant_repository's mock store). brief_repository.seed_tenant('t1', {'email': 'pm@gadventures.com', 'name': 'G Adventures'}) calls = _install_fake_resend(monkeypatch) brief_service.send_weekly_brief('t1') assert len(calls) == 1 assert calls[0]['to'] == 'pm@gadventures.com' assert 'Bettersight' in calls[0]['html'] assert list(brief_repository._logs.values())[-1]['status'] == 'sent' def test_send_weekly_brief_skips_when_no_admin_email(monkeypatch): calls = _install_fake_resend(monkeypatch) # 'unknown-tenant' was never seeded — get_weekly_data returns admin_email=None. brief_service.send_weekly_brief('unknown-tenant') assert calls == [] def test_send_weekly_brief_logs_failure_when_resend_raises(monkeypatch): brief_repository.seed_tenant('t2', {'email': 'pm@gadventures.com', 'name': 'G Adventures'}) def _raise(payload): raise RuntimeError('resend api down') fake = types.ModuleType('resend') fake.api_key = None fake.Emails = type('Emails', (), {'send': staticmethod(_raise)}) monkeypatch.setitem(sys.modules, 'resend', fake) # Must not raise — a failed send is a side-effect failure only. brief_service.send_weekly_brief('t2') assert list(brief_repository._logs.values())[-1]['status'] == 'failed'