Coverage for app / backend / src / tests / test_templating.py: 93%
98 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-03 06:18 +0000
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-03 06:18 +0000
1# Tests jinja template rendering
3from datetime import date
4from typing import Any
5from zoneinfo import ZoneInfo
7from markupsafe import Markup
9from couchers.i18n import LocalizationContext
10from couchers.i18n.i18next import I18Next
11from couchers.i18n.plurals import PluralRules
12from couchers.templating import Jinja2Template
15def _render_en_utc(template: Jinja2Template, args: dict[str, Any]) -> str:
16 return template.render(args, LocalizationContext.en_utc(), i18next=I18Next())
19def test_multiline() -> None:
20 template = Jinja2Template(source="{{ text|multiline }}", html=False)
21 rendered = _render_en_utc(template, {"text": "a\nb"})
22 assert rendered == "a\nb"
24 template = Jinja2Template(source="{{ text|multiline }}", html=True)
25 rendered = _render_en_utc(template, {"text": "a\nb"})
26 assert rendered == "a<br>b"
29def test_quotelines() -> None:
30 template = Jinja2Template(source="{{ text|quotelines }}", html=False)
31 rendered = _render_en_utc(template, {"text": "a\nb"})
32 assert rendered == "> a\n> b"
35def test_html_escaping() -> None:
36 template = Jinja2Template(source="Hello {{ name }}!", html=True)
37 rendered = _render_en_utc(template, {"name": "<script />"})
38 assert rendered == "Hello <script />!"
41def test_safe_html() -> None:
42 template = Jinja2Template(source="Hello {{ name|html }}!", html=True)
43 rendered = _render_en_utc(template, {"name": "<script />"})
44 assert rendered == "Hello <script />!"
47def test_date_formatting() -> None:
48 the_date = date(1970, 1, 1)
49 template = Jinja2Template(source="Date: {{ date }}", html=False)
50 rendered = _render_en_utc(template, {"date": the_date})
51 assert rendered == "Date: Thursday 1 January 1970"
54def _greeting_i18next(value: str) -> I18Next:
55 i18next = I18Next()
56 language = i18next.add_language("en", PluralRules.en)
57 language.add_string("greeting", value)
58 return i18next
61def _i18next_from_dict(value: dict[str, dict[str, str]]) -> I18Next:
62 i18next = I18Next()
63 for lang_code, strings in value.items():
64 language = i18next.add_language(lang_code, PluralRules.en)
65 language.load_json_dict(strings)
66 return i18next
69def test_translate_no_substitutions() -> None:
70 template = Jinja2Template(source='{{ "greeting"|translate }}', html=False)
71 i18next = _greeting_i18next("Hello!")
72 rendered = template.render({}, LocalizationContext.en_utc(), i18next)
73 assert rendered == "Hello!"
76def test_translate_multiple_languages() -> None:
77 template = Jinja2Template(source='{{ "greeting"|translate }}', html=False)
78 i18next = I18Next()
79 i18next.add_language("en", PluralRules.en).add_string("greeting", "Hello!")
80 i18next.add_language("fr", PluralRules.en).add_string("greeting", "Bonjour!")
81 fr_loc_context = LocalizationContext(locale="fr", timezone=ZoneInfo("Etc/UTC"))
82 rendered = template.render({}, fr_loc_context, i18next)
83 assert rendered == "Bonjour!"
86def test_translate_with_substitutions() -> None:
87 template = Jinja2Template(source='{{ "greeting"|translate(name=user_name) }}', html=False)
88 i18next = _greeting_i18next("Hello, {{name}}!")
89 rendered = template.render({"user_name": "Jack"}, LocalizationContext.en_utc(), i18next)
90 assert rendered == "Hello, Jack!"
93def test_translate_substitution_escaping() -> None:
94 template = Jinja2Template(source='{{ "greeting"|translate(name=name) }}', html=True)
95 i18next = _greeting_i18next("Hello, {{name}}!")
96 rendered = template.render({"name": "<script />"}, LocalizationContext.en_utc(), i18next)
97 assert rendered == "Hello, <script />!"
100def test_translate_substitution_safe_html() -> None:
101 template = Jinja2Template(source='{{ "greeting"|translate(name=name) }}', html=True)
102 i18next = _greeting_i18next("Hello, {{name}}!")
103 rendered = template.render({"name": Markup("<script />")}, LocalizationContext.en_utc(), i18next)
104 assert rendered == "Hello, <script />!"
107def test_translate_translation_tags() -> None:
108 template = Jinja2Template(source='{{ "greeting"|translate }}', html=True)
109 i18next = _greeting_i18next("<b>Hello!</b>")
110 rendered = template.render({}, LocalizationContext.en_utc(), i18next)
111 assert rendered == "<b>Hello!</b>"
114def test_translate_newlines_br() -> None:
115 template = Jinja2Template(source='{{ "greeting"|translate }}', html=True)
116 i18next = _greeting_i18next("Hello!\nWelcome!")
117 rendered = template.render({}, LocalizationContext.en_utc(), i18next)
118 assert rendered == "Hello!<br>Welcome!"
121def test_translate_plain_strip_tags() -> None:
122 template = Jinja2Template(source='{{ "greeting"|translate }}', html=False)
123 i18next = _greeting_i18next("<b>Hello!</b>")
124 rendered = template.render({}, LocalizationContext.en_utc(), i18next)
125 assert rendered == "Hello!"
128def test_translate_plain_strip_links() -> None:
129 template = Jinja2Template(source='{{ "greeting"|translate }}', html=False)
130 i18next = _greeting_i18next('<a href="https://example.com">Hello!</a>')
131 rendered = template.render({}, LocalizationContext.en_utc(), i18next)
132 assert rendered == "<https://example.com>"
135def test_translate_plain_strip_mailto() -> None:
136 template = Jinja2Template(source='{{ "greeting"|translate }}', html=False)
137 i18next = _greeting_i18next('<a href="mailto:me@example.com">Hello!</a>')
138 rendered = template.render({}, LocalizationContext.en_utc(), i18next)
139 assert rendered == "<me@example.com>"