diff --git a/odoo/addons/base/models/ir_ui_view.py b/odoo/addons/base/models/ir_ui_view.py index b337f6a509b..c69f3f71bb3 100644 --- a/odoo/addons/base/models/ir_ui_view.py +++ b/odoo/addons/base/models/ir_ui_view.py @@ -1927,7 +1927,12 @@ actual arch. if not attrs.intersection(descendant.attrib): continue self._pop_view_branding(descendant) - # TODO: find a better name and check if we have a string to boolean helper + + # Remove the processing instructions indicating where nodes were + # removed (see apply_inheritance_specs) + for descendant in e.iterdescendants(tag=etree.ProcessingInstruction): + if descendant.target == 'apply-inheritance-specs-node-removal': + descendant.getparent().remove(descendant) return node_path = e.get('data-oe-xpath') diff --git a/odoo/addons/base/tests/test_views.py b/odoo/addons/base/tests/test_views.py index c1579f15dd5..71fbb699e13 100644 --- a/odoo/addons/base/tests/test_views.py +++ b/odoo/addons/base/tests/test_views.py @@ -950,6 +950,73 @@ class TestTemplating(ViewCase): initial.get('data-oe-xpath'), "The node's xpath position should be correct") + def test_branding_inherit_remove_node_processing_instruction(self): + view1 = self.View.create({ + 'name': "Base view", + 'type': 'qweb', + 'arch': """ + + + + + + + + + """ + }) + self.View.create({ + 'name': "Extension", + 'type': 'qweb', + 'inherit_id': view1.id, + 'arch': """ + + + + + """ + }) + + arch_string = view1.with_context(inherit_branding=True).get_combined_arch() + arch = etree.fromstring(arch_string) + + head = arch.xpath('//head')[0] + head_child = head[0] + self.assertEqual( + head_child.target, + 'apply-inheritance-specs-node-removal', + "A node was removed at the start of the , a processing instruction should exist as first child node") + self.assertEqual( + head_child.text, + 'hello', + "The processing instruction should mention the tag of the node that was removed") + + body = arch.xpath('//body')[0] + body_child = body[0] + self.assertEqual( + body_child.target, + 'apply-inheritance-specs-node-removal', + "A node was removed at the start of the , a processing instruction should exist as first child node") + self.assertEqual( + body_child.text, + 'world', + "The processing instruction should mention the tag of the node that was removed") + + self.View.distribute_branding(arch) + + # Test that both head and body have their processing instruction + # 'apply-inheritance-specs-node-removal' removed after branding + # distribution. Note: test head and body separately as the code in + # charge of the removal is different in each case. + self.assertEqual( + len(head), + 0, + "The processing instruction of the should have been removed") + self.assertEqual( + len(body), + 0, + "The processing instruction of the should have been removed") + def test_branding_inherit_top_t_field(self): view1 = self.View.create({ 'name': "Base view",