Coverage for app/backend/src/tests/test_email_localization.py: 100%
29 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-05-29 04:01 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-05-29 04:01 +0000
1"""
2Guardrail tests that every email fully renders in English.
4These emails build their localization keys at runtime (sometimes dynamically from internal
5state, e.g. a host request status), so a missing or mistyped key only blows up when that
6specific email is sent in production. Here we render every email -- and every variant of
7emails whose output depends on internal state -- and assert that no localization key is
8missing. See `EmailBase.dummy_variants`.
9"""
11import inspect
12from datetime import UTC
14import pytest
16import couchers.email.emails
17from couchers.email.emails import EmailBase
18from couchers.email.rendering import (
19 EmailFooter,
20 UnsubscribeInfo,
21 UnsubscribeLink,
22 render_html_body,
23 render_plaintext_body,
24)
25from couchers.i18n import LocalizationContext
28def _all_email_variants() -> list[tuple[str, EmailBase]]:
29 variants: list[tuple[str, EmailBase]] = []
30 for _, email_class in inspect.getmembers(
31 couchers.email.emails, lambda o: inspect.isclass(o) and o.__base__ == EmailBase
32 ):
33 instances = email_class.dummy_variants()
34 for i, instance in enumerate(instances):
35 variant_id = email_class.__name__ if len(instances) == 1 else f"{email_class.__name__}-{i}"
36 variants.append((variant_id, instance))
37 return variants
40_VARIANTS = _all_email_variants()
42_FOOTER = EmailFooter(
43 timezone_name="UTC",
44 unsubscribe_info=UnsubscribeInfo(
45 manage_notifications_url="https://example.com/manage-notifications",
46 do_not_email_url="https://example.com/do-not-email",
47 topic_action_link=UnsubscribeLink(text="topic-action", url="https://example.com/unsubscribe"),
48 ),
49)
52@pytest.fixture(autouse=True)
53def _(testconfig):
54 pass
57@pytest.mark.parametrize("email", [v for _, v in _VARIANTS], ids=[i for i, _ in _VARIANTS])
58def test_email_renders_in_english(email: EmailBase):
59 loc_context = LocalizationContext(locale="en", timezone=UTC)
61 subject = email.get_subject_line(loc_context)
62 assert subject
64 preview = email.get_preview_line(loc_context)
65 blocks = email.get_body_blocks(loc_context)
67 # Render both the html and plaintext bodies end-to-end, since each resolves its own keys.
68 render_html_body(subject=subject, preview=preview, blocks=blocks, footer=_FOOTER, loc_context=loc_context)
69 render_plaintext_body(blocks=blocks, footer=_FOOTER, loc_context=loc_context)