feat: Add support for HTML fragments (#845)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Juro Oravec 2024-12-19 10:03:35 +01:00 committed by GitHub
parent 6681fc0085
commit 4dab940db8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 1225 additions and 246 deletions

View file

@ -68,9 +68,7 @@ class RenderDependenciesTests(BaseTestCase):
self.assertInHTML('<script src="django_components/django_components.min.js"></script>', rendered, count=1)
self.assertInHTML("<style>.xyz { color: red; }</style>", rendered, count=1) # Inlined CSS
self.assertInHTML(
"<script>eval(Components.unescapeJs(`console.log(&quot;xyz&quot;);`))</script>", rendered, count=1
) # Inlined JS
self.assertInHTML('<script>console.log("xyz");</script>', rendered, count=1) # Inlined JS
self.assertInHTML('<link href="style.css" media="all" rel="stylesheet">', rendered, count=1) # Media.css
@ -90,9 +88,7 @@ class RenderDependenciesTests(BaseTestCase):
self.assertInHTML('<script src="django_components/django_components.min.js"></script>', rendered, count=1)
self.assertInHTML("<style>.xyz { color: red; }</style>", rendered, count=1) # Inlined CSS
self.assertInHTML(
"<script>eval(Components.unescapeJs(`console.log(&quot;xyz&quot;);`))</script>", rendered, count=1
) # Inlined JS
self.assertInHTML('<script>console.log("xyz");</script>', rendered, count=1) # Inlined JS
self.assertInHTML('<link href="style.css" media="all" rel="stylesheet">', rendered, count=1) # Media.css
self.assertEqual(rendered.count("<link"), 1)
@ -119,9 +115,7 @@ class RenderDependenciesTests(BaseTestCase):
self.assertInHTML('<script src="django_components/django_components.min.js"></script>', rendered, count=1)
self.assertInHTML("<style>.xyz { color: red; }</style>", rendered, count=1) # Inlined CSS
self.assertInHTML(
"<script>eval(Components.unescapeJs(`console.log(&quot;xyz&quot;);`))</script>", rendered, count=1
) # Inlined JS
self.assertInHTML('<script>console.log("xyz");</script>', rendered, count=1) # Inlined JS
self.assertInHTML('<link href="style.css" media="all" rel="stylesheet">', rendered, count=1) # Media.css
self.assertEqual(rendered.count("<link"), 1)
@ -157,7 +151,7 @@ class RenderDependenciesTests(BaseTestCase):
self.assertInHTML('<link href="style.css" media="all" rel="stylesheet">', rendered_raw, count=0) # Media.css
self.assertInHTML(
"<script>eval(Components.unescapeJs(`console.log(&quot;xyz&quot;);`))</script>",
'<script>console.log("xyz");</script>',
rendered_raw,
count=0,
) # Inlined JS
@ -184,9 +178,7 @@ class RenderDependenciesTests(BaseTestCase):
self.assertInHTML('<script src="django_components/django_components.min.js"></script>', rendered, count=1)
self.assertInHTML("<style>.xyz { color: red; }</style>", rendered, count=1) # Inlined CSS
self.assertInHTML(
"<script>eval(Components.unescapeJs(`console.log(&quot;xyz&quot;);`))</script>", rendered, count=1
) # Inlined JS
self.assertInHTML('<script>console.log("xyz");</script>', rendered, count=1) # Inlined JS
self.assertEqual(rendered.count('<link href="style.css" media="all" rel="stylesheet">'), 1) # Media.css
self.assertEqual(rendered.count("<link"), 1)
@ -234,7 +226,7 @@ class RenderDependenciesTests(BaseTestCase):
count=1,
)
self.assertInHTML(
"""<script>eval(Components.unescapeJs(`console.log(&quot;xyz&quot;);`))</script>""",
'<script>console.log("xyz");</script>',
rendered_body,
count=1,
)
@ -286,7 +278,7 @@ class RenderDependenciesTests(BaseTestCase):
count=1,
)
self.assertInHTML(
"""<script>eval(Components.unescapeJs(`console.log(&quot;xyz&quot;);`))</script>""",
'<script>console.log("xyz");</script>',
rendered_head,
count=1,
)
@ -401,6 +393,11 @@ class RenderDependenciesTests(BaseTestCase):
rendered_raw = Template(template_str).render(Context({"formset": [1]}))
rendered = render_dependencies(rendered_raw, type="fragment")
# Base64 encodings:
# `PGxpbmsgaHJlZj0ic3R5bGUuY3NzIiBtZWRpYT0iYWxsIiByZWw9InN0eWxlc2hlZXQiPg==` -> `<link href="style.css" media="all" rel="stylesheet">` # noqa: E501
# `PGxpbmsgaHJlZj0iL2NvbXBvbmVudHMvY2FjaGUvU2ltcGxlQ29tcG9uZW50XzMxMTA5Ny5jc3MiIG1lZGlhPSJhbGwiIHJlbD0ic3R5bGVzaGVldCI+` -> `<link href="/components/cache/SimpleComponent_311097.css" media="all" rel="stylesheet">` # noqa: E501
# `PHNjcmlwdCBzcmM9InNjcmlwdC5qcyI+PC9zY3JpcHQ+` -> `<script src="script.js"></script>`
# `PHNjcmlwdCBzcmM9Ii9jb21wb25lbnRzL2NhY2hlL1NpbXBsZUNvbXBvbmVudF8zMTEwOTcuanMiPjwvc2NyaXB0Pg==` -> `<script src="/components/cache/SimpleComponent_311097.js"></script>` # noqa: E501
expected = """
<table class="table-auto border-collapse divide-y divide-x divide-slate-300 w-full">
<!-- Table head -->
@ -423,10 +420,49 @@ class RenderDependenciesTests(BaseTestCase):
</tr>
</tbody>
</table>
"""
<script type="application/json" data-djc>
{"loadedCssUrls": [],
"loadedJsUrls": [],
"toLoadCssTags": ["PGxpbmsgaHJlZj0ic3R5bGUuY3NzIiBtZWRpYT0iYWxsIiByZWw9InN0eWxlc2hlZXQiPg==",
"PGxpbmsgaHJlZj0iL2NvbXBvbmVudHMvY2FjaGUvU2ltcGxlQ29tcG9uZW50XzMxMTA5Ny5jc3MiIG1lZGlhPSJhbGwiIHJlbD0ic3R5bGVzaGVldCI+"],
"toLoadJsTags": ["PHNjcmlwdCBzcmM9InNjcmlwdC5qcyI+PC9zY3JpcHQ+",
"PHNjcmlwdCBzcmM9Ii9jb21wb25lbnRzL2NhY2hlL1NpbXBsZUNvbXBvbmVudF8zMTEwOTcuanMiPjwvc2NyaXB0Pg=="]}
</script>
""" # noqa: E501
self.assertHTMLEqual(expected, rendered)
def test_raises_if_script_end_tag_inside_component_js(self):
class ComponentWithScript(SimpleComponent):
js: types.js = """
console.log("</script >");
"""
registry.register(name="test", component=ComponentWithScript)
with self.assertRaisesMessage(
RuntimeError,
"Content of `Component.js` for component 'ComponentWithScript' contains '</script>' end tag.",
):
ComponentWithScript.render(kwargs={"variable": "foo"})
def test_raises_if_script_end_tag_inside_component_css(self):
class ComponentWithScript(SimpleComponent):
css: types.css = """
/* </style > */
.xyz {
color: red;
}
"""
registry.register(name="test", component=ComponentWithScript)
with self.assertRaisesMessage(
RuntimeError,
"Content of `Component.css` for component 'ComponentWithScript' contains '</style>' end tag.",
):
ComponentWithScript.render(kwargs={"variable": "foo"})
class MiddlewareTests(BaseTestCase):
def test_middleware_response_without_content_type(self):
@ -462,9 +498,7 @@ class MiddlewareTests(BaseTestCase):
self.assertInHTML('<script src="django_components/django_components.min.js"></script>', rendered, count=1)
# Inlined JS
self.assertInHTML(
"<script>eval(Components.unescapeJs(`console.log(&quot;xyz&quot;);`))</script>", rendered, count=1
)
self.assertInHTML('<script>console.log("xyz");</script>', rendered, count=1)
# Inlined CSS
self.assertInHTML("<style>.xyz { color: red; }</style>", rendered, count=1)
# Media.css