""" CAPA HTML rendering tests. """ import os import textwrap import unittest from unittest import mock import ddt from lxml import etree from openedx.core.djangolib.markup import HTML from xmodule.capa.tests.helpers import mock_capa_system, new_loncapa_problem from xmodule.capa.tests.test_util import UseUnsafeCodejail from .response_xml_factory import CustomResponseXMLFactory, StringResponseXMLFactory @ddt.ddt @UseUnsafeCodejail() class CapaHtmlRenderTest(unittest.TestCase): """ CAPA HTML rendering tests class. """ def setUp(self): super().setUp() self.capa_system = mock_capa_system() def test_blank_problem(self): """ It's important that blank problems don't break, since that's what you start with in studio. """ xml_str = " " # Create the problem problem = new_loncapa_problem(xml_str) # Render the HTML etree.XML(problem.get_html()) # TODO: This test should inspect the rendered html and assert one or more things about it def test_include_html(self): """Verify that files are embedded correctly in rendered HTML.""" # Create a test file to include self._create_test_file("test_include.xml", "Test include") # Generate some XML with an xml_str = textwrap.dedent( """ """ ) # Create the problem problem = new_loncapa_problem(xml_str, capa_system=self.capa_system) # Render the HTML rendered_html = etree.XML(problem.get_html()) # Expect that the include file was embedded in the problem test_element = rendered_html.find("test") assert test_element.tag == "test" assert test_element.text == "Test include" def test_process_outtext(self): """Ensure and are converted to tags.""" # Generate some XML with and xml_str = textwrap.dedent( """ Test text """ ) # Create the problem problem = new_loncapa_problem(xml_str) # Render the HTML rendered_html = etree.XML(problem.get_html()) # Expect that the and # were converted to tags span_element = rendered_html.find("span") assert span_element.text == "Test text" def test_anonymous_student_id(self): """Check that $anonymous_student_id is rendered as 'student'.""" # make sure anonymous_student_id is rendered properly as a context variable xml_str = textwrap.dedent( """ Welcome $anonymous_student_id """ ) # Create the problem problem = new_loncapa_problem(xml_str) # Render the HTML rendered_html = etree.XML(problem.get_html()) # Expect that the anonymous_student_id was converted to "student" span_element = rendered_html.find("span") assert span_element.text == "Welcome student" def test_render_script(self): """Ensure """ ) # Create the problem problem = new_loncapa_problem(xml_str) # Render the HTML rendered_html = etree.XML(problem.get_html()) # Expect that the script element has been removed from the rendered HTML script_element = rendered_html.find("script") assert script_element is None def test_render_javascript(self): """Verify JavaScript in """ ) # Create the problem problem = new_loncapa_problem(xml_str) # Render the HTML rendered_html = etree.XML(problem.get_html()) # expect the javascript is still present in the rendered html assert '' in etree.tostring(rendered_html).decode("utf-8") def test_render_response_xml(self): """Test that response XML is rendered correctly into HTML with template calls.""" # Generate some XML for a string response kwargs = { "question_text": "Test question", "explanation_text": "Test explanation", "answer": "Test answer", "hints": [("test prompt", "test_hint", "test hint text")], } xml_str = StringResponseXMLFactory().build_xml(**kwargs) # Mock out the template renderer the_system = mock_capa_system() the_system.render_template = mock.Mock() the_system.render_template.return_value = "
Input Template Render
" # Create the problem and render the HTML problem = new_loncapa_problem(xml_str, capa_system=the_system) rendered_html = etree.XML(problem.get_html()) # Expect problem has been turned into a
assert rendered_html.tag == "div" # Expect that the response has been turned into a
with correct attributes response_element = rendered_html.find("div") assert response_element.tag == "div" assert response_element.attrib["aria-label"] == "Question 1" # Expect that the response div.wrapper-problem-response # that contains a
for the textline textline_element = response_element.find("div") assert textline_element.text == "Input Template Render" # Expect a child
for the solution # with the rendered template solution_element = rendered_html.xpath('//div[@class="input-template-render"]')[0] assert solution_element.text == "Input Template Render" # Expect that the template renderer was called with the correct # arguments, once for the textline input and once for # the solution expected_textline_context = { "STATIC_URL": "/dummy-static/", "status": the_system.STATUS_CLASS("unsubmitted"), "value": "", "preprocessor": None, "msg": "", "inline": False, "hidden": False, "do_math": False, "id": "1_2_1", "trailing_text": "", "size": None, "response_data": {"label": "Test question", "descriptions": {}}, "describedby_html": HTML('aria-describedby="status_1_2_1"'), } expected_solution_context = {"id": "1_solution_1"} expected_calls = [ mock.call("textline.html", expected_textline_context), mock.call("solutionspan.html", expected_solution_context), mock.call("textline.html", expected_textline_context), mock.call("solutionspan.html", expected_solution_context), ] assert the_system.render_template.call_args_list == expected_calls def test_correct_aria_label(self): """Check that rendered responses have correct aria-label attributes.""" xml = """ over-suspicious funny Urdu Finnish """ problem = new_loncapa_problem(xml) rendered_html = etree.XML(problem.get_html()) response_elements = rendered_html.findall("div") assert response_elements[0].attrib["aria-label"] == "Question 1" assert response_elements[1].attrib["aria-label"] == "Question 2" def test_render_response_with_overall_msg(self): """Verify that CustomResponse overall messages are rendered correctly.""" # CustomResponse script that sets an overall_message script = textwrap.dedent( """ def check_func(*args): msg = '

Test message 1

Test message 2

' return {'overall_message': msg, 'input_list': [ {'ok': True, 'msg': '' } ] } """ ) # Generate some XML for a CustomResponse kwargs = {"script": script, "cfn": "check_func"} xml_str = CustomResponseXMLFactory().build_xml(**kwargs) # Create the problem and render the html problem = new_loncapa_problem(xml_str) # Grade the problem problem.grade_answers({"1_2_1": "test"}) # Render the html rendered_html = etree.XML(problem.get_html()) # Expect that there is a
within the response
# with css class response_message msg_div_element = rendered_html.find(".//div[@class='response_message']") assert msg_div_element.tag == "div" assert msg_div_element.get("class") == "response_message" # Expect that the
contains our message (as part of the XML tree) msg_p_elements = msg_div_element.findall("p") assert msg_p_elements[0].tag == "p" assert msg_p_elements[0].text == "Test message 1" assert msg_p_elements[1].tag == "p" assert msg_p_elements[1].text == "Test message 2" def test_substitute_python_vars(self): """Ensure Python variables in XML scripts are substituted correctly in attributes.""" # Generate some XML with Python variables defined in a script # and used later as attributes xml_str = textwrap.dedent( """ """ ) # Create the problem and render the HTML problem = new_loncapa_problem(xml_str) rendered_html = etree.XML(problem.get_html()) # Expect that the variable $test has been replaced with its value span_element = rendered_html.find("span") assert span_element.get("attr") == "TEST" def test_xml_comments_and_other_odd_things(self): """Ensure XML comments and processing instructions are skipped in rendering.""" # Comments and processing instructions should be skipped. xml_str = textwrap.dedent( """\ """ ) # Create the problem problem = new_loncapa_problem(xml_str) # Render the HTML the_html = problem.get_html() self.assertRegex(the_html, r"
\s*
") def _create_test_file(self, path, content_str): """Create a temporary test file with the given content and schedule cleanup.""" test_fp = self.capa_system.resources_fs.open(path, "w") test_fp.write(content_str) test_fp.close() self.addCleanup(lambda: os.remove(test_fp.name))