mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-20 02:12:01 +02:00
vanilla 17.0
This commit is contained in:
parent
d72e748793
commit
a9bcec8e91
1986 changed files with 1613876 additions and 568976 deletions
|
|
@ -9,6 +9,7 @@ from . import test_menu
|
|||
from . import test_click_everywhere
|
||||
from . import test_base_document_layout
|
||||
from . import test_load_menus
|
||||
from . import test_partner
|
||||
from . import test_profiler
|
||||
from . import test_session_info
|
||||
from . import test_read_progress_bar
|
||||
|
|
@ -16,6 +17,11 @@ from . import test_assets
|
|||
from . import test_assets_xml
|
||||
from . import test_login
|
||||
from . import test_web_search_read
|
||||
from . import test_web_read_group
|
||||
from . import test_domain
|
||||
from . import test_translate
|
||||
from . import test_web_redirect
|
||||
from . import test_res_users
|
||||
from . import test_webmanifest
|
||||
from . import test_ir_qweb
|
||||
from . import test_reports
|
||||
|
|
|
|||
|
|
@ -17,26 +17,31 @@ _logger = logging.getLogger(__name__)
|
|||
|
||||
class TestAssetsGenerateTimeCommon(odoo.tests.TransactionCase):
|
||||
|
||||
def generate_bundles(self):
|
||||
self.env['ir.attachment'].search([('url', '=like', '/web/assets/%')]).unlink() # delete existing attachement
|
||||
def generate_bundles(self, unlink=True):
|
||||
if unlink:
|
||||
self.env['ir.attachment'].search([('url', '=like', '/web/assets/%')]).unlink() # delete existing attachement
|
||||
installed_module_names = self.env['ir.module.module'].search([('state', '=', 'installed')]).mapped('name')
|
||||
bundles = {
|
||||
key
|
||||
for module in installed_module_names
|
||||
for key in get_manifest(module)['assets']
|
||||
for key in get_manifest(module).get('assets', [])
|
||||
}
|
||||
|
||||
for bundle in bundles:
|
||||
for bundle_name in bundles:
|
||||
with mute_logger('odoo.addons.base.models.assetsbundle'):
|
||||
for assets_type in 'css', 'js':
|
||||
try:
|
||||
start_t = time.time()
|
||||
css = assets_type == 'css'
|
||||
js = assets_type == 'js'
|
||||
self.env['ir.qweb']._generate_asset_nodes(bundle, css=css, js=js)
|
||||
yield (f'{bundle}.{assets_type}', time.time() - start_t)
|
||||
bundle = self.env['ir.qweb']._get_asset_bundle(bundle_name, css=css, js=js)
|
||||
if assets_type == 'css' and bundle.stylesheets:
|
||||
bundle.css()
|
||||
if assets_type == 'js' and bundle.javascripts:
|
||||
bundle.js()
|
||||
yield (f'{bundle_name}.{assets_type}', time.time() - start_t)
|
||||
except ValueError:
|
||||
_logger.info('Error detected while generating bundle %r %s', bundle, assets_type)
|
||||
_logger.info('Error detected while generating bundle %r %s', bundle_name, assets_type)
|
||||
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install', 'assets_bundle')
|
||||
|
|
@ -47,9 +52,33 @@ class TestLogsAssetsGenerateTime(TestAssetsGenerateTimeCommon):
|
|||
The purpose of this test is to monitor the time of assets bundle generation.
|
||||
This is not meant to test the generation failure, hence the try/except and the mute logger.
|
||||
"""
|
||||
for bundle, duration in self.generate_bundles():
|
||||
for bundle, duration in list(self.generate_bundles()):
|
||||
_logger.info('Bundle %r generated in %.2fs', bundle, duration)
|
||||
|
||||
def test_logs_assets_check_time(self):
|
||||
"""
|
||||
The purpose of this test is to monitor the time of assets bundle generation.
|
||||
This is not meant to test the generation failure, hence the try/except and the mute logger.
|
||||
"""
|
||||
start = time.time()
|
||||
for bundle, duration in self.generate_bundles(False):
|
||||
_logger.info('Bundle %r checked in %.2fs', bundle, duration)
|
||||
duration = time.time() - start
|
||||
_logger.info('All bundle checked in %.2fs', duration)
|
||||
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install', '-standard', 'test_assets')
|
||||
class TestPregenerateTime(HttpCase):
|
||||
|
||||
def test_logs_pregenerate_time(self):
|
||||
self.env['ir.qweb']._pregenerate_assets_bundles()
|
||||
start = time.time()
|
||||
self.env.registry.clear_cache()
|
||||
self.env.cache.invalidate()
|
||||
with self.profile(collectors=['sql', odoo.tools.profiler.PeriodicCollector(interval=0.01)], disable_gc=True):
|
||||
self.env['ir.qweb']._pregenerate_assets_bundles()
|
||||
duration = time.time() - start
|
||||
_logger.info('All bundle checked in %.2fs', duration)
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install', '-standard', 'assets_bundle')
|
||||
class TestAssetsGenerateTime(TestAssetsGenerateTimeCommon):
|
||||
|
|
@ -73,6 +102,7 @@ class TestAssetsGenerateTime(TestAssetsGenerateTimeCommon):
|
|||
class TestLoad(HttpCase):
|
||||
def test_assets_already_exists(self):
|
||||
self.authenticate('admin', 'admin')
|
||||
# TODO xdo adapt this test. url open won't generate attachment anymore even if not pregenerated
|
||||
_save_attachment = odoo.addons.base.models.assetsbundle.AssetsBundle.save_attachment
|
||||
|
||||
def save_attachment(bundle, extension, content):
|
||||
|
|
|
|||
|
|
@ -63,19 +63,13 @@ class TestStaticInheritanceCommon(odoo.tests.TransactionCase):
|
|||
def renderBundle(self, debug=False):
|
||||
files = []
|
||||
for url in self.template_files:
|
||||
atype = 'text/xml'
|
||||
if '.js' in url:
|
||||
atype = 'text/javascript'
|
||||
files.append({
|
||||
'atype': atype,
|
||||
'url': url,
|
||||
'filename': url,
|
||||
'content': None,
|
||||
'media': None,
|
||||
})
|
||||
asset = AssetsBundle('web.test_bundle', files, env=self.env, css=False, js=True)
|
||||
# to_node return the files descriptions and generate attachments.
|
||||
asset.to_node(css=False, js=False, debug=debug and 'assets' or '')
|
||||
asset = AssetsBundle('web.test_bundle', files, env=self.env, css=False, js=True, debug_assets=debug)
|
||||
content = asset.xml(show_inherit_info=debug)
|
||||
return f'<templates xml:space="preserve">\n{content}\n</templates>'
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
import logging
|
||||
import odoo.tests
|
||||
|
||||
from datetime import datetime
|
||||
from odoo.addons.base.tests.common import HttpCaseWithUserDemo
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -15,12 +18,11 @@ class TestMenusAdmin(odoo.tests.HttpCase):
|
|||
for app_id in menus['root']['children']:
|
||||
with self.subTest(app=menus[app_id]['name']):
|
||||
_logger.runbot('Testing %s', menus[app_id]['name'])
|
||||
self.browser_js("/web", "odoo.__DEBUG__.services['web.clickEverywhere']('%s');" % menus[app_id]['xmlid'], "odoo.isReady === true", login="admin", timeout=600)
|
||||
self.terminate_browser()
|
||||
self.browser_js("/web", "odoo.loader.modules.get('@web/webclient/clickbot/clickbot_loader').startClickEverywhere('%s');" % menus[app_id]['xmlid'], "odoo.isReady === true", login="admin", timeout=1200)
|
||||
|
||||
|
||||
@odoo.tests.tagged('click_all', 'post_install', '-at_install', '-standard')
|
||||
class TestMenusDemo(odoo.tests.HttpCase):
|
||||
class TestMenusDemo(HttpCaseWithUserDemo):
|
||||
allow_end_on_form = True
|
||||
def test_01_click_everywhere_as_demo(self):
|
||||
user_demo = self.env.ref("base.user_demo")
|
||||
|
|
@ -28,16 +30,35 @@ class TestMenusDemo(odoo.tests.HttpCase):
|
|||
for app_id in menus['root']['children']:
|
||||
with self.subTest(app=menus[app_id]['name']):
|
||||
_logger.runbot('Testing %s', menus[app_id]['name'])
|
||||
self.browser_js("/web", "odoo.__DEBUG__.services['web.clickEverywhere']('%s');" % menus[app_id]['xmlid'], "odoo.isReady === true", login="demo", timeout=600)
|
||||
self.terminate_browser()
|
||||
self.browser_js("/web", "odoo.loader.modules.get('@web/webclient/clickbot/clickbot_loader').startClickEverywhere('%s');" % menus[app_id]['xmlid'], "odoo.isReady === true", login="demo", timeout=1200)
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install')
|
||||
class TestMenusAdminLight(odoo.tests.HttpCase):
|
||||
allow_end_on_form = True
|
||||
def test_01_click_apps_menus_as_admin(self):
|
||||
self.browser_js("/web", "odoo.__DEBUG__.services['web.clickEverywhere'](undefined, true);", "odoo.isReady === true", login="admin", timeout=120)
|
||||
# Due to action_pos_preparation_display_kitchen_display, cliking on the "Kitchen Display"
|
||||
# menuitem could open the UI display, which will break the crawler tests as there is no
|
||||
# way for the tour to be executed, leading to a timeout
|
||||
if 'pos_preparation_display.display' in self.env:
|
||||
self.env['pos_preparation_display.display'].create({
|
||||
'name': 'Super Smart Kitchen Display',
|
||||
})
|
||||
# There is a bug when we go the Field Service app (without any demo data) and we
|
||||
# click on the Studio button. It seems the fake group generated containing one record
|
||||
# to be used in the KanbanEditorRenderer has groupByField to undefined
|
||||
# (I guess it is because there is no group by?) and we got an error at this line
|
||||
# because we assume groupByField is defined.
|
||||
if 'project.task' in self.env and 'is_fsm' in self.env['project.task']:
|
||||
self.env['project.task'].create({
|
||||
'name': 'Zizizbroken',
|
||||
'project_id': self.env.ref('industry_fsm.fsm_project').id,
|
||||
'user_ids': [(4, self.env.ref('base.user_admin').id)],
|
||||
'date_deadline': datetime.now() + relativedelta(hour=12),
|
||||
'planned_date_begin': datetime.now() + relativedelta(hour=10),
|
||||
})
|
||||
self.browser_js("/web", "odoo.loader.modules.get('@web/webclient/clickbot/clickbot_loader').startClickEverywhere(undefined, true);", "odoo.isReady === true", login="admin", timeout=120)
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install',)
|
||||
@odoo.tests.tagged('post_install', '-at_install')
|
||||
class TestMenusDemoLight(HttpCaseWithUserDemo):
|
||||
allow_end_on_form = True
|
||||
|
||||
|
|
@ -47,4 +68,4 @@ class TestMenusDemoLight(HttpCaseWithUserDemo):
|
|||
group_website_designer = self.env.ref('website.group_website_designer', raise_if_not_found=False)
|
||||
if group_website_designer:
|
||||
self.env.ref('base.group_user').write({"implied_ids": [(4, group_website_designer.id)]})
|
||||
self.browser_js("/web", "odoo.__DEBUG__.services['web.clickEverywhere'](undefined, true);", "odoo.isReady === true", login="demo", timeout=120)
|
||||
self.browser_js("/web", "odoo.loader.modules.get('@web/webclient/clickbot/clickbot_loader').startClickEverywhere(undefined, true);", "odoo.isReady === true", login="demo", timeout=120)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import operator
|
||||
import re
|
||||
import secrets
|
||||
from io import BytesIO
|
||||
from unittest.mock import patch
|
||||
|
||||
import requests
|
||||
|
|
@ -68,6 +69,14 @@ class TestDatabaseOperations(BaseCase):
|
|||
def assertDbs(self, dbs):
|
||||
self.assertEqual(self.list_dbs_filtered() - self.base_databases, set(dbs))
|
||||
|
||||
def url_open_drop(self, dbname):
|
||||
res = self.session.post(self.url('/web/database/drop'), data={
|
||||
'master_pwd': self.password,
|
||||
'name': dbname,
|
||||
}, allow_redirects=False)
|
||||
res.raise_for_status()
|
||||
return res
|
||||
|
||||
def test_database_creation(self):
|
||||
# check verify_admin_password patch
|
||||
self.assertTrue(odoo.tools.config.verify_admin_password(self.password))
|
||||
|
|
@ -88,10 +97,7 @@ class TestDatabaseOperations(BaseCase):
|
|||
self.assertDbs([test_db_name])
|
||||
|
||||
# delete the created database
|
||||
res = self.session.post(self.url('/web/database/drop'), data={
|
||||
'master_pwd': self.password,
|
||||
'name': test_db_name,
|
||||
}, allow_redirects=False)
|
||||
res = self.url_open_drop(test_db_name)
|
||||
self.assertEqual(res.status_code, 303)
|
||||
self.assertIn('/web/database/manager', res.headers['Location'])
|
||||
self.assertDbs([])
|
||||
|
|
@ -110,10 +116,70 @@ class TestDatabaseOperations(BaseCase):
|
|||
self.assertDbs([test_db_name])
|
||||
|
||||
# delete the created database
|
||||
res = self.session.post(self.url('/web/database/drop'), data={
|
||||
'master_pwd': self.password,
|
||||
'name': test_db_name,
|
||||
}, allow_redirects=False)
|
||||
self.assertEqual(res.status_code, 303)
|
||||
res = self.url_open_drop(test_db_name)
|
||||
self.assertIn('/web/database/manager', res.headers['Location'])
|
||||
self.assertDbs([])
|
||||
|
||||
def test_database_restore(self):
|
||||
test_db_name = self.db_name + '-test-database-restore'
|
||||
self.assertNotIn(test_db_name, self.list_dbs_filtered())
|
||||
|
||||
# backup the current database inside a temporary zip file
|
||||
res = self.session.post(
|
||||
self.url('/web/database/backup'),
|
||||
data={
|
||||
'master_pwd': self.password,
|
||||
'name': self.db_name,
|
||||
},
|
||||
allow_redirects=False,
|
||||
stream=True,
|
||||
)
|
||||
res.raise_for_status()
|
||||
datetime_pattern = r'\d\d\d\d-\d\d-\d\d_\d\d-\d\d-\d\d'
|
||||
self.assertRegex(
|
||||
res.headers.get('Content-Disposition'),
|
||||
fr"attachment; filename\*=UTF-8''{self.db_name}_{datetime_pattern}\.zip"
|
||||
)
|
||||
backup_file = BytesIO()
|
||||
backup_file.write(res.content)
|
||||
self.assertGreater(backup_file.tell(), 0, "The backup seems corrupted")
|
||||
|
||||
# upload the backup under a new name (create a duplicate)
|
||||
with self.subTest(DEFAULT_MAX_CONTENT_LENGTH=None), \
|
||||
patch.object(odoo.http, 'DEFAULT_MAX_CONTENT_LENGTH', None):
|
||||
backup_file.seek(0)
|
||||
self.session.post(
|
||||
self.url('/web/database/restore'),
|
||||
data={
|
||||
'master_pwd': self.password,
|
||||
'name': test_db_name,
|
||||
'copy': True,
|
||||
},
|
||||
files={
|
||||
'backup_file': backup_file,
|
||||
},
|
||||
allow_redirects=False
|
||||
).raise_for_status()
|
||||
self.assertDbs([test_db_name])
|
||||
self.url_open_drop(test_db_name)
|
||||
|
||||
# upload the backup again, this time simulating that the file is
|
||||
# too large under the default size limit, the default size limit
|
||||
# shouldn't apply to /web/database URLs
|
||||
with self.subTest(DEFAULT_MAX_CONTENT_LENGTH=1024), \
|
||||
patch.object(odoo.http, 'DEFAULT_MAX_CONTENT_LENGTH', 1024):
|
||||
backup_file.seek(0)
|
||||
self.session.post(
|
||||
self.url('/web/database/restore'),
|
||||
data={
|
||||
'master_pwd': self.password,
|
||||
'name': test_db_name,
|
||||
'copy': True,
|
||||
},
|
||||
files={
|
||||
'backup_file': backup_file,
|
||||
},
|
||||
allow_redirects=False
|
||||
).raise_for_status()
|
||||
self.assertDbs([test_db_name])
|
||||
self.url_open_drop(test_db_name)
|
||||
|
|
|
|||
|
|
@ -63,3 +63,12 @@ class IrModelAccessTest(TransactionCase):
|
|||
# non existent model comes after existent model
|
||||
result = self.env['ir.model'].display_name_for(["res.company", "unexistent"])
|
||||
self.assertEqual(result, [{"display_name": "Companies", "model": "res.company"}, {"display_name": "unexistent", "model": "unexistent"}])
|
||||
# transient models
|
||||
result = self.env['ir.model'].display_name_for(["res.company", "base.language.export"])
|
||||
self.assertEqual(result, [{"display_name": "Companies", "model": "res.company"}, {"display_name": "base.language.export", "model": "base.language.export"}])
|
||||
|
||||
# do not return results for transient models
|
||||
result = self.env['ir.model'].get_available_models()
|
||||
result = {values["model"] for values in result}
|
||||
self.assertIn("res.company", result)
|
||||
self.assertNotIn("base.language.export", result)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import base64
|
||||
from lxml import etree
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.tools.mimetypes import guess_mimetype
|
||||
|
||||
class TestIrQweb(TransactionCase):
|
||||
def test_image_field(self):
|
||||
|
|
@ -28,3 +31,44 @@ class TestIrQweb(TransactionCase):
|
|||
self.assertTrue(img.get("src").startswith("/web/image"))
|
||||
self.assertEqual(img.get("class"), "img img-fluid")
|
||||
self.assertEqual(img.get("alt"), "test image partner")
|
||||
|
||||
def test_image_field_webp(self):
|
||||
webp = "UklGRsCpAQBXRUJQVlA4WAoAAAAQAAAAGAQA/wMAQUxQSMywAAAdNANp22T779/0RUREkvqLOTPesG1T21jatpLTSbpXQzTMEw3zWMM81jCPnWG2fTM7vpndvpkd38y2758Y+6a/Ld/Mt3zzT/XwzCKlV0Ooo61UpZIsKLjKc98R"
|
||||
webp_decoded = base64.b64decode(webp)
|
||||
self.assertEqual(guess_mimetype(webp_decoded), "image/webp")
|
||||
|
||||
view = self.env["ir.ui.view"].create({
|
||||
"key": "web.test_qweb",
|
||||
"type": "qweb",
|
||||
"arch": """<t t-name="test_qweb">
|
||||
<span t-field="record.flag_image" t-options-widget="'image'" t-options-qweb_img_raw_data="is_raw_image" />
|
||||
</t>"""
|
||||
})
|
||||
lang_record = self.env["res.lang"].create({
|
||||
"name": "test lang",
|
||||
"flag_image": webp,
|
||||
"code": "TEST"
|
||||
})
|
||||
attachment = self.env["ir.attachment"].search([
|
||||
("res_model", "=", "res.lang"),
|
||||
("res_id", '=', lang_record.id),
|
||||
("res_field", "=", "flag_image")
|
||||
])
|
||||
|
||||
jpeg_attach = self.env["ir.attachment"].create({
|
||||
"name": "webpcopy.jpg",
|
||||
"res_model": "ir.attachment",
|
||||
"res_id": attachment.id,
|
||||
"datas": "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAF0lEQVR4nGJxKFrEwMDAxAAGgAAAAP//D+IBWx9K7TUAAAAASUVORK5CYII="
|
||||
})
|
||||
jpeg_datas = jpeg_attach.datas
|
||||
|
||||
html = view.with_context(webp_as_jpg=False)._render_template(view.id, {"is_raw_image": True, "record": lang_record})
|
||||
tree = etree.fromstring(html)
|
||||
img = tree.find("img")
|
||||
self.assertEqual(img.get("src"), "data:image/webp;base64,%s" % webp)
|
||||
|
||||
html = view.with_context(webp_as_jpg=True)._render_template(view.id, {"is_raw_image": True, "record": lang_record})
|
||||
tree = etree.fromstring(html)
|
||||
img = tree.find("img")
|
||||
self.assertEqual(img.get("src"), "data:image/png;base64,%s" % jpeg_datas.decode())
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import re
|
||||
from contextlib import suppress
|
||||
|
||||
import odoo.tests
|
||||
from odoo.tools.misc import file_open
|
||||
from werkzeug.urls import url_quote_plus
|
||||
|
||||
RE_ONLY = re.compile(r'QUnit\.(only|debug)\(')
|
||||
|
|
@ -106,11 +109,12 @@ class WebSuite(WebsuiteCommon):
|
|||
|
||||
for asset in assets:
|
||||
filename = asset['filename']
|
||||
if not filename or asset['atype'] != 'text/javascript':
|
||||
if not filename.endswith('.js'):
|
||||
continue
|
||||
with open(filename, 'rb') as fp:
|
||||
if RE_ONLY.search(fp.read().decode('utf-8')):
|
||||
self.fail("`QUnit.only()` or `QUnit.debug()` used in file %r" % asset['url'])
|
||||
with suppress(FileNotFoundError):
|
||||
with file_open(filename, 'rb', filter_ext=('.js',)) as fp:
|
||||
if RE_ONLY.search(fp.read().decode('utf-8')):
|
||||
self.fail("`QUnit.only()` or `QUnit.debug()` used in file %r" % asset['url'])
|
||||
|
||||
|
||||
@odoo.tests.tagged('post_install', '-at_install')
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ class LoadMenusTests(HttpCase):
|
|||
|
||||
def test_load_menus(self):
|
||||
menu_loaded = self.url_open("/web/webclient/load_menus/1234")
|
||||
|
||||
expected = {
|
||||
str(self.menu.id): {
|
||||
"actionID": False,
|
||||
|
|
@ -28,6 +27,7 @@ class LoadMenusTests(HttpCase):
|
|||
"name": "test_menu",
|
||||
"webIcon": False,
|
||||
"webIconData": False,
|
||||
"webIconDataMimetype": False,
|
||||
"xmlid": ""
|
||||
},
|
||||
"root": {
|
||||
|
|
@ -41,6 +41,7 @@ class LoadMenusTests(HttpCase):
|
|||
"name": "root",
|
||||
"webIcon": None,
|
||||
"webIconData": None,
|
||||
"webIconDataMimetype": None,
|
||||
"xmlid": "",
|
||||
"backgroundImage": None,
|
||||
}
|
||||
|
|
|
|||
117
odoo-bringout-oca-ocb-web/web/tests/test_partner.py
Normal file
117
odoo-bringout-oca-ocb-web/web/tests/test_partner.py
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
import io
|
||||
import logging
|
||||
import unittest
|
||||
import zipfile
|
||||
from odoo.fields import Command
|
||||
|
||||
from odoo.tests.common import HttpCase, tagged
|
||||
from base64 import b64decode
|
||||
|
||||
from odoo.tools import mute_logger
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import vobject
|
||||
except ImportError:
|
||||
_logger.warning("`vobject` Python module not found, vcard file generation disabled. Consider installing this module if you want to generate vcard files")
|
||||
vobject = None
|
||||
|
||||
|
||||
@tagged('-at_install', 'post_install')
|
||||
class TestPartnerVCard(HttpCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
if not vobject:
|
||||
raise unittest.SkipTest("Skip tests when `vobject` Python module is not found.")
|
||||
|
||||
self.partners = self.env['res.partner'].create([{
|
||||
'name': 'John Doe',
|
||||
'email': 'john.doe@test.example.com',
|
||||
'mobile': '+1 202 555 0888',
|
||||
'phone': '+1 202 555 0122',
|
||||
'function': 'Painter',
|
||||
'street': 'Cookieville Minimum-Security Orphanarium',
|
||||
'city': 'New York',
|
||||
'country_id': self.env.ref('base.us').id,
|
||||
'zip': '97648',
|
||||
'website': 'https://test.exemple.com',
|
||||
}, {
|
||||
'name': 'shut',
|
||||
'email': 'shut@test.example.com',
|
||||
'mobile': '+1 202 555 0999',
|
||||
'phone': '+1 202 555 0123',
|
||||
'function': 'Developer',
|
||||
'street': 'Donutville Maximum-Security Orphanarium',
|
||||
'city': 'Washington DC',
|
||||
'country_id': self.env.ref('base.us').id,
|
||||
'zip': '97649',
|
||||
'website': 'https://test.example.com',
|
||||
'child_ids': [
|
||||
Command.create({'type': 'other'})
|
||||
]
|
||||
}])
|
||||
self.authenticate("admin", "admin")
|
||||
|
||||
def check_vcard_contents(self, vcard, partner):
|
||||
self.assertEqual(vcard.contents["n"][0].value.family, partner.name, "Vcard should have the same name")
|
||||
self.assertEqual(vcard.contents["adr"][0].value.street, partner.street, "Vcard should have the same street")
|
||||
self.assertEqual(vcard.contents["adr"][0].value.city, partner.city, "Vcard should have the same city")
|
||||
self.assertEqual(vcard.contents["adr"][0].value.code, partner.zip, "Vcard should have the same zip")
|
||||
self.assertEqual(vcard.contents["adr"][0].value.country, self.env.ref('base.us').name, "Vcard should have the same country")
|
||||
self.assertEqual(vcard.contents["email"][0].value, partner.email, "Vcard should have the same email")
|
||||
self.assertEqual(vcard.contents["url"][0].value, partner.website, "Vcard should have the same website")
|
||||
self.assertEqual(vcard.contents["tel"][0].params['TYPE'], ["work"], "Vcard should have the same phone")
|
||||
self.assertEqual(vcard.contents["tel"][0].value, partner.phone, "Vcard should have the same phone")
|
||||
self.assertEqual(vcard.contents["tel"][1].params['TYPE'], ["cell"], "Vcard should have the same mobile")
|
||||
self.assertEqual(vcard.contents["tel"][1].value, partner.mobile, "Vcard should have the same mobile")
|
||||
self.assertEqual(vcard.contents["title"][0].value, partner.function, "Vcard should have the same function")
|
||||
self.assertEqual(len(vcard.contents['photo'][0].value), len(b64decode(partner.avatar_512)), "Vcard should have the same photo")
|
||||
|
||||
def test_fetch_single_partner_vcard(self):
|
||||
res = self.url_open('/web_enterprise/partner/%d/vcard' % self.partners[0].id)
|
||||
vcard = vobject.readOne(res.text)
|
||||
self.check_vcard_contents(vcard, self.partners[0])
|
||||
|
||||
def test_fetch_multiple_partners_vcard(self):
|
||||
res = self.url_open('/web/partner/vcard?partner_ids=%s,%s'
|
||||
% (self.partners[0].id, self.partners[1].id))
|
||||
with io.BytesIO(res.content) as buffer:
|
||||
with zipfile.ZipFile(buffer, 'r') as zipf:
|
||||
vcfFileList = zipf.namelist()
|
||||
for i, vcfFile in enumerate(vcfFileList):
|
||||
vcardFile = zipf.read(vcfFile).decode()
|
||||
self.check_vcard_contents(vobject.readOne(vcardFile), self.partners[i])
|
||||
|
||||
@unittest.skip
|
||||
def test_not_exist_partner_vcard(self):
|
||||
partner_id = self.partner.id
|
||||
self.partner.unlink()
|
||||
res = self.url_open('/web/partner/%d/vcard' % partner_id)
|
||||
self.assertEqual(res.status_code, 404)
|
||||
|
||||
def test_check_partner_access_for_user(self):
|
||||
self.env['res.users'].create({
|
||||
'groups_id': [Command.set([self.env.ref('base.group_public').id])],
|
||||
'name': 'Test User',
|
||||
'login': 'testuser',
|
||||
'password': 'testuser',
|
||||
})
|
||||
self.authenticate('testuser', 'testuser')
|
||||
with mute_logger('odoo.http'): # mute 403 warning
|
||||
res = self.url_open('/web/partner/vcard?partner_ids=%s,%s' %
|
||||
(self.partners[0].id, self.partners[1].id))
|
||||
self.assertEqual(res.status_code, 403)
|
||||
|
||||
def test_fetch_single_partner_vcard_without_name(self):
|
||||
"""
|
||||
Test to fetch a vcard of a partner create through
|
||||
child of another partner without name
|
||||
"""
|
||||
partner = self.partners[1].child_ids[0]
|
||||
res = self.url_open('/web/partner/vcard?partner_ids=%s' % partner.id)
|
||||
vcard = vobject.readOne(res.text)
|
||||
self.assertEqual(vcard.contents["n"][0].value.family, partner.complete_name, "Vcard will have the complete name when it dosen't have name")
|
||||
|
|
@ -86,24 +86,24 @@ class TestReadProgressBar(common.TransactionCase):
|
|||
c1, c2, c3 = self.env['res.country'].search([], limit=3)
|
||||
|
||||
self.env['x_progressbar'].create([
|
||||
# week 21
|
||||
{'x_country_id': c1.id, 'x_date': '2021-05-20', 'x_state': 'foo'},
|
||||
{'x_country_id': c1.id, 'x_date': '2021-05-21', 'x_state': 'foo'},
|
||||
{'x_country_id': c1.id, 'x_date': '2021-05-22', 'x_state': 'foo'},
|
||||
{'x_country_id': c1.id, 'x_date': '2021-05-23', 'x_state': 'bar'},
|
||||
# week 22
|
||||
{'x_country_id': c1.id, 'x_date': '2021-05-24', 'x_state': 'baz'},
|
||||
{'x_country_id': c2.id, 'x_date': '2021-05-25', 'x_state': 'foo'},
|
||||
{'x_country_id': c2.id, 'x_date': '2021-05-26', 'x_state': 'bar'},
|
||||
{'x_country_id': c2.id, 'x_date': '2021-05-27', 'x_state': 'bar'},
|
||||
{'x_country_id': c2.id, 'x_date': '2021-05-28', 'x_state': 'baz'},
|
||||
{'x_country_id': c2.id, 'x_date': '2021-05-29', 'x_state': 'baz'},
|
||||
{'x_country_id': c3.id, 'x_date': '2021-05-30', 'x_state': 'foo'},
|
||||
# week 23
|
||||
{'x_country_id': c3.id, 'x_date': '2021-05-31', 'x_state': 'foo'},
|
||||
{'x_country_id': c3.id, 'x_date': '2021-06-01', 'x_state': 'baz'},
|
||||
{'x_country_id': c3.id, 'x_date': '2021-06-02', 'x_state': 'baz'},
|
||||
{'x_country_id': c3.id, 'x_date': '2021-06-03', 'x_state': 'baz'},
|
||||
# week 53 2018 / week 1 2019
|
||||
{'x_country_id': c1.id, 'x_date': '2019-01-01', 'x_state': 'foo'},
|
||||
{'x_country_id': c1.id, 'x_date': '2019-01-02', 'x_state': 'foo'},
|
||||
{'x_country_id': c1.id, 'x_date': '2019-01-03', 'x_state': 'foo'},
|
||||
{'x_country_id': c1.id, 'x_date': '2019-01-04', 'x_state': 'bar'},
|
||||
{'x_country_id': c1.id, 'x_date': '2019-01-05', 'x_state': 'baz'},
|
||||
# week 2 2019
|
||||
{'x_country_id': c2.id, 'x_date': '2019-01-06', 'x_state': 'foo'},
|
||||
{'x_country_id': c2.id, 'x_date': '2019-01-07', 'x_state': 'bar'},
|
||||
{'x_country_id': c2.id, 'x_date': '2019-01-08', 'x_state': 'bar'},
|
||||
{'x_country_id': c2.id, 'x_date': '2019-01-09', 'x_state': 'baz'},
|
||||
{'x_country_id': c3.id, 'x_date': '2019-01-10', 'x_state': 'baz'},
|
||||
{'x_country_id': c3.id, 'x_date': '2019-01-11', 'x_state': 'foo'},
|
||||
{'x_country_id': c3.id, 'x_date': '2019-01-12', 'x_state': 'foo'},
|
||||
# week 3 2019
|
||||
{'x_country_id': c3.id, 'x_date': '2019-01-13', 'x_state': 'baz'},
|
||||
{'x_country_id': c3.id, 'x_date': '2019-01-14', 'x_state': 'baz'},
|
||||
{'x_country_id': c3.id, 'x_date': '2019-01-15', 'x_state': 'baz'},
|
||||
])
|
||||
|
||||
progress_bar = {
|
||||
|
|
@ -113,16 +113,16 @@ class TestReadProgressBar(common.TransactionCase):
|
|||
result = self.env['x_progressbar'].read_progress_bar([], 'x_country_id', progress_bar)
|
||||
self.assertEqual(result, {
|
||||
c1.display_name: {'foo': 3, 'bar': 1, 'baz': 1},
|
||||
c2.display_name: {'foo': 1, 'bar': 2, 'baz': 2},
|
||||
c3.display_name: {'foo': 2, 'bar': 0, 'baz': 3},
|
||||
c2.display_name: {'foo': 1, 'bar': 2, 'baz': 1},
|
||||
c3.display_name: {'foo': 2, 'bar': 0, 'baz': 4},
|
||||
})
|
||||
|
||||
# check date aggregation and format
|
||||
result = self.env['x_progressbar'].read_progress_bar([], 'x_date:week', progress_bar)
|
||||
self.assertEqual(result, {
|
||||
'W21 2021': {'foo': 3, 'bar': 1, 'baz': 0},
|
||||
'W22 2021': {'foo': 2, 'bar': 2, 'baz': 3},
|
||||
'W23 2021': {'foo': 1, 'bar': 0, 'baz': 3},
|
||||
'W1 2019': {'foo': 3, 'bar': 1, 'baz': 1},
|
||||
'W2 2019': {'foo': 3, 'bar': 2, 'baz': 2},
|
||||
'W3 2019': {'foo': 0, 'bar': 0, 'baz': 3},
|
||||
})
|
||||
|
||||
# add a computed field on model
|
||||
|
|
@ -146,13 +146,14 @@ class TestReadProgressBar(common.TransactionCase):
|
|||
result = self.env['x_progressbar'].read_progress_bar([], 'x_country_id', progress_bar)
|
||||
self.assertEqual(result, {
|
||||
c1.display_name: {'foo': 3, 'bar': 1, 'baz': 1},
|
||||
c2.display_name: {'foo': 1, 'bar': 2, 'baz': 2},
|
||||
c3.display_name: {'foo': 2, 'bar': 0, 'baz': 3},
|
||||
c2.display_name: {'foo': 1, 'bar': 2, 'baz': 1},
|
||||
c3.display_name: {'foo': 2, 'bar': 0, 'baz': 4},
|
||||
})
|
||||
|
||||
result = self.env['x_progressbar'].read_progress_bar([], 'x_date:week', progress_bar)
|
||||
self.assertEqual(result, {
|
||||
'W21 2021': {'foo': 3, 'bar': 1, 'baz': 0},
|
||||
'W22 2021': {'foo': 2, 'bar': 2, 'baz': 3},
|
||||
'W23 2021': {'foo': 1, 'bar': 0, 'baz': 3},
|
||||
# first week is not the same as above, but that seems acceptable...
|
||||
'W1 2019': {'foo': 3, 'bar': 1, 'baz': 1},
|
||||
'W2 2019': {'foo': 3, 'bar': 2, 'baz': 2},
|
||||
'W3 2019': {'foo': 0, 'bar': 0, 'baz': 3},
|
||||
})
|
||||
|
|
|
|||
39
odoo-bringout-oca-ocb-web/web/tests/test_res_users.py
Normal file
39
odoo-bringout-oca-ocb-web/web/tests/test_res_users.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests import TransactionCase
|
||||
|
||||
|
||||
class TestResUsers(TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.users = cls.env["res.users"].create([
|
||||
{'name': 'Jean', 'login': 'jean@mail.com', 'password': 'jean@mail.com'},
|
||||
{'name': 'Jean-Paul', 'login': 'jean-paul@mail.com', 'password': 'jean-paul@mail.com'},
|
||||
{'name': 'Jean-Jacques', 'login': 'jean-jacques@mail.com', 'password': 'jean-jacques@mail.com'},
|
||||
{'name': 'Georges', 'login': 'georges@mail.com', 'password': 'georges@mail.com'},
|
||||
{'name': 'Claude', 'login': 'claude@mail.com', 'password': 'claude@mail.com'},
|
||||
{'name': 'Pascal', 'login': 'pascal@mail.com', 'password': 'pascal@mail.com'},
|
||||
])
|
||||
|
||||
def test_name_search(self):
|
||||
"""
|
||||
Test name search with self assign feature
|
||||
The self assign feature is present only when a limit is present,
|
||||
which is the case with the public name_search by default
|
||||
"""
|
||||
ResUsers = self.env['res.users']
|
||||
jean = self.users[0]
|
||||
user_ids = [id_ for id_, __ in ResUsers.with_user(jean).name_search('')]
|
||||
self.assertEqual(jean.id, user_ids[0], "The current user, Jean, should be the first in the result.")
|
||||
user_ids = [id_ for id_, __ in ResUsers.with_user(jean).name_search('Claude')]
|
||||
self.assertNotIn(jean.id, user_ids, "The current user, Jean, should not be in the result because his name does not fit the condition.")
|
||||
pascal = self.users[-1]
|
||||
user_ids = [id_ for id_, __ in ResUsers.with_user(pascal).name_search('')]
|
||||
self.assertEqual(pascal.id, user_ids[0], "The current user, Pascal, should be the first in the result.")
|
||||
user_ids = [id_ for id_, __ in ResUsers.with_user(pascal).name_search('', limit=3)]
|
||||
self.assertEqual(pascal.id, user_ids[0], "The current user, Pascal, should be the first in the result.")
|
||||
self.assertEqual(len(user_ids), 3, "The number of results found should still respect the limit set.")
|
||||
jean_paul = self.users[1]
|
||||
user_ids = [id_ for id_, __ in ResUsers.with_user(jean_paul).name_search('Jean')]
|
||||
self.assertEqual(jean_paul.id, user_ids[0], "The current user, Jean-Paul, should be the first in the result")
|
||||
|
|
@ -14,7 +14,11 @@ class TestSessionInfo(common.HttpCase):
|
|||
cls.company_a = cls.env['res.company'].create({'name': "A"})
|
||||
cls.company_b = cls.env['res.company'].create({'name': "B"})
|
||||
cls.company_c = cls.env['res.company'].create({'name': "C"})
|
||||
cls.companies = [cls.company_a, cls.company_b, cls.company_c]
|
||||
cls.company_b_branch = cls.env['res.company'].create({'name': "B Branch", 'parent_id': cls.company_b.id})
|
||||
cls.company_c_branch = cls.env['res.company'].create({'name': "C Branch", 'parent_id': cls.company_c.id})
|
||||
cls.company_c_branch_branch = cls.env['res.company'].create({'name': "C Branch Branch", 'parent_id': cls.company_c_branch.id})
|
||||
cls.allowed_companies = cls.company_a + cls.company_b_branch + cls.company_c + cls.company_c_branch_branch
|
||||
cls.disallowed_ancestor_companies = cls.company_b + cls.company_c_branch
|
||||
|
||||
cls.user_password = "info"
|
||||
cls.user = common.new_test_user(
|
||||
|
|
@ -25,7 +29,7 @@ class TestSessionInfo(common.HttpCase):
|
|||
tz="UTC")
|
||||
cls.user.write({
|
||||
'company_id': cls.company_a.id,
|
||||
'company_ids': [Command.set([company.id for company in cls.companies])],
|
||||
'company_ids': [Command.set(cls.allowed_companies.ids)],
|
||||
})
|
||||
|
||||
cls.payload = json.dumps(dict(jsonrpc="2.0", method="call", id=str(uuid4())))
|
||||
|
|
@ -47,11 +51,25 @@ class TestSessionInfo(common.HttpCase):
|
|||
'id': company.id,
|
||||
'name': company.name,
|
||||
'sequence': company.sequence,
|
||||
} for company in self.companies
|
||||
'child_ids': company.child_ids.ids,
|
||||
'parent_id': company.parent_id.id,
|
||||
} for company in self.allowed_companies
|
||||
}
|
||||
|
||||
expected_disallowed_ancestor_companies = {
|
||||
str(company.id): {
|
||||
'id': company.id,
|
||||
'name': company.name,
|
||||
'sequence': company.sequence,
|
||||
'child_ids': company.child_ids.ids,
|
||||
'parent_id': company.parent_id.id,
|
||||
} for company in self.disallowed_ancestor_companies
|
||||
}
|
||||
|
||||
expected_user_companies = {
|
||||
'current_company': self.company_a.id,
|
||||
'allowed_companies': expected_allowed_companies,
|
||||
'disallowed_ancestor_companies': expected_disallowed_ancestor_companies,
|
||||
}
|
||||
self.assertEqual(
|
||||
result['user_companies'],
|
||||
|
|
@ -63,12 +81,3 @@ class TestSessionInfo(common.HttpCase):
|
|||
response = self.url_open("/web/session/modules", data=self.payload, headers=self.headers)
|
||||
data = response.json()
|
||||
self.assertTrue(isinstance(data['result'], list))
|
||||
|
||||
def test_load_polish_lang(self):
|
||||
# Regression test, making sure languages without thousand separators
|
||||
# work correctly
|
||||
lang_pl = self.env['res.lang']._activate_lang('pl_PL')
|
||||
self.user.lang = lang_pl.code
|
||||
self.authenticate(self.user.login, self.user_password)
|
||||
res = self.url_open('/web')
|
||||
res.raise_for_status()
|
||||
|
|
|
|||
42
odoo-bringout-oca-ocb-web/web/tests/test_translate.py
Normal file
42
odoo-bringout-oca-ocb-web/web/tests/test_translate.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
class TestTranslationOverride(TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.category = cls.env['res.partner.category'].create({'name': 'Reblochon'})
|
||||
cls.custom = cls.env['ir.model.fields'].create({
|
||||
'name': 'x_html_test',
|
||||
'ttype': 'html',
|
||||
'model_id': cls.category.id,
|
||||
'translate': True,
|
||||
})
|
||||
|
||||
def test_web_override_translations(self):
|
||||
self.env['res.lang']._activate_lang('fr_FR')
|
||||
categoryEN = self.category.with_context(lang='en_US')
|
||||
categoryFR = self.category.with_context(lang='fr_FR')
|
||||
customEN = self.custom.with_context(lang='en_US')
|
||||
customFR = self.custom.with_context(lang='fr_FR')
|
||||
|
||||
self.category.web_override_translations({'name': 'commonName'})
|
||||
self.assertEqual(categoryEN.name, 'commonName')
|
||||
self.assertEqual(categoryFR.name, 'commonName')
|
||||
|
||||
# cannot void translations (incluiding en_US)
|
||||
self.category.web_override_translations({'name': False})
|
||||
self.assertEqual(categoryEN.name, 'commonName')
|
||||
self.assertEqual(categoryFR.name, 'commonName')
|
||||
|
||||
# empty str is a valid translation
|
||||
self.category.web_override_translations({'name': ''})
|
||||
self.assertEqual(categoryEN.name, '')
|
||||
self.assertEqual(categoryFR.name, '')
|
||||
|
||||
# translated html fields are not changed
|
||||
self.custom.web_override_translations({'name': '<div>dont</div><div>change</div>'})
|
||||
self.assertEqual(customEN.name, 'x_html_test')
|
||||
self.assertEqual(customFR.name, 'x_html_test')
|
||||
20
odoo-bringout-oca-ocb-web/web/tests/test_web_read_group.py
Normal file
20
odoo-bringout-oca-ocb-web/web/tests/test_web_read_group.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
from odoo import fields
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
@common.tagged('post_install', '-at_install')
|
||||
class TestWebReadGroup(common.TransactionCase):
|
||||
|
||||
def test_web_read_group_with_date_groupby_and_limit(self):
|
||||
first, second = self.env["res.partner"].create([
|
||||
{
|
||||
"name": "first",
|
||||
"date": fields.Date.to_date("2021-06-01")
|
||||
},
|
||||
{
|
||||
"name": "second",
|
||||
"date": fields.Date.to_date("2021-07-01")
|
||||
}
|
||||
])
|
||||
groups = self.env["res.partner"].web_read_group([["id", "in", [first.id, second.id]]], [], groupby=["date"], limit=1)
|
||||
self.assertEqual(groups["length"], 2)
|
||||
25
odoo-bringout-oca-ocb-web/web/tests/test_web_redirect.py
Normal file
25
odoo-bringout-oca-ocb-web/web/tests/test_web_redirect.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from werkzeug.urls import url_parse
|
||||
|
||||
from odoo.tests.common import HttpCase
|
||||
|
||||
|
||||
class TestWebRedirect(HttpCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.encoded_url_query = "redirect=web%23cids%3D1%26action%3Dmenu"
|
||||
|
||||
def test_root_route_redirect_param(self):
|
||||
web_response = self.url_open(f"/?{self.encoded_url_query}")
|
||||
web_response.raise_for_status()
|
||||
response_url_query = url_parse(web_response.url).query
|
||||
|
||||
self.assertEqual(response_url_query, self.encoded_url_query)
|
||||
|
||||
def test_web_route_redirect_param(self):
|
||||
web_response = self.url_open(f"/web?{self.encoded_url_query}")
|
||||
web_response.raise_for_status()
|
||||
response_url_query = url_parse(web_response.url).query
|
||||
|
||||
self.assertEqual(response_url_query, self.encoded_url_query)
|
||||
|
|
@ -12,7 +12,8 @@ class TestWebSearchRead(common.TransactionCase):
|
|||
cls.ResCurrency = cls.env['res.currency'].with_context(active_test=False)
|
||||
cls.max = cls.ResCurrency.search_count([])
|
||||
|
||||
def assert_web_search_read(self, expected_length, expected_records_length, expected_search_count_called=True, **kwargs):
|
||||
def assert_web_search_read(self, expected_length, expected_records_length, expected_search_count_called=True,
|
||||
**kwargs):
|
||||
original_search_count = self.ResCurrency.search_count
|
||||
search_count_called = [False]
|
||||
|
||||
|
|
@ -21,13 +22,13 @@ class TestWebSearchRead(common.TransactionCase):
|
|||
return original_search_count(*method_args, **method_kwargs)
|
||||
|
||||
with patch('odoo.addons.base.models.res_currency.Currency.search_count', new=search_count):
|
||||
results = self.ResCurrency.web_search_read(domain=[], fields=['id'], **kwargs)
|
||||
results = self.ResCurrency.web_search_read(domain=[], specification={'id':{}}, **kwargs)
|
||||
|
||||
self.assertEqual(results['length'], expected_length)
|
||||
self.assertEqual(len(results['records']), expected_records_length)
|
||||
self.assertEqual(search_count_called[0], expected_search_count_called)
|
||||
|
||||
def test_web_search_read(self):
|
||||
def test_unity_web_search_read(self):
|
||||
self.assert_web_search_read(self.max, self.max, expected_search_count_called=False)
|
||||
self.assert_web_search_read(self.max, 2, limit=2)
|
||||
self.assert_web_search_read(self.max, 2, limit=2, offset=10)
|
||||
|
|
|
|||
92
odoo-bringout-oca-ocb-web/web/tests/test_webmanifest.py
Normal file
92
odoo-bringout-oca-ocb-web/web/tests/test_webmanifest.py
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.addons.base.tests.common import HttpCaseWithUserDemo
|
||||
from odoo.tests.common import tagged
|
||||
|
||||
|
||||
@tagged("-at_install", "post_install")
|
||||
class WebManifestRoutesTest(HttpCaseWithUserDemo):
|
||||
"""
|
||||
This test suite is used to request the routes used by the PWA backend implementation
|
||||
"""
|
||||
|
||||
def test_webmanifest(self):
|
||||
"""
|
||||
This route returns a well formed backend's WebManifest
|
||||
"""
|
||||
self.authenticate("admin", "admin")
|
||||
response = self.url_open("/web/manifest.webmanifest")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.headers["Content-Type"], "application/manifest+json")
|
||||
data = response.json()
|
||||
self.assertEqual(data["name"], "Odoo")
|
||||
self.assertEqual(data["scope"], "/web")
|
||||
self.assertEqual(data["start_url"], "/web")
|
||||
self.assertEqual(data["display"], "standalone")
|
||||
self.assertEqual(data["background_color"], "#714B67")
|
||||
self.assertEqual(data["theme_color"], "#714B67")
|
||||
self.assertEqual(data["prefer_related_applications"], False)
|
||||
self.assertCountEqual(data["icons"], [
|
||||
{'src': '/web/static/img/odoo-icon-192x192.png', 'sizes': '192x192', 'type': 'image/png'},
|
||||
{'src': '/web/static/img/odoo-icon-512x512.png', 'sizes': '512x512', 'type': 'image/png'}
|
||||
])
|
||||
self.assertGreaterEqual(len(data["shortcuts"]), 0)
|
||||
for shortcut in data["shortcuts"]:
|
||||
self.assertGreater(len(shortcut["name"]), 0)
|
||||
self.assertGreater(len(shortcut["description"]), 0)
|
||||
self.assertGreater(len(shortcut["icons"]), 0)
|
||||
self.assertTrue(shortcut["url"].startswith("/web#menu_id="))
|
||||
|
||||
def test_webmanifest_unauthenticated(self):
|
||||
"""
|
||||
This route returns a well formed backend's WebManifest
|
||||
"""
|
||||
response = self.url_open("/web/manifest.webmanifest")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.headers["Content-Type"], "application/manifest+json")
|
||||
data = response.json()
|
||||
self.assertEqual(data["name"], "Odoo")
|
||||
self.assertEqual(data["scope"], "/web")
|
||||
self.assertEqual(data["start_url"], "/web")
|
||||
self.assertEqual(data["display"], "standalone")
|
||||
self.assertEqual(data["background_color"], "#714B67")
|
||||
self.assertEqual(data["theme_color"], "#714B67")
|
||||
self.assertEqual(data["prefer_related_applications"], False)
|
||||
self.assertCountEqual(data["icons"], [
|
||||
{'src': '/web/static/img/odoo-icon-192x192.png', 'sizes': '192x192', 'type': 'image/png'},
|
||||
{'src': '/web/static/img/odoo-icon-512x512.png', 'sizes': '512x512', 'type': 'image/png'}
|
||||
])
|
||||
self.assertEqual(len(data["shortcuts"]), 0)
|
||||
|
||||
def test_serviceworker(self):
|
||||
"""
|
||||
This route returns a JavaScript's ServiceWorker
|
||||
"""
|
||||
response = self.url_open("/web/service-worker.js")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.headers["Content-Type"], "text/javascript")
|
||||
self.assertEqual(response.headers["Service-Worker-Allowed"], "/web")
|
||||
|
||||
def test_offline_url(self):
|
||||
"""
|
||||
This route returns the offline page
|
||||
"""
|
||||
response = self.url_open("/web/offline")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.headers["Content-Type"], "text/html; charset=utf-8")
|
||||
|
||||
def test_apple_touch_icon(self):
|
||||
"""
|
||||
This request tests the presence of an apple-touch-icon image route for the PWA icon and
|
||||
its presence from the head of the document.
|
||||
"""
|
||||
self.authenticate("demo", "demo")
|
||||
response = self.url_open("/web/static/img/odoo-icon-ios.png")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
document = self.url_open("/web")
|
||||
self.assertIn(
|
||||
'<link rel="apple-touch-icon" href="/web/static/img/odoo-icon-ios.png"/>', document.text,
|
||||
"Icon for iOS is present in the head of the document.",
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue