from typing import Any import pytest from django.conf import settings from django.http import HttpRequest, HttpResponse from django.template import Context, Template from django.test import Client from django.urls import path from pytest_django.asserts import assertInHTML from django_components import Component, ComponentView, get_component_url, register, types from django_components.testing import djc_test from django_components.urls import urlpatterns as dc_urlpatterns from django_components.util.misc import format_url from .testutils import setup_test_config # DO NOT REMOVE! # # This is intentionally defined before `setup_test_config()` in order to test that # the URL extension works even before the Django has been set up. # # Because if we define the component before `django.setup()`, then we store it in # event queue, and will register it when `AppConfig.ready()` is finally called. # # This test relies on the "url" extension calling `add_extension_urls()` from within # the `on_component_class_created()` hook. class ComponentBeforeReady(Component): class View: public = True template = "Hello" setup_test_config({"autodiscover": False}) class CustomClient(Client): def __init__(self, urlpatterns=None, *args, **kwargs): import types if urlpatterns: urls_module = types.ModuleType("urls") urls_module.urlpatterns = urlpatterns + dc_urlpatterns # type: ignore[attr-defined] settings.ROOT_URLCONF = urls_module else: settings.ROOT_URLCONF = __name__ settings.SECRET_KEY = "secret" # noqa: S105 super().__init__(*args, **kwargs) @djc_test class TestComponentAsView: def test_render_component_from_template(self): @register("testcomponent") class MockComponentRequest(Component): template = """
{% csrf_token %}
""" def get_template_data(self, args, kwargs, slots, context): return {"variable": kwargs["variable"]} def render_template_view(_request): template = Template( """ {% load component_tags %} {% component "testcomponent" variable="TEMPLATE" %}{% endcomponent %} """, ) return HttpResponse(template.render(Context({}))) client = CustomClient(urlpatterns=[path("test_template/", render_template_view)]) response = client.get("/test_template/") assert response.status_code == 200 assertInHTML( '', response.content.decode(), ) def test_get_request(self): class MockComponentRequest(Component): template = """
{% csrf_token %}
""" def get_template_data(self, args, kwargs, slots, context): return {"inner_var": kwargs["variable"]} class View(ComponentView): def get(self, request, *args, **kwargs) -> HttpResponse: return self.component.render_to_response(kwargs={"variable": "GET"}) client = CustomClient(urlpatterns=[path("test/", MockComponentRequest.as_view())]) response = client.get("/test/") assert response.status_code == 200 assertInHTML( '', response.content.decode(), ) def test_get_request_shortcut(self): class MockComponentRequest(Component): template = """
{% csrf_token %}
""" def get_template_data(self, args, kwargs, slots, context): return {"inner_var": kwargs["variable"]} def get(self, request, *args, **kwargs) -> HttpResponse: return self.render_to_response(kwargs={"variable": "GET"}) client = CustomClient(urlpatterns=[path("test/", MockComponentRequest.as_view())]) response = client.get("/test/") assert response.status_code == 200 assertInHTML( '', response.content.decode(), ) def test_post_request(self): class MockComponentRequest(Component): template: types.django_html = """
{% csrf_token %}
""" def get_template_data(self, args, kwargs, slots, context): return {"inner_var": kwargs["variable"]} class View(ComponentView): def post(self, request, *args, **kwargs) -> HttpResponse: variable = request.POST.get("variable") return self.component.render_to_response(kwargs={"variable": variable}) client = CustomClient(urlpatterns=[path("test/", MockComponentRequest.as_view())]) response = client.post("/test/", {"variable": "POST"}) assert response.status_code == 200 assertInHTML( '', response.content.decode(), ) def test_post_request_shortcut(self): class MockComponentRequest(Component): template: types.django_html = """
{% csrf_token %}
""" def get_template_data(self, args, kwargs, slots, context): return {"inner_var": kwargs["variable"]} def post(self, request, *args, **kwargs) -> HttpResponse: variable = request.POST.get("variable") return self.render_to_response(kwargs={"variable": variable}) client = CustomClient(urlpatterns=[path("test/", MockComponentRequest.as_view())]) response = client.post("/test/", {"variable": "POST"}) assert response.status_code == 200 assertInHTML( '', response.content.decode(), ) def test_instantiate_component(self): class MockComponentRequest(Component): template = """
""" def get_template_data(self, args, kwargs, slots, context): return {"inner_var": kwargs["variable"]} def get(self, request, *args, **kwargs) -> HttpResponse: return self.render_to_response(kwargs={"variable": self.name}) view = MockComponentRequest.as_view() client = CustomClient(urlpatterns=[path("test/", view)]) response = client.get("/test/") assert response.status_code == 200 assertInHTML( '', response.content.decode(), ) def test_replace_slot_in_view(self): class MockComponentSlot(Component): template = """ {% load component_tags %}
{% slot "first_slot" %} Hey, I'm {{ name }} {% endslot %} {% slot "second_slot" %} {% endslot %}
""" def get(self, request, *args, **kwargs) -> HttpResponse: return self.render_to_response( context={"name": "Bob"}, slots={"second_slot": "Nice to meet you, Bob"}, ) client = CustomClient(urlpatterns=[path("test_slot/", MockComponentSlot.as_view())]) response = client.get("/test_slot/") assert response.status_code == 200 assert b"Hey, I'm Bob" in response.content assert b"Nice to meet you, Bob" in response.content def test_replace_slot_in_view_with_insecure_content(self): class MockInsecureComponentSlot(Component): template = """ {% load component_tags %}
{% slot "test_slot" %} {% endslot %}
""" def get(self, request, *args, **kwargs) -> HttpResponse: return self.render_to_response( context={}, slots={"test_slot": ""}, ) client = CustomClient(urlpatterns=[path("test_slot_insecure/", MockInsecureComponentSlot.as_view())]) response = client.get("/test_slot_insecure/") assert response.status_code == 200 assert b""}) client = CustomClient(urlpatterns=[path("test_context_insecure/", MockInsecureComponentContext.as_view())]) response = client.get("/test_context_insecure/") assert response.status_code == 200 assert b"