from typing import List from django.test import override_settings from playwright.async_api import Error, Page from django_components import types from tests.django_test_setup import setup_test_config from tests.e2e.utils import TEST_SERVER_URL, with_playwright from tests.testutils import BaseTestCase setup_test_config( components={"autodiscover": False}, extra_settings={ "ROOT_URLCONF": "tests.test_dependency_manager", }, ) urlpatterns: List = [] class _BaseDepManagerTestCase(BaseTestCase): async def _create_page_with_dep_manager(self) -> Page: page = await self.browser.new_page() # Load the JS library by opening a page with the script, and then running the script code # E.g. `http://localhost:54017/static/django_components/django_components.min.js` script_url = TEST_SERVER_URL + "/static/django_components/django_components.min.js" await page.goto(script_url) # The page's body is the script code. We load it by executing the code await page.evaluate( """ () => { eval(document.body.textContent); } """ ) # Ensure the body is clear await page.evaluate( """ () => { document.body.innerHTML = ''; document.head.innerHTML = ''; } """ ) return page @override_settings(STATIC_URL="static/") class DependencyManagerTests(_BaseDepManagerTestCase): @with_playwright async def test_script_loads(self): page = await self._create_page_with_dep_manager() # Check the exposed API keys = sorted(await page.evaluate("Object.keys(Components)")) self.assertEqual(keys, ["createComponentsManager", "manager", "unescapeJs"]) keys = await page.evaluate("Object.keys(Components.manager)") self.assertEqual( keys, ["callComponent", "registerComponent", "registerComponentData", "loadScript", "markScriptLoaded"] ) await page.close() # Tests for `manager.loadScript()` / `manager.markAsLoaded()` @override_settings(STATIC_URL="static/") class LoadScriptTests(_BaseDepManagerTestCase): @with_playwright async def test_load_js_scripts(self): page = await self._create_page_with_dep_manager() # JS code that loads a few dependencies, capturing the HTML after each action test_js: types.js = """() => { const manager = Components.createComponentsManager(); const headBeforeFirstLoad = document.head.innerHTML; // Adds a script the first time manager.loadScript('js', ""); const bodyAfterFirstLoad = document.body.innerHTML; // Does not add it the second time manager.loadScript('js', ""); const bodyAfterSecondLoad = document.body.innerHTML; // Adds different script manager.loadScript('js', ""); const bodyAfterThirdLoad = document.body.innerHTML; const headAfterThirdLoad = document.head.innerHTML; return { bodyAfterFirstLoad, bodyAfterSecondLoad, bodyAfterThirdLoad, headBeforeFirstLoad, headAfterThirdLoad, }; }""" data = await page.evaluate(test_js) self.assertEqual(data["bodyAfterFirstLoad"], '') self.assertEqual(data["bodyAfterSecondLoad"], '') self.assertEqual( data["bodyAfterThirdLoad"], '' ) self.assertEqual(data["headBeforeFirstLoad"], data["headAfterThirdLoad"]) self.assertEqual(data["headBeforeFirstLoad"], "") await page.close() @with_playwright async def test_load_css_scripts(self): page = await self._create_page_with_dep_manager() # JS code that loads a few dependencies, capturing the HTML after each action test_js: types.js = """() => { const manager = Components.createComponentsManager(); const bodyBeforeFirstLoad = document.body.innerHTML; // Adds a script the first time manager.loadScript('css', ""); const headAfterFirstLoad = document.head.innerHTML; // Does not add it the second time manager.loadScript('css', ""); const headAfterSecondLoad = document.head.innerHTML; // Adds different script manager.loadScript('css', ""); const headAfterThirdLoad = document.head.innerHTML; const bodyAfterThirdLoad = document.body.innerHTML; return { headAfterFirstLoad, headAfterSecondLoad, headAfterThirdLoad, bodyBeforeFirstLoad, bodyAfterThirdLoad, }; }""" data = await page.evaluate(test_js) self.assertEqual(data["headAfterFirstLoad"], '') self.assertEqual(data["headAfterSecondLoad"], '') self.assertEqual(data["headAfterThirdLoad"], '') self.assertEqual(data["bodyBeforeFirstLoad"], data["bodyAfterThirdLoad"]) self.assertEqual(data["bodyBeforeFirstLoad"], "") await page.close() @with_playwright async def test_does_not_load_script_if_marked_as_loaded(self): page = await self._create_page_with_dep_manager() # JS code that loads a few dependencies, capturing the HTML after each action test_js: types.js = """() => { const manager = Components.createComponentsManager(); // Adds a script the first time manager.markScriptLoaded('css', '/one/two'); manager.markScriptLoaded('js', '/one/three'); manager.loadScript('css', ""); const headAfterFirstLoad = document.head.innerHTML; manager.loadScript('js', ""); const bodyAfterSecondLoad = document.body.innerHTML; return { headAfterFirstLoad, bodyAfterSecondLoad, }; }""" data = await page.evaluate(test_js) self.assertEqual(data["headAfterFirstLoad"], "") self.assertEqual(data["bodyAfterSecondLoad"], "") await page.close() # Tests for `manager.registerComponent()` / `registerComponentData()` / `callComponent()` @override_settings(STATIC_URL="static/") class CallComponentTests(_BaseDepManagerTestCase): @with_playwright async def test_calls_component_successfully(self): page = await self._create_page_with_dep_manager() test_js: types.js = """() => { const manager = Components.createComponentsManager(); const compName = 'my_comp'; const compId = '12345'; const inputHash = 'input-abc'; // Pretend that this HTML belongs to our component document.body.insertAdjacentHTML('beforeend', '