from unittest.mock import patch import frappe from frappe import get_hooks from frappe.tests import IntegrationTestCase from frappe.utils import set_request from frappe.website.page_renderers.static_page import StaticPage from frappe.website.serve import get_response, get_response_content from frappe.website.utils import build_response, clear_website_cache, get_home_page class TestWebsite(IntegrationTestCase): def setUp(self): frappe.set_user("Guest") self._clearRequest() def tearDown(self): frappe.db.delete("Access Log") frappe.set_user("Administrator") self._clearRequest() def _clearRequest(self): if hasattr(frappe.local, "request"): delattr(frappe.local, "request") def test_home_page(self): frappe.set_user("Administrator") # test home page via role user = frappe.get_doc( doctype="User", email="test-user-for-home-page@example.com", first_name="test" ).insert(ignore_if_duplicate=True) user.reload() role = frappe.get_doc(doctype="Role", role_name="home-page-test", desk_access=0).insert( ignore_if_duplicate=True ) user.add_roles(role.name) user.save() frappe.db.set_value("Role", "home-page-test", "home_page", "home-page-test") frappe.set_user("test-user-for-home-page@example.com") self.assertEqual(get_home_page(), "home-page-test") frappe.set_user("Administrator") frappe.db.set_value("Role", "home-page-test", "home_page", "") # home page via portal settings frappe.db.set_single_value("Portal Settings", "default_portal_home", "test-portal-home") frappe.set_user("test-user-for-home-page@example.com") frappe.cache.hdel("home_page", frappe.session.user) self.assertEqual(get_home_page(), "test-portal-home") frappe.db.set_single_value("Portal Settings", "default_portal_home", "") clear_website_cache() # home page via website settings frappe.db.set_single_value("Website Settings", "home_page", "contact") self.assertEqual(get_home_page(), "contact") frappe.db.set_single_value("Website Settings", "home_page", None) clear_website_cache() # fallback homepage self.assertEqual(get_home_page(), "me") # fallback homepage for guest frappe.set_user("Guest") self.assertEqual(get_home_page(), "login") frappe.set_user("Administrator") # test homepage via hooks clear_website_cache() with patch.object( frappe, "get_hooks", patched_get_hooks( "get_website_user_home_page", ["frappe.www._test._test_home_page.get_website_user_home_page"] ), ): self.assertEqual(get_home_page(), "_test/_test_folder") clear_website_cache() with patch.object(frappe, "get_hooks", patched_get_hooks("website_user_home_page", ["login"])): self.assertEqual(get_home_page(), "login") clear_website_cache() with patch.object(frappe, "get_hooks", patched_get_hooks("home_page", ["about"])): self.assertEqual(get_home_page(), "about") clear_website_cache() with patch.object( frappe, "get_hooks", patched_get_hooks("role_home_page", {"home-page-test": ["home-page-test"]}) ): self.assertEqual(get_home_page(), "home-page-test") def test_page_load(self): set_request(method="POST", path="login") response = get_response() self.assertEqual(response.status_code, 200) html = frappe.safe_decode(response.get_data()) self.assertTrue("// login.js" in html) self.assertTrue("" in html) def test_static_page(self): set_request(method="GET", path="/_test/static-file-test.png") response = get_response() self.assertEqual(response.status_code, 200) set_request(method="GET", path="/_test/assets/image.jpg") response = get_response() self.assertEqual(response.status_code, 200) set_request(method="GET", path="/_test/assets/image") response = get_response() self.assertEqual(response.status_code, 200) with patch.object(StaticPage, "render") as static_render: set_request(method="GET", path="/_test/assets/image") response = get_response() static_render.assert_called() def test_error_page(self): set_request(method="GET", path="/_test/problematic_page") response = get_response() self.assertEqual(response.status_code, 417) def test_login(self): set_request(method="GET", path="/login") response = get_response() self.assertEqual(response.status_code, 200) html = frappe.safe_decode(response.get_data()) self.assertTrue("// login.js" in html) self.assertTrue("" in html) def test_app(self): frappe.set_user("Administrator") set_request(method="GET", path="/desk") response = get_response() self.assertEqual(response.status_code, 200) html = frappe.safe_decode(response.get_data()) self.assertTrue("window.app = true;" in html) frappe.local.session_obj = None def test_not_found(self): set_request(method="GET", path="/_test/missing") response = get_response() self.assertEqual(response.status_code, 404) def test_redirect(self): import frappe.hooks frappe.set_user("Administrator") frappe.hooks.website_redirects = [ dict(source=r"/testfrom", target=r"://testto1"), dict(source=r"/testfromregex.*", target=r"://testto2"), dict(source=r"/testsub/(.*)", target=r"://testto3/\1"), dict(source=r"/courses/course\?course=(.*)", target=r"/courses/\1", match_with_query_string=True), dict( source="/test307", target="/test", redirect_http_status=307, ), ] website_settings = frappe.get_doc("Website Settings") website_settings.append( "route_redirects", {"source": "/testsource", "target": "/testtarget"}, ) website_settings.append( "route_redirects", {"source": "/testdoc307", "target": "/testtarget", "redirect_http_status": 307}, ) website_settings.append( "route_redirects", {"source": "/test-query", "target": "/test-query-new", "forward_query_parameters": 1}, ) website_settings.save() set_request(method="GET", path="/testfrom") response = get_response() self.assertEqual(response.status_code, 301) self.assertEqual(response.headers.get("Location"), r"://testto1") set_request(method="GET", path="/testfromregex/test") response = get_response() self.assertEqual(response.status_code, 301) self.assertEqual(response.headers.get("Location"), r"://testto2") set_request(method="GET", path="/testsub/me") response = get_response() self.assertEqual(response.status_code, 301) self.assertEqual(response.headers.get("Location"), r"://testto3/me") set_request(method="GET", path="/test404") response = get_response() self.assertEqual(response.status_code, 404) set_request(method="GET", path="/testsource") response = get_response() self.assertEqual(response.status_code, 301) self.assertEqual(response.headers.get("Location"), "/testtarget") set_request(method="GET", path="/testdoc307") response = get_response() self.assertEqual(response.status_code, 307) self.assertEqual(response.headers.get("Location"), "/testtarget") set_request(method="GET", path="/courses/course?course=data") response = get_response() self.assertEqual(response.status_code, 301) self.assertEqual(response.headers.get("Location"), "/courses/data") set_request(method="GET", path="/test307") response = get_response() self.assertEqual(response.status_code, 307) self.assertEqual(response.headers.get("Location"), "/test") set_request(method="POST", path="/test307") response = get_response() self.assertEqual(response.status_code, 307) self.assertEqual(response.headers.get("Location"), "/test") set_request(method="GET", path="/test-query?param=123") response = get_response() self.assertEqual(response.status_code, 301) self.assertEqual(response.headers.get("Location"), "/test-query-new?param=123") delattr(frappe.hooks, "website_redirects") frappe.client_cache.delete_value("app_hooks") def test_custom_page_renderer(self): from frappe import get_hooks def patched_get_hooks(*args, **kwargs): return_value = get_hooks(*args, **kwargs) if args and args[0] == "page_renderer": return_value = ["frappe.tests.test_website.CustomPageRenderer"] return return_value with patch.object(frappe, "get_hooks", patched_get_hooks): set_request(method="GET", path="/custom") response = get_response() self.assertEqual(response.status_code, 3984) set_request(method="GET", path="/new") content = get_response_content() self.assertIn("
Test content
", content) def test_json_sidebar_data(self): frappe.flags.look_for_sidebar = False content = get_response_content("/_test/_test_folder/_test_page") self.assertNotIn("Test Sidebar", content) clear_website_cache() frappe.flags.look_for_sidebar = True content = get_response_content("/_test/_test_folder/_test_page") self.assertIn("Test Sidebar", content) frappe.flags.look_for_sidebar = False def test_base_template(self): content = get_response_content("/_test/_test_custom_base.html") # assert the text in base template is rendered self.assertIn("Test content
", content) def test_index_and_next_comment(self): content = get_response_content("/_test/_test_folder") # test if {index} was rendered self.assertIn(' Test Page', content) self.assertIn('Test TOC', content) content = get_response_content("/_test/_test_folder/_test_page") # test if {next} was rendered self.assertIn('Next: Test TOC', content) def test_colocated_assets(self): content = get_response_content("/_test/_test_folder/_test_page") self.assertIn("""""", content) self.assertIn("background-color: var(--bg-color);", content) def test_raw_assets_are_loaded(self): content = get_response_content("/_test/assets/js_asset.min.js") # minified js files should not be passed through jinja renderer self.assertEqual("""//{% if title %} {{title}} {% endif %}\nconsole.log("in");\n""", content) content = get_response_content("/_test/assets/css_asset.css") self.assertEqual("""body{color:red}""", content) def test_breadcrumbs(self): content = get_response_content("/_test/_test_folder/_test_page") self.assertIn('Test Folder', content) self.assertIn(' Test Page', content) content = get_response_content("/_test/_test_folder/index") self.assertIn(' Test', content) self.assertIn('Test Folder', content) def test_get_context_without_context_object(self): content = get_response_content("/_test/_test_no_context") self.assertIn("Custom Content", content) def test_caching(self): # to enable caching frappe.flags.force_website_cache = True clear_website_cache() # first response no-cache response = get_response("/_test/_test_folder/_test_page") self.assertIn(("X-From-Cache", "False"), list(response.headers)) # first response returned from cache response = get_response("/_test/_test_folder/_test_page") self.assertIn(("X-From-Cache", "True"), list(response.headers)) frappe.flags.force_website_cache = False def test_safe_render(self): content = get_response_content("/_test/_test_safe_render_on") self.assertNotIn("Safe Render On", content) self.assertIn("Show Error", content) content = get_response_content("/_test/_test_safe_render_off") self.assertIn("Safe Render Off", content) self.assertIn("test.__test", content) self.assertNotIn("Show Error", content) def test_never_render(self): from pathlib import Path from random import choices WWW = Path(frappe.get_app_path("frappe")) / "www" FILES_TO_SKIP = choices(list(WWW.glob("**/*.py*")), k=10) for suffix in FILES_TO_SKIP: path: str = suffix.relative_to(WWW).as_posix() content = get_response_content(path) self.assertIn("