From d8409535af8f9e9944c63c73f33bc7cc9577ccfb Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 21 Aug 2024 09:51:15 +0200 Subject: Adding upstream version 0.45+dfsg. Signed-off-by: Daniel Baumann --- tests/test_render.py | 992 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 992 insertions(+) create mode 100644 tests/test_render.py (limited to 'tests/test_render.py') diff --git a/tests/test_render.py b/tests/test_render.py new file mode 100644 index 0000000..1e52cda --- /dev/null +++ b/tests/test_render.py @@ -0,0 +1,992 @@ +import time +from pathlib import Path +from textwrap import dedent + +import jinja2 +import pytest +from jinja2.exceptions import TemplateSyntaxError +from markupsafe import Markup + +import jinjax + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_render_simple(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Greeting.jinja").write_text( + """ +{#def message #} +
{{ message }}
+ """ + ) + html = catalog.render("Greeting", message="Hello world!") + assert html == Markup('
Hello world!
') + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_render_source(catalog, autoescape): + catalog.jinja_env.autoescape = autoescape + + source = '{#def message #}\n
{{ message }}
' + expected = Markup('
Hello world!
') + + html = catalog.render("Greeting", message="Hello world!", _source=source) + assert expected == html + + # Legacy + html = catalog.render("Greeting", message="Hello world!", __source=source) + assert expected == html + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_render_content(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Card.jinja").write_text(""" +
+{{ content }} +
+ """) + + content = '' + expected = Markup(f'
\n{content}\n
') + + html = catalog.render("Card", _content=content) + print(html) + assert expected == html + + # Legacy + html = catalog.render("Card", __content=content) + assert expected == html + + +@pytest.mark.parametrize("autoescape", [True, False]) +@pytest.mark.parametrize( + "source, expected", + [ + ("HiHi", "

Hi

Hi

"), + ("", ''), + ("Hi", '

Hi

'), + ("Hi", '

Hi

'), + ], +) +def test_render_mix_of_contentful_and_contentless_components( + catalog, + folder, + source, + expected, + autoescape, +): + catalog.jinja_env.autoescape = autoescape + + (folder / "Icon.jinja").write_text('') + (folder / "Title.jinja").write_text("

{{ content }}

") + (folder / "Page.jinja").write_text(source) + + html = catalog.render("Page") + assert html == Markup(expected) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_composition(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Greeting.jinja").write_text( + """ +{#def message #} +
{{ message }}
+""" + ) + + (folder / "CloseBtn.jinja").write_text( + """ +{#def disabled=False -#} + +""" + ) + + (folder / "Card.jinja").write_text( + """ +
+{{ content }} + +
+""" + ) + + (folder / "Page.jinja").write_text( + """ +{#def message #} + + + + +""" + ) + + html = catalog.render("Page", message="Hello") + print(html) + assert ( + """ +
+
Hello
+ + +
+""".strip() + in html + ) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_just_properties(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Lorem.jinja").write_text( + """ +{#def ipsum=False #} +

lorem {{ "ipsum" if ipsum else "lorem" }}

+""" + ) + + (folder / "Layout.jinja").write_text( + """ +
+{{ content }} +
+""" + ) + + (folder / "Page.jinja").write_text( + """ + + +

meh

+ +
+""" + ) + + html = catalog.render("Page") + print(html) + assert ( + """ +
+

lorem ipsum

+

meh

+

lorem lorem

+
+""".strip() + in html + ) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_render_assets(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Greeting.jinja").write_text( + """ +{#def message #} +{#css greeting.css, http://example.com/super.css #} +{#js greeting.js #} +
{{ message }}
+""" + ) + + (folder / "Card.jinja").write_text( + """ +{#css https://somewhere.com/style.css, card.css #} +{#js card.js, shared.js #} +
+{{ content }} +
+""" + ) + + (folder / "Layout.jinja").write_text( + """ + +{{ catalog.render_assets() }} +{{ content }} + +""" + ) + + (folder / "Page.jinja").write_text( + """ +{#def message #} +{#js https://somewhere.com/blabla.js, shared.js #} + + + + + + +""" + ) + + html = catalog.render("Page", message="Hello") + print(html) + assert ( + """ + + + + + + + + + +
+
Hello
+ +
+ +""".strip() + in html + ) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_global_values(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Global.jinja").write_text("""{{ globalvar }}""") + message = "Hello world!" + catalog.jinja_env.globals["globalvar"] = message + html = catalog.render("Global") + print(html) + assert message in html + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_required_attr_are_required(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Greeting.jinja").write_text( + """ +{#def message #} +
{{ message }}
+""" + ) + + with pytest.raises(jinjax.MissingRequiredArgument): + catalog.render("Greeting") + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_subfolder(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + sub = folder / "UI" + sub.mkdir() + (folder / "Meh.jinja").write_text("Meh") + (sub / "Tab.jinja").write_text('
{{ content }}
') + + html = catalog.render("Meh") + assert html == Markup('
Meh
') + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_default_attr(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Greeting.jinja").write_text( + """ +{#def message="Hello", world=False #} +
{{ message }}{% if world %} World{% endif %}
+""" + ) + + (folder / "Page.jinja").write_text( + """ + + + + + +""" + ) + + html = catalog.render("Page", message="Hello") + print(html) + assert ( + """ +
Hello
+
Hi
+
Hello
+
Hello World
+
Hello World
+""".strip() + in html + ) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_raw_content(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Code.jinja").write_text(""" +
+{{ content|e }}
+
+""") + + (folder / "Page.jinja").write_text(""" + +{% raw -%} +{#def message="Hello", world=False #} +
+
{{ message }}{% if world %} World{% endif %}
+{%- endraw %} +
+""") + + html = catalog.render("Page") + print(html) + assert ( + """ +
+{#def message="Hello", world=False #}
+<Header />
+<div>{{ message }}{% if world %} World{% endif %}</div>
+
+""".strip() + in html + ) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_multiple_raw(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "C.jinja").write_text(""" +
+""") + + (folder / "Page.jinja").write_text(""" + +{% raw -%} + +{%- endraw %} + +{% raw %}{% endraw %} + +""") + + html = catalog.render("Page", message="Hello") + print(html) + assert ( + """ +
+<C id="2" /> +
+<C id="4" /> +
+""".strip() + in html + ) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_check_for_unclosed(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Lorem.jinja").write_text(""" +{#def ipsum=False #} +

lorem {{ "ipsum" if ipsum else "lorem" }}

+""") + + (folder / "Page.jinja").write_text(""" +
+ +
+""") + + with pytest.raises(TemplateSyntaxError): + try: + catalog.render("Page") + except TemplateSyntaxError as err: + print(err) + raise + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_dict_as_attr(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "CitiesList.jinja").write_text(""" +{#def cities #} +{% for city, country in cities.items() -%} +

{{ city }}, {{ country }}

+{%- endfor %} +""") + + (folder / "Page.jinja").write_text(""" + +""") + + html = catalog.render("Page") + assert html == Markup("

Lima, Peru

New York, USA

") + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_cleanup_assets(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Layout.jinja").write_text(""" + +{{ catalog.render_assets() }} +{{ content }} + +""") + + (folder / "Foo.jinja").write_text(""" +{#js foo.js #} + +

Foo

+
+""") + + (folder / "Bar.jinja").write_text(""" +{#js bar.js #} + +

Bar

+
+""") + + html = catalog.render("Foo") + print(html, "\n") + assert ( + """ + + +

Foo

+ +""".strip() + in html + ) + + html = catalog.render("Bar") + print(html) + assert ( + """ + + +

Bar

+ +""".strip() + in html + ) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_do_not_mess_with_external_jinja_env(folder_t, folder, autoescape): + """https://github.com/jpsca/jinjax/issues/19""" + (folder_t / "greeting.html").write_text("Jinja still works") + (folder / "Greeting.jinja").write_text("JinjaX works") + + jinja_env = jinja2.Environment( + loader=jinja2.FileSystemLoader(folder_t), + extensions=["jinja2.ext.i18n"], + ) + jinja_env.globals = {"glo": "bar"} + jinja_env.filters = {"fil": lambda x: x} + jinja_env.tests = {"tes": lambda x: x} + jinja_env.autoescape = autoescape + + catalog = jinjax.Catalog( + jinja_env=jinja_env, + extensions=["jinja2.ext.debug"], + globals={"xglo": "foo"}, + filters={"xfil": lambda x: x}, + tests={"xtes": lambda x: x}, + ) + catalog.add_folder(folder) + + html = catalog.render("Greeting") + assert html == Markup("JinjaX works") + + assert catalog.jinja_env.globals["catalog"] == catalog + assert catalog.jinja_env.globals["glo"] == "bar" + assert catalog.jinja_env.globals["xglo"] == "foo" + assert catalog.jinja_env.filters["fil"] + assert catalog.jinja_env.filters["xfil"] + assert catalog.jinja_env.tests["tes"] + assert catalog.jinja_env.tests["xtes"] + assert "jinja2.ext.InternationalizationExtension" in catalog.jinja_env.extensions + assert "jinja2.ext.DebugExtension" in catalog.jinja_env.extensions + assert "jinja2.ext.ExprStmtExtension" in catalog.jinja_env.extensions + + tmpl = jinja_env.get_template("greeting.html") + assert tmpl.render() == "Jinja still works" + + assert jinja_env.globals["catalog"] == catalog + assert jinja_env.globals["glo"] == "bar" + assert "xglo" not in jinja_env.globals + assert jinja_env.filters["fil"] + assert "xfil" not in jinja_env.filters + assert jinja_env.tests["tes"] + assert "xtes" not in jinja_env.tests + assert "jinja2.ext.InternationalizationExtension" in jinja_env.extensions + assert "jinja2.ext.DebugExtension" not in jinja_env.extensions + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_auto_reload(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Layout.jinja").write_text(""" + +{{ content }} + +""") + + (folder / "Foo.jinja").write_text(""" + +

Foo

+ +
+""") + + bar_file = folder / "Bar.jinja" + bar_file.write_text("

Bar

") + + html1 = catalog.render("Foo") + print(bar_file.stat().st_mtime) + print(html1, "\n") + assert ( + """ + +

Foo

+

Bar

+ +""".strip() + in html1 + ) + + # Give it some time so the st_mtime are different + time.sleep(0.1) + + catalog.auto_reload = False + bar_file.write_text("

Ignored

") + print(bar_file.stat().st_mtime) + html2 = catalog.render("Foo") + print(html2, "\n") + + catalog.auto_reload = True + bar_file.write_text("

Updated

") + print(bar_file.stat().st_mtime) + html3 = catalog.render("Foo") + print(html3, "\n") + + assert html1 == html2 + assert ( + """ + +

Foo

+

Updated

+ +""".strip() + in html3 + ) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_subcomponents(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + """Issue https://github.com/jpsca/jinjax/issues/32""" + (folder / "Page.jinja").write_text(""" +{#def message #} + +

lorem ipsum

+ +{{ message }} + +""") + + (folder / "Subcomponent.jinja").write_text(""" +

foo bar

+""") + + html = catalog.render("Page", message="<3") + + if autoescape: + expected = """ + +

lorem ipsum

+

foo bar

+<3 +""" + else: + expected = """ + +

lorem ipsum

+

foo bar

+<3 +""" + + assert html == Markup(expected.strip()) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_fingerprint_assets(catalog, folder: Path, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Layout.jinja").write_text(""" + +{{ catalog.render_assets() }} +{{ content }} + +""") + + (folder / "Page.jinja").write_text(""" +{#css app.css, http://example.com/super.css #} +{#js app.js #} +Hi +""") + + (folder / "app.css").write_text("...") + + catalog.fingerprint = True + html = catalog.render("Page", message="Hello") + print(html) + + assert 'src="/static/components/app.js"' in html + assert 'href="/static/components/app-' in html + assert 'href="http://example.com/super.css' in html + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_colon_in_attrs(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "C.jinja").write_text(""" +
+""") + + (folder / "Page.jinja").write_text(""" + +""") + + html = catalog.render("Page", message="Hello") + print(html) + assert """
""" in html + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_template_globals(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Input.jinja").write_text(""" +{# def name, value #} +""") + + (folder / "CsrfToken.jinja").write_text(""" + +""") + + (folder / "Form.jinja").write_text(""" +
{{content}} +""") + + (folder / "Page.jinja").write_text(""" +{# def value #} +
+""") + + html = catalog.render("Page", value="bar", __globals={"csrf_token": "abc"}) + print(html) + assert """""" in html + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_template_globals_update_cache(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "CsrfToken.jinja").write_text( + """""" + ) + (folder / "Page.jinja").write_text("""""") + + html = catalog.render("Page", __globals={"csrf_token": "abc"}) + print(html) + assert """""" in html + + html = catalog.render("Page", __globals={"csrf_token": "xyz"}) + print(html) + assert """""" in html + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_alpine_sintax(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Greeting.jinja").write_text(""" +{#def message #} +""") + + html = catalog.render("Greeting", message="Hello world!") + print(html) + expected = """""" + assert html == Markup(expected) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_alpine_sintax_in_component(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Button.jinja").write_text( + """""" + ) + + (folder / "Greeting.jinja").write_text( + """""" + ) + + html = catalog.render("Greeting") + print(html) + expected = """""" + assert html == Markup(expected) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_autoescaped_attrs(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "CheckboxItem.jinja").write_text( + """
""" + ) + + (folder / "Page.jinja").write_text( + """""" + ) + + html = catalog.render("Page") + print(html) + expected = """
""" + assert html == Markup(expected) + + +@pytest.mark.parametrize( + "template", + [ + pytest.param( + dedent( + """ + {# def + href, + hx_target="#maincontent", + hx_swap="innerHTML show:body:top", + hx_push_url=true, + #} + + {{- content -}} + + """ + ), + id="no comment", + ), + pytest.param( + dedent( + """ + {# def + href, + hx_target="#maincontent", # css selector + hx_swap="innerHTML show:body:top", + hx_push_url=true, + #} + + {{- content -}} + + """ + ), + id="comment with # on line", + ), + pytest.param( + dedent( + """ + {# def + href, # url of the target page + hx_target="#maincontent", # css selector + hx_swap="innerHTML show:body:top", # browse on top of the page + hx_push_url=true, # replace the url of the browser + #} + + {{- content -}} + + """ + ), + id="many comments", + ), + pytest.param( + dedent( + """ + {# def + href: str, # url of the target page + hx_target: str = "#maincontent", # css selector + hx_swap: str = "innerHTML show:body:top", # browse on top of the page + hx_push_url: bool = true, # replace the url + #} + + {{- content -}} + + """ + ), + id="many comments and typing", + ), + ], +) +@pytest.mark.parametrize("autoescape", [True, False]) +def test_strip_comment(catalog, folder, autoescape, template): + catalog.jinja_env.autoescape = autoescape + + (folder / "A.jinja").write_text(template) + + (folder / "Page.jinja").write_text("""Yolo""") + + html = catalog.render("Page") + print(html) + expected = """ +Yolo""".strip() + assert html == Markup(expected) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_auto_load_assets_with_same_name(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Layout.jinja").write_text( + """{{ catalog.render_assets() }}\n{{ content }}""" + ) + + (folder / "FooBar.css").touch() + + (folder / "common").mkdir() + (folder / "common" / "Form.jinja").write_text( + """ +{#js "shared.js" #} +
""" + ) + + (folder / "common" / "Form.css").touch() + (folder / "common" / "Form.js").touch() + + (folder / "Page.jinja").write_text( + """ +{#css "Page.css" #} +""" + ) + + (folder / "Page.css").touch() + (folder / "Page.js").touch() + + html = catalog.render("Page") + print(html) + + expected = """ + + + + + +
+""".strip() + + assert html == Markup(expected) + + +def test_vue_like_syntax(catalog, folder): + (folder / "Test.jinja").write_text(""" + {#def a, b, c, d #} + {{ a }} {{ b }} {{ c }} {{ d }} + """) + (folder / "Caller.jinja").write_text( + """""" + ) + html = catalog.render("Caller") + print(html) + expected = """4 2+2 {'lorem': 'ipsum'} False""".strip() + assert html == Markup(expected) + + +def test_jinja_like_syntax(catalog, folder): + (folder / "Test.jinja").write_text(""" + {#def a, b, c, d #} + {{ a }} {{ b }} {{ c }} {{ d }} + """) + (folder / "Caller.jinja").write_text( + """""" + ) + html = catalog.render("Caller") + print(html) + expected = """4 2+2 {'lorem': 'ipsum'} False""".strip() + assert html == Markup(expected) + + +def test_mixed_syntax(catalog, folder): + (folder / "Test.jinja").write_text(""" + {#def a, b, c, d #} + {{ a }} {{ b }} {{ c }} {{ d }} + """) + (folder / "Caller.jinja").write_text( + """""" + ) + html = catalog.render("Caller") + print(html) + expected = """4 {{2+2}} {'lorem': 'ipsum'} False""".strip() + assert html == Markup(expected) + + +@pytest.mark.parametrize("autoescape", [True, False]) +def test_slots(catalog, folder, autoescape): + catalog.jinja_env.autoescape = autoescape + + (folder / "Component.jinja").write_text( + """ +

{{ content }}

+

{{ content("first") }}

+

{{ content("second") }}

+

{{ content("antoher") }}

+

{{ content() }}

+""".strip() + ) + + (folder / "Messages.jinja").write_text( + """ + +{% if _slot == "first" %}Hello World +{%- elif _slot == "second" %}Lorem Ipsum +{%- elif _slot == "meh" %}QWERTYUIOP +{%- else %}Default{% endif %} + +""".strip() + ) + + html = catalog.render("Messages") + print(html) + expected = """ +

Default

+

Hello World

+

Lorem Ipsum

+

Default

+

Default

+""".strip() + assert html == Markup(expected) -- cgit v1.2.3