1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from collections import OrderedDict
from lxml import etree
from odoo.fields import Command
from odoo.tests import HttpCase, TransactionCase, loaded_demo_data, tagged
_logger = logging.getLogger(__name__)
@tagged('-at_install', 'post_install')
class TestWebsiteSaleComparison(TransactionCase):
def test_01_website_sale_comparison_remove(self):
""" This tour makes sure the product page still works after the module
`website_sale_comparison` has been removed.
Technically it tests the removal of copied views by the base method
`_remove_copied_views`. The problematic view that has to be removed is
`product_attributes_body` because it has a reference to `add_to_compare`.
"""
# YTI TODO: Adapt this tour without demo data
# I still didn't figure why, but this test freezes on runbot
# without the demo data
if not loaded_demo_data(self.env):
_logger.warning("This test relies on demo data. To be rewritten independently of demo data for accurate and reliable results.")
return
Website0 = self.env['website'].with_context(website_id=None)
Website1 = self.env['website'].with_context(website_id=1)
# Create a generic inherited view, with a key not starting with
# `website_sale_comparison` otherwise the unlink will work just based on
# the key, but we want to test also for `MODULE_UNINSTALL_FLAG`.
product_attributes_body = Website0.viewref('website_sale_comparison.product_attributes_body')
test_view_key = 'my_test.my_key'
self.env['ir.ui.view'].with_context(website_id=None).create({
'name': 'test inherited view',
'key': test_view_key,
'inherit_id': product_attributes_body.id,
'arch': '<div/>',
})
# Retrieve the generic view
product = Website0.viewref('website_sale.product')
# Trigger COW to create specific views of the whole tree
product.with_context(website_id=1).write({'name': 'Trigger COW'})
# Verify initial state: the specific views exist
self.assertEqual(Website1.viewref('website_sale.product').website_id.id, 1)
self.assertEqual(Website1.viewref('website_sale_comparison.product_attributes_body').website_id.id, 1)
self.assertEqual(Website1.viewref(test_view_key).website_id.id, 1)
# Remove the module (use `module_uninstall` because it is enough to test
# what we want here, no need/can't use `button_immediate_uninstall`
# because it would commit the test transaction)
website_sale_comparison = self.env['ir.module.module'].search([('name', '=', 'website_sale_comparison')])
website_sale_comparison.module_uninstall()
# Check that the generic view is correctly removed
self.assertFalse(Website0.viewref('website_sale_comparison.product_attributes_body', raise_if_not_found=False))
# Check that the specific view is correctly removed
self.assertFalse(Website1.viewref('website_sale_comparison.product_attributes_body', raise_if_not_found=False))
# Check that the generic inherited view is correctly removed
self.assertFalse(Website0.viewref(test_view_key, raise_if_not_found=False))
# Check that the specific inherited view is correctly removed
self.assertFalse(Website1.viewref(test_view_key, raise_if_not_found=False))
@tagged('post_install', '-at_install')
class TestWebsiteSaleComparisonUi(HttpCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.attribute_varieties = cls.env['product.attribute'].create({
'name': 'Grape Varieties',
'sequence': 2,
'value_ids': [
Command.create({
'name': n,
'sequence': i,
}) for i, n in enumerate(['Cabernet Sauvignon', 'Merlot', 'Cabernet Franc', 'Petit Verdot'])
],
})
cls.attribute_vintage = cls.env['product.attribute'].create({
'name': 'Vintage',
'sequence': 1,
'value_ids': [
Command.create({
'name': n,
'sequence': i,
}) for i, n in enumerate(['2018', '2017', '2016', '2015'])
],
})
cls.values_varieties = cls.attribute_varieties.value_ids
cls.values_vintage = cls.attribute_vintage.value_ids
cls.template_margaux = cls.env['product.template'].create({
'name': "Château Margaux",
'website_published': True,
'list_price': 0,
'attribute_line_ids': [
Command.create({
'attribute_id': cls.attribute_vintage.id,
'value_ids': [Command.set(cls.values_vintage.ids)]
})
]
})
cls.attribute_line_vintage = cls.template_margaux.attribute_line_ids
cls.attribute_line_varieties = cls.env['product.template.attribute.line'].create([{
'product_tmpl_id': cls.template_margaux.id,
'attribute_id': cls.attribute_varieties.id,
'value_ids': [(6, 0, v.ids)],
} for v in cls.values_varieties])
cls.variants_margaux = cls.template_margaux._get_possible_variants_sorted()
for variant, price in zip(cls.variants_margaux, [487.32, 394.05, 532.44, 1047.84]):
variant.product_template_attribute_value_ids.filtered(lambda ptav: ptav.attribute_id == cls.attribute_vintage).price_extra = price
def test_01_admin_tour_product_comparison(self):
# YTI FIXME: Adapt to work without demo data
if not loaded_demo_data(self.env):
_logger.warning("This test relies on demo data. To be rewritten independently of demo data for accurate and reliable results.")
return
self.start_tour("/", 'product_comparison', login='admin')
def test_02_attribute_multiple_lines(self):
# Case product page with "Product attributes table" disabled (website_sale standard case)
self.env['website'].viewref('website_sale_comparison.product_attributes_body').active = False
res = self.url_open('/shop/%d' % self.template_margaux.id)
self.assertEqual(res.status_code, 200)
root = etree.fromstring(res.content, etree.HTMLParser())
tr_varieties_simple_att = root.xpath('//div[@id="product_attributes_simple"]//tr')[0]
text = etree.tostring(tr_varieties_simple_att, encoding='unicode', method='text')
self.assertEqual(text.replace(' ', '').replace('\n', ''), "GrapeVarieties:CabernetSauvignon,Merlot,CabernetFranc,PetitVerdot")
# Case product page with "Product attributes table" enabled
self.env['website'].viewref('website_sale_comparison.product_attributes_body').active = True
res = self.url_open('/shop/%d' % self.template_margaux.id)
self.assertEqual(res.status_code, 200)
root = etree.fromstring(res.content, etree.HTMLParser())
tr_vintage = root.xpath('//div[@id="product_specifications"]//tr')[0]
text_vintage = etree.tostring(tr_vintage, encoding='unicode', method='text')
self.assertEqual(text_vintage.replace(' ', '').replace('\n', ''), "Vintage2018,2017,2016,2015")
tr_varieties = root.xpath('//div[@id="product_specifications"]//tr')[1]
text_varieties = etree.tostring(tr_varieties, encoding='unicode', method='text')
self.assertEqual(text_varieties.replace(' ', '').replace('\n', ''), "GrapeVarietiesCabernetSauvignon,Merlot,CabernetFranc,PetitVerdot")
# Case compare page
res = self.url_open('/shop/compare?products=%s' % ','.join(str(id) for id in self.variants_margaux.ids))
self.assertEqual(res.status_code, 200)
root = etree.fromstring(res.content, etree.HTMLParser())
table = root.xpath('//table[@id="o_comparelist_table"]')[0]
products = table.xpath('//a[@class="o_product_comparison_table"]')
self.assertEqual(len(products), 4)
for product, name in zip(products, ['ChâteauMargaux(2018)', 'ChâteauMargaux(2017)', 'ChâteauMargaux(2016)', 'ChâteauMargaux(2015)']):
text = etree.tostring(product, encoding='unicode', method='text')
self.assertEqual(text.replace(' ', '').replace('\n', ''), name)
tr_vintage = table.xpath('tbody/tr')[0]
text_vintage = etree.tostring(tr_vintage, encoding='unicode', method='text')
self.assertEqual(text_vintage.replace(' ', '').replace('\n', ''), "Vintage2018,2017,2016,20152018,2017,2016,20152018,2017,2016,20152018,2017,2016,2015")
tr_varieties = table.xpath('tbody/tr')[1]
text_varieties = etree.tostring(tr_varieties, encoding='unicode', method='text')
self.assertEqual(text_varieties.replace(' ', '').replace('\n', ''), "GrapeVarieties" + 4 * "CabernetSauvignon,Merlot,CabernetFranc,PetitVerdot")
def test_03_category_order(self):
"""Test that categories are shown in the correct order when the
attributes are in a different order."""
category_vintage = self.env['product.attribute.category'].create({
'name': 'Vintage',
'sequence': 2,
})
category_varieties = self.env['product.attribute.category'].create({
'name': 'Varieties',
'sequence': 1,
})
self.attribute_vintage.category_id = category_vintage
self.attribute_varieties.category_id = category_varieties
prep_categories = self.template_margaux.valid_product_template_attribute_line_ids._prepare_categories_for_display()
self.assertEqual(prep_categories, OrderedDict([
(category_varieties, self.attribute_line_varieties),
(category_vintage, self.attribute_line_vintage),
]))
prep_categories = self.variants_margaux[0]._prepare_categories_for_display()
self.assertEqual(prep_categories, OrderedDict([
(category_varieties, OrderedDict([
(self.attribute_varieties, OrderedDict([
(self.template_margaux.product_variant_id, self.attribute_line_varieties.value_ids)
]))
])),
(category_vintage, OrderedDict([
(self.attribute_vintage, OrderedDict([
(self.template_margaux.product_variant_id, self.attribute_line_vintage.value_ids)
]))
])),
]))
|