test_xml_tools.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. # -*- coding: utf-8 -*-
  2. # Part of Odoo. See LICENSE file for full copyright and licensing details.
  3. from lxml import etree
  4. from odoo.tests import common
  5. from odoo.tools.xml_utils import cleanup_xml_node
  6. class TestXMLTools(common.TransactionCase):
  7. def setUp(self):
  8. super(TestXMLTools, self).setUp()
  9. self.qweb_poor = self.env()['ir.ui.view'].create({
  10. 'type': 'qweb',
  11. 'arch_db': """
  12. <h1>
  13. <h2/>
  14. <h2>text</h2>
  15. \t<h2><h3/></h2>
  16. <h2> </h2>
  17. <!-- comment removed by qweb -->
  18. </h1>"""})
  19. def test_cleanup_xml_node_no_modif(self):
  20. # Qweb removes comments and any whitespace before first tag, no other content affected
  21. expected = """<h1>
  22. <h2/>
  23. <h2>text</h2>
  24. \t<h2><h3/></h2>
  25. <h2> </h2>
  26. </h1>"""
  27. qweb = self.env['ir.qweb']._render(self.qweb_poor.id)
  28. self.check_xml_cleanup_result_is_as_expected(qweb, expected, remove_blank_text=False, remove_blank_nodes=False, indent_level=-1)
  29. def test_cleanup_xml_node_indent_level(self):
  30. # Indentation level and spacing works as expected, nothing else affected
  31. # (quirk: first tag not indented because indent is actually previous tag's tail)
  32. expected = """<h1>
  33. __<h2/>
  34. __<h2>text</h2>
  35. __<h2>
  36. ___<h3/>
  37. __</h2>
  38. __<h2> </h2>
  39. _</h1>
  40. """
  41. qweb = self.env['ir.qweb']._render(self.qweb_poor.id)
  42. self.check_xml_cleanup_result_is_as_expected(qweb, expected, remove_blank_text=False, remove_blank_nodes=False, indent_level=1, indent_space="_")
  43. def test_cleanup_xml_node_keep_blank_text(self):
  44. # Blank nodes are removed but not nodes containing blank text
  45. expected = """<h1>
  46. <h2>text</h2>
  47. <h2> </h2>
  48. </h1>
  49. """
  50. qweb = self.env['ir.qweb']._render(self.qweb_poor.id)
  51. self.check_xml_cleanup_result_is_as_expected(qweb, expected, remove_blank_text=False)
  52. def test_cleanup_xml_node_keep_blank_nodes(self):
  53. # Blank text is removed but blank (empty) nodes remain
  54. expected = """<h1>
  55. <h2/>
  56. <h2>text</h2>
  57. <h2>
  58. <h3/>
  59. </h2>
  60. <h2></h2>
  61. </h1>
  62. """
  63. qweb = self.env['ir.qweb']._render(self.qweb_poor.id)
  64. self.check_xml_cleanup_result_is_as_expected(qweb, expected, remove_blank_nodes=False)
  65. def test_cleanup_xml_t_call_indent(self):
  66. # Indentation is fixed after t-call (which keeps indentation of called template)
  67. template_1 = self.env['ir.ui.view'].create({
  68. 'type': 'qweb',
  69. 'arch_db': '''<h1>
  70. <content>This is content!</content>
  71. </h1>
  72. '''})
  73. template_2 = self.env['ir.ui.view'].create({
  74. 'name': 'test',
  75. 'type': 'qweb',
  76. 'arch_db': f'''<odoo>
  77. <data>
  78. <t t-call="{template_1.id}"/>
  79. </data>
  80. </odoo>
  81. '''})
  82. expected = """<odoo>
  83. <data>
  84. <h1>
  85. <content>This is content!</content>
  86. </h1>
  87. </data>
  88. </odoo>
  89. """
  90. qweb = self.env['ir.qweb']._render(template_2.id)
  91. self.check_xml_cleanup_result_is_as_expected(qweb, expected)
  92. def test_qweb_render_values_empty_nodes(self):
  93. # Indentation is fixed and empty nodes are removed after conditional rendering
  94. template_addresses = self.env['ir.ui.view'].create({
  95. 'type': 'qweb',
  96. 'arch_db': '''<t>
  97. <street t-esc="address.get('street')"/>
  98. <number t-esc="address.get('number')"/>
  99. <city t-esc="address.get('city')"/>
  100. </t>
  101. '''})
  102. template_main = self.env['ir.ui.view'].create({
  103. 'type': 'qweb',
  104. 'arch_db': f'''<data>
  105. <item t-foreach="items" t-as="item" t-esc="item"/>
  106. <addressSender t-call='{template_addresses.id}'>
  107. <t t-set="address" t-value="addressSender"/>
  108. </addressSender>
  109. <addressRecipient t-call='{template_addresses.id}'>
  110. <t t-set="address" t-value="addressRecipient"/>
  111. </addressRecipient>
  112. </data>
  113. '''})
  114. expected = """<data>
  115. <item>1</item>
  116. <item>2</item>
  117. <item>Three</item>
  118. <addressRecipient>
  119. <street>Baker street</street>
  120. <number>221B</number>
  121. <city>London</city>
  122. </addressRecipient>
  123. </data>
  124. """
  125. qweb = self.env['ir.qweb']._render(template_main.id, {
  126. 'items': [1, 2, "Three", False],
  127. 'addressRecipient': {
  128. 'number': '221B',
  129. 'street': 'Baker street',
  130. 'city': 'London',
  131. },
  132. 'addressSender': {
  133. 'street': ' '
  134. }
  135. })
  136. self.check_xml_cleanup_result_is_as_expected(qweb, expected)
  137. def check_xml_cleanup_result_is_as_expected(self, original_string, expected_string, **kwargs):
  138. result_string = etree.tostring(cleanup_xml_node(original_string, **kwargs)).decode()
  139. self.assertEqual(expected_string, result_string)
  140. self.assertNotEqual(expected_string, original_string)