[IMP] tool, website, website_sale: move test utils functions
We have multiple ways of simulating a frontend context while running python tests (mainly during TransactionCase): - `MockObject` class from8557bcfa30- `simulate_frontend_context` method froma5a5a57e48- `DotDict` fromf8efc9a957This commit moves `MockObject` to misc to be reusable and adapt it to be accessible by dot notation with `DotDict`. Part of #34396
This commit is contained in:
@@ -2,10 +2,9 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import re
|
||||
import werkzeug
|
||||
|
||||
import odoo
|
||||
from odoo import tools
|
||||
from odoo.addons.website.tools import MockRequest
|
||||
from odoo.modules.module import get_module_resource
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
@@ -66,42 +65,6 @@ class TestQweb(TransactionCase):
|
||||
"user_id": demo.id,
|
||||
}).encode('utf8'))
|
||||
|
||||
class MockObject(object):
|
||||
_log_call = []
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.__dict__ = kwargs
|
||||
def __call__(self, *args, **kwargs):
|
||||
self._log_call.append((args, kwargs))
|
||||
return self
|
||||
def __getitem__(self, index):
|
||||
return self
|
||||
|
||||
def werkzeugRaiseNotFound(*args, **kwargs):
|
||||
raise werkzeug.exceptions.NotFound()
|
||||
|
||||
class MockRequest(object):
|
||||
""" Class with context manager mocking odoo.http.request for tests """
|
||||
def __init__(self, env, website=None, context=None, multilang=True, routing=True):
|
||||
app = MockObject(routing={
|
||||
'type': 'http',
|
||||
'website': True,
|
||||
'multilang': multilang,
|
||||
})
|
||||
app.get_db_router = app.bind = app.match = app
|
||||
if not routing:
|
||||
app.match = werkzeugRaiseNotFound
|
||||
self.request = MockObject(
|
||||
env=env, context=context or {}, db=None, debug=False,
|
||||
website=website, httprequest=MockObject(
|
||||
path='/hello/',
|
||||
app=app
|
||||
)
|
||||
)
|
||||
odoo.http._request_stack.push(self.request)
|
||||
def __enter__(self):
|
||||
return self.request
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
odoo.http._request_stack.pop()
|
||||
|
||||
class TestQwebProcessAtt(TransactionCase):
|
||||
def setUp(self):
|
||||
@@ -128,7 +91,7 @@ class TestQwebProcessAtt(TransactionCase):
|
||||
self._test_att('/a', {'href': '/a'})
|
||||
|
||||
def test_process_att_no_website(self):
|
||||
with MockRequest(self.env) as request:
|
||||
with MockRequest(self.env):
|
||||
# no website so URL rewriting
|
||||
self._test_att('/', {'href': '/'})
|
||||
self._test_att('/en_US/', {'href': '/en_US/'})
|
||||
@@ -137,7 +100,7 @@ class TestQwebProcessAtt(TransactionCase):
|
||||
self._test_att('/a', {'href': '/a'})
|
||||
|
||||
def test_process_att_monolang_route(self):
|
||||
with MockRequest(self.env, website=self.website, multilang=False) as request:
|
||||
with MockRequest(self.env, website=self.website, multilang=False):
|
||||
# lang not changed in URL but CDN enabled
|
||||
self._test_att('/a', {'href': 'http://test.cdn/a'})
|
||||
self._test_att('/en_US/a', {'href': 'http://test.cdn/en_US/a'})
|
||||
@@ -145,19 +108,19 @@ class TestQwebProcessAtt(TransactionCase):
|
||||
self._test_att('/en_US/b', {'href': '/en_US/b'})
|
||||
|
||||
def test_process_att_no_request_lang(self):
|
||||
with MockRequest(self.env, self.website) as request:
|
||||
with MockRequest(self.env, website=self.website):
|
||||
self._test_att('/', {'href': '/'})
|
||||
self._test_att('/en_US/', {'href': '/'})
|
||||
self._test_att('/fr_FR/', {'href': '/fr_FR/'})
|
||||
|
||||
def test_process_att_with_request_lang(self):
|
||||
with MockRequest(self.env, self.website, context={'lang': 'fr_FR'}) as request:
|
||||
with MockRequest(self.env, website=self.website, context={'lang': 'fr_FR'}):
|
||||
self._test_att('/', {'href': '/fr_FR/'})
|
||||
self._test_att('/en_US/', {'href': '/'})
|
||||
self._test_att('/fr_FR/', {'href': '/fr_FR/'})
|
||||
|
||||
def test_process_att_matching_cdn_and_lang(self):
|
||||
with MockRequest(self.env, self.website) as request:
|
||||
with MockRequest(self.env, website=self.website):
|
||||
# lang prefix is added before CDN
|
||||
self._test_att('/a', {'href': 'http://test.cdn/a'})
|
||||
self._test_att('/en_US/a', {'href': 'http://test.cdn/a'})
|
||||
@@ -167,13 +130,13 @@ class TestQwebProcessAtt(TransactionCase):
|
||||
self._test_att('/fr_FR/b', {'href': '/fr_FR/b'})
|
||||
|
||||
def test_process_att_no_route(self):
|
||||
with MockRequest(self.env, self.website, context={'lang': 'fr_FR'}, routing=False) as request:
|
||||
with MockRequest(self.env, website=self.website, context={'lang': 'fr_FR'}, routing=False):
|
||||
# default on multilang=True if route is not /{module}/static/
|
||||
self._test_att('/web/static/hi', {'href': '/web/static/hi'})
|
||||
self._test_att('/my-page', {'href': '/fr_FR/my-page'})
|
||||
|
||||
def test_process_att_url_crap(self):
|
||||
with MockRequest(self.env, self.website) as request:
|
||||
with MockRequest(self.env, website=self.website) as request:
|
||||
# #{fragment} is stripped from URL when testing route
|
||||
self._test_att('/x#y?z', {'href': '/x#y?z'})
|
||||
self.assertEqual(
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import odoo
|
||||
import werkzeug
|
||||
|
||||
from odoo.tools import DotDict
|
||||
|
||||
|
||||
class MockObject(object):
|
||||
_log_call = []
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.__dict__ = kwargs
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
self._log_call.append((args, kwargs))
|
||||
return self
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self
|
||||
|
||||
|
||||
def werkzeugRaiseNotFound(*args, **kwargs):
|
||||
raise werkzeug.exceptions.NotFound()
|
||||
|
||||
|
||||
class MockRequest(object):
|
||||
""" Class with context manager mocking odoo.http.request for tests """
|
||||
def __init__(self, env, **kw):
|
||||
app = MockObject(routing={
|
||||
'type': 'http',
|
||||
'website': True,
|
||||
'multilang': kw.get('multilang', True),
|
||||
})
|
||||
app.get_db_router = app.bind = app.match = app
|
||||
if not kw.get('routing', True):
|
||||
app.match = werkzeugRaiseNotFound
|
||||
self.request = DotDict({
|
||||
'context': kw.get('context', {}),
|
||||
'db': None,
|
||||
'debug': False,
|
||||
'env': env,
|
||||
'httprequest': {
|
||||
'path': '/hello/',
|
||||
'app': app,
|
||||
},
|
||||
'redirect': werkzeug.utils.redirect,
|
||||
'session': {
|
||||
'sale_order_id': kw.get('sale_order_id'),
|
||||
},
|
||||
'website': kw.get('website'),
|
||||
})
|
||||
odoo.http._request_stack.push(self.request)
|
||||
|
||||
def __enter__(self):
|
||||
return self.request
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
odoo.http._request_stack.pop()
|
||||
@@ -5,6 +5,7 @@ try:
|
||||
except ImportError:
|
||||
from mock import patch
|
||||
from odoo.tests.common import HttpCase, TransactionCase
|
||||
from odoo.tools import DotDict
|
||||
|
||||
''' /!\/!\
|
||||
Calling `get_pricelist_available` after setting `property_product_pricelist` on
|
||||
@@ -154,13 +155,6 @@ def simulate_frontend_context(self, website_id=1):
|
||||
self.addCleanup(patcher.stop)
|
||||
|
||||
|
||||
class DotDict(dict):
|
||||
"""dot.notation access to dictionary attributes"""
|
||||
def __getattr__(*args):
|
||||
val = dict.get(*args)
|
||||
return DotDict(val) if type(val) is dict else val
|
||||
|
||||
|
||||
class TestWebsitePriceListAvailable(TransactionCase):
|
||||
# This is enough to avoid a mock (request.session/website do not exist during test)
|
||||
def get_pricelist_available(self, show_visible=False, website_id=1, country_code=None, website_sale_current_pl=None):
|
||||
|
||||
@@ -1242,3 +1242,14 @@ def wrap_module(module, attr_list):
|
||||
raise AttributeError(attrib)
|
||||
# module and attr_list are in the closure
|
||||
return WrappedModule()
|
||||
|
||||
|
||||
class DotDict(dict):
|
||||
"""Helper for dot.notation access to dictionary attributes
|
||||
E.g.
|
||||
foo = DotDict({'bar': False})
|
||||
return foo.bar
|
||||
"""
|
||||
def __getattr__(self, attrib):
|
||||
val = self.get(attrib)
|
||||
return DotDict(val) if type(val) is dict else val
|
||||
|
||||
Reference in New Issue
Block a user