Coverage for app / backend / src / tests / test_templating.py: 93%
96 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-05 09:44 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-05 09:44 +0000
1# Tests jinja template rendering
3from datetime import UTC, date
4from typing import Any
6from markupsafe import Markup
8from couchers.i18n import LocalizationContext
9from couchers.i18n.i18next import I18Next
10from couchers.templating import Jinja2Template
13def _render_en_utc(template: Jinja2Template, args: dict[str, Any]) -> str:
14 return template.render(args, LocalizationContext.en_utc(), i18next=I18Next())
17def test_multiline() -> None:
18 template = Jinja2Template(source="{{ text|multiline }}", html=False)
19 rendered = _render_en_utc(template, {"text": "a\nb"})
20 assert rendered == "a\nb"
22 template = Jinja2Template(source="{{ text|multiline }}", html=True)
23 rendered = _render_en_utc(template, {"text": "a\nb"})
24 assert rendered == "a<br>b"
27def test_quotelines() -> None:
28 template = Jinja2Template(source="{{ text|quotelines }}", html=False)
29 rendered = _render_en_utc(template, {"text": "a\nb"})
30 assert rendered == "> a\n> b"
33def test_html_escaping() -> None:
34 template = Jinja2Template(source="Hello {{ name }}!", html=True)
35 rendered = _render_en_utc(template, {"name": "<script />"})
36 assert rendered == "Hello <script />!"
39def test_safe_html() -> None:
40 template = Jinja2Template(source="Hello {{ name|html }}!", html=True)
41 rendered = _render_en_utc(template, {"name": "<script />"})
42 assert rendered == "Hello <script />!"
45def test_date_formatting() -> None:
46 the_date = date(1970, 1, 1)
47 template = Jinja2Template(source="Date: {{ date }}", html=False)
48 rendered = _render_en_utc(template, {"date": the_date})
49 assert rendered == "Date: Jan 1, 1970"
52def _greeting_i18next(value: str) -> I18Next:
53 i18next = I18Next()
54 language = i18next.add_translation("en")
55 language.add_string("greeting", value)
56 return i18next
59def _i18next_from_dict(value: dict[str, dict[str, str]]) -> I18Next:
60 i18next = I18Next()
61 for lang_code, strings in value.items():
62 language = i18next.add_translation(lang_code)
63 language.load_json_dict(strings)
64 return i18next
67def test_translate_no_substitutions() -> None:
68 template = Jinja2Template(source='{{ "greeting"|translate }}', html=False)
69 i18next = _greeting_i18next("Hello!")
70 rendered = template.render({}, LocalizationContext.en_utc(), i18next)
71 assert rendered == "Hello!"
74def test_translate_multiple_languages() -> None:
75 template = Jinja2Template(source='{{ "greeting"|translate }}', html=False)
76 i18next = I18Next()
77 i18next.add_translation("en").add_string("greeting", "Hello!")
78 i18next.add_translation("fr").add_string("greeting", "Bonjour!")
79 fr_loc_context = LocalizationContext(locale="fr", timezone=UTC)
80 rendered = template.render({}, fr_loc_context, i18next)
81 assert rendered == "Bonjour!"
84def test_translate_with_substitutions() -> None:
85 template = Jinja2Template(source='{{ "greeting"|translate(name=user_name) }}', html=False)
86 i18next = _greeting_i18next("Hello, {{name}}!")
87 rendered = template.render({"user_name": "Jack"}, LocalizationContext.en_utc(), i18next)
88 assert rendered == "Hello, Jack!"
91def test_translate_substitution_escaping() -> None:
92 template = Jinja2Template(source='{{ "greeting"|translate(name=name) }}', html=True)
93 i18next = _greeting_i18next("Hello, {{name}}!")
94 rendered = template.render({"name": "<script />"}, LocalizationContext.en_utc(), i18next)
95 assert rendered == "Hello, <script />!"
98def test_translate_substitution_safe_html() -> None:
99 template = Jinja2Template(source='{{ "greeting"|translate(name=name) }}', html=True)
100 i18next = _greeting_i18next("Hello, {{name}}!")
101 rendered = template.render({"name": Markup("<script />")}, LocalizationContext.en_utc(), i18next)
102 assert rendered == "Hello, <script />!"
105def test_translate_translation_tags() -> None:
106 template = Jinja2Template(source='{{ "greeting"|translate }}', html=True)
107 i18next = _greeting_i18next("<b>Hello!</b>")
108 rendered = template.render({}, LocalizationContext.en_utc(), i18next)
109 assert rendered == "<b>Hello!</b>"
112def test_translate_newlines_br() -> None:
113 template = Jinja2Template(source='{{ "greeting"|translate }}', html=True)
114 i18next = _greeting_i18next("Hello!\nWelcome!")
115 rendered = template.render({}, LocalizationContext.en_utc(), i18next)
116 assert rendered == "Hello!<br>Welcome!"
119def test_translate_plain_strip_tags() -> None:
120 template = Jinja2Template(source='{{ "greeting"|translate }}', html=False)
121 i18next = _greeting_i18next("<b>Hello!</b>")
122 rendered = template.render({}, LocalizationContext.en_utc(), i18next)
123 assert rendered == "Hello!"
126def test_translate_plain_strip_links() -> None:
127 template = Jinja2Template(source='{{ "greeting"|translate }}', html=False)
128 i18next = _greeting_i18next('<a href="https://example.com">Hello!</a>')
129 rendered = template.render({}, LocalizationContext.en_utc(), i18next)
130 assert rendered == "<https://example.com>"
133def test_translate_plain_strip_mailto() -> None:
134 template = Jinja2Template(source='{{ "greeting"|translate }}', html=False)
135 i18next = _greeting_i18next('<a href="mailto:me@example.com">Hello!</a>')
136 rendered = template.render({}, LocalizationContext.en_utc(), i18next)
137 assert rendered == "<me@example.com>"