[IMP] tests: log a warning when HttpCase test in at_install

When loading a page on an existing starting database, registry is not
fully loaded causing potential error when trying to access model
existing in database (views, menitem, ...) since model added in last
loaded module does not exist in registry.

Thus, executing browser js test may lead to errors when executed during
an update on a database with other modules installed.

HTTPCase should be executed post_install to ensure that registry is
fully loaded to avoid this problem.

Since HTTPCase are slower than other test, it is also a good idea to
execute them at the end, in order to prioritize fast fail.

With this commit, a warning is isued if such a test class is tagged to
run at install time.

While at it, remove deprecated at_install and post_install helpers and
remove the deprecated phantom_js alias.

closes odoo/odoo#39462

Signed-off-by: Christophe Monniez (moc) <moc@odoo.com>
This commit is contained in:
Christophe Monniez
2019-10-30 12:35:23 +00:00
parent b6ed34e134
commit 8d5da6e4be
25 changed files with 43 additions and 65 deletions
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from odoo.tests.common import HttpCase
from odoo.tests.common import TransactionCase
class AccountingTestTemplConsistency(HttpCase):
class AccountingTestTemplConsistency(TransactionCase):
'''Test the templates consistency between some objects like account.account when account.account.template.
'''
+1 -1
View File
@@ -8,4 +8,4 @@ import odoo.tests
class IMSupportSuite(odoo.tests.HttpCase):
def test_im_support_js(self):
self.phantom_js('/im_support/tests?mod=web&failfast', "", "", login='admin', timeout=180)
self.browser_js('/im_support/tests?mod=web&failfast', "", "", login='admin', timeout=180)
@@ -2,13 +2,12 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.survey.tests import common
from odoo.tests.common import HttpCase
from psycopg2 import IntegrityError
from odoo.exceptions import AccessError
from odoo.tools import mute_logger
class TestCertificationBadge(common.SurveyCase, HttpCase):
class TestCertificationBadge(common.SurveyCase):
def setUp(self):
super(TestCertificationBadge, self).setUp()
self.certification_survey = self.env['survey.survey'].with_user(self.survey_manager).create({
@@ -9,7 +9,7 @@ from odoo.tests import tagged
from odoo.tests.common import HttpCase
@tagged('functional')
@tagged('-at_install', 'post_install', 'functional')
class TestCertificationFlow(common.SurveyCase, HttpCase):
def _answer_question(self, question, answer, answer_token, csrf_token, button_submit='next'):
# Employee submits the question answer
+1 -1
View File
@@ -6,7 +6,7 @@ from odoo.tests import tagged
from odoo.tests.common import HttpCase
@tagged('functional')
@tagged('-at_install', 'post_install', 'functional')
class TestSurveyFlow(common.SurveyCase, HttpCase):
def _format_submission_data(self, page, answer_data, additional_post_data):
post_data = {}
+2 -1
View File
@@ -2,9 +2,10 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from werkzeug.urls import url_decode, url_parse
from odoo.tests.common import HttpCase
from odoo.tests.common import HttpCase, tagged
@tagged('-at_install', 'post_install')
class TestMultiCompany(HttpCase):
def test_redirect_to_records(self):
@@ -16,7 +16,7 @@ class TestUi(tests.HttpCase):
})
self.env.ref('website_slides.slide_channel_demo_6_furn3')._remove_membership(self.env.ref('base.partner_demo').ids)
self.phantom_js(
self.browser_js(
'/slides',
'odoo.__DEBUG__.services["web_tour.tour"].run("certification_member")',
'odoo.__DEBUG__.services["web_tour.tour"].tours.certification_member.ready',
+2 -1
View File
@@ -6,7 +6,7 @@ from datetime import date
from unittest.mock import patch
from odoo import http
from odoo.tests import common
from odoo.tests import common, tagged
from odoo.addons.web.controllers.main import ExportXlsxWriter
from odoo.addons.test_mail.tests.common import mail_new_test_user
@@ -69,6 +69,7 @@ class XlsxCreatorCase(common.HttpCase):
self.assertFalse(value, "There are unexpected cells in the export")
@tagged('-at_install', 'post_install')
class TestGroupedExport(XlsxCreatorCase):
model_name = 'export.group_operator'
+2 -1
View File
@@ -6,9 +6,10 @@ import base64
from PIL import Image
from odoo.tests.common import HttpCase
from odoo.tests.common import HttpCase, tagged
@tagged('-at_install', 'post_install')
class TestImage(HttpCase):
def test_01_content_image_resize_placeholder(self):
"""The goal of this test is to make sure the placeholder image is
+2 -2
View File
@@ -12,7 +12,7 @@ class WebSuite(odoo.tests.HttpCase):
def test_js(self):
# webclient desktop test suite
self.phantom_js('/web/tests?mod=web&failfast', "", "", login='admin', timeout=1800)
self.browser_js('/web/tests?mod=web&failfast', "", "", login='admin', timeout=1800)
def test_check_suite(self):
# verify no js test is using `QUnit.only` as it forbid any other test to be executed
@@ -39,4 +39,4 @@ class MobileWebSuite(odoo.tests.HttpCase):
def test_mobile_js(self):
# webclient mobile test suite
self.phantom_js('/web/tests/mobile?mod=web&failfast', "", "", login='admin', timeout=1800)
self.browser_js('/web/tests/mobile?mod=web&failfast', "", "", login='admin', timeout=1800)
+1
View File
@@ -184,6 +184,7 @@ class TestPage(common.TransactionCase):
self.assertTrue(website_id not in View.search([('name', 'in', ('Base', 'Extension'))]).mapped('website_id').ids, "Same for views")
@tagged('-at_install', 'post_install')
class Crawler(HttpCase):
def test_unpublished_page(self):
Page = self.env['website.page']
+1 -1
View File
@@ -93,7 +93,7 @@ class TestUiTranslate(odoo.tests.HttpCase):
class TestUi(odoo.tests.HttpCase):
def test_01_public_homepage(self):
self.phantom_js("/", "console.log('test successful')", "'website.content.snippets.animation' in odoo.__DEBUG__.services")
self.browser_js("/", "console.log('test successful')", "'website.content.snippets.animation' in odoo.__DEBUG__.services")
def test_02_admin_tour_banner(self):
self.start_tour("/", 'banner', login='admin')
+1
View File
@@ -897,6 +897,7 @@ class TestCowViewSaving(common.TransactionCase):
# 3 | Extension 2 | , extended content 2 | 1 | 5 | website.extension_view_2
@tagged('-at_install', 'post_install')
class Crawler(HttpCase):
def setUp(self):
super(Crawler, self).setUp()
+2 -1
View File
@@ -1,7 +1,8 @@
# coding: utf-8
from odoo.tests import HttpCase
from odoo.tests import HttpCase, tagged
@tagged('-at_install', 'post_install')
class WebsiteVisitorTests(HttpCase):
def test_create_visitor_on_tracked_page(self):
Page = self.env['website.page']
@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*-
from odoo.tests import common
from odoo.tests import common, tagged
from odoo.tools.misc import mute_logger, ustr
@tagged('-at_install', 'post_install')
class TestConfirmUnsubscribe(common.HttpCase):
def setUp(self):
super(TestConfirmUnsubscribe, self).setUp()
@@ -3,8 +3,7 @@
import odoo.tests
@odoo.tests.common.at_install(False)
@odoo.tests.common.post_install(True)
@odoo.tests.tagged('-at_install', 'post_install')
class TestUi(odoo.tests.HttpCase):
def test_01_wishlist_tour(self):
self.start_tour("/", 'shop_wishlist')
@@ -15,7 +15,7 @@ class TestUi(tests.HttpCase):
})
self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo').ids)
self.phantom_js(
self.browser_js(
'/slides',
'odoo.__DEBUG__.services["web_tour.tour"].run("course_member")',
'odoo.__DEBUG__.services["web_tour.tour"].tours.course_member.ready',
@@ -31,7 +31,7 @@ class TestUi(tests.HttpCase):
})
self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo').ids)
self.phantom_js(
self.browser_js(
'/slides',
'odoo.__DEBUG__.services["web_tour.tour"].run("course_member")',
'odoo.__DEBUG__.services["web_tour.tour"].tours.course_member.ready',
@@ -44,7 +44,7 @@ class TestUi(tests.HttpCase):
user_portal.flush()
self.env.ref('website_slides.slide_channel_demo_0_gard_0')._remove_membership(self.env.ref('base.partner_demo_portal').ids)
self.phantom_js(
self.browser_js(
'/slides',
'odoo.__DEBUG__.services["web_tour.tour"].run("course_member")',
'odoo.__DEBUG__.services["web_tour.tour"].tours.course_member.ready',
@@ -63,7 +63,7 @@ class TestUiYoutube(tests.HttpCase):
})
self.env.ref('website_slides.slide_channel_demo_3_furn0')._remove_membership(self.env.ref('base.partner_demo').ids)
self.phantom_js(
self.browser_js(
'/slides',
'odoo.__DEBUG__.services["web_tour.tour"].run("course_member_youtube")',
'odoo.__DEBUG__.services["web_tour.tour"].tours.course_member_youtube.ready',
@@ -78,7 +78,7 @@ class TestUiYoutube(tests.HttpCase):
'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id), (4, self.env.ref('website.group_website_designer').id)]
})
self.phantom_js(
self.browser_js(
'/slides',
'odoo.__DEBUG__.services["web_tour.tour"].run("course_publisher")',
'odoo.__DEBUG__.services["web_tour.tour"].tours.course_publisher.ready',
@@ -54,6 +54,7 @@ class TestViews(TransactionCase):
self.assertEqual(specific_main_view_children.website_id, website_1, "..and the website is the correct one.")
@tagged('-at_install', 'post_install')
class Crawler(HttpCase):
def test_multi_website_views_retrieving(self):
View = self.env['ir.ui.view']
+3 -3
View File
@@ -56,7 +56,7 @@ related to testing Odoo content (modules, mainly):
.. autoclass:: odoo.tests.common.SavepointCase
.. autoclass:: odoo.tests.common.HttpCase
:members: browse_ref, ref, url_open, phantom_js
:members: browse_ref, ref, url_open, browser_js
.. autofunction:: odoo.tests.common.tagged
@@ -321,7 +321,7 @@ infrastructure:
- we want the runbot to also run these tests, so there is a test (in `test_js.py`_)
which simply spawns a browser and points it to the *web/tests* url. Note that
the phantom_js method does not spawn phantom_js, but Chrome headless instead.
the browser_js method spawns a Chrome headless instance.
Modularity and testing
@@ -501,7 +501,7 @@ Testing Python code and JS code separately is very useful, but it does not prove
that the web client and the server work together. In order to do that, we can
write another kind of test: tours. A tour is a mini scenario of some interesting
business flow. It explains a sequence of steps that should be followed. The
test runner will then create a phantom_js browser, point it to the proper url
test runner will then create a Chrome headless browser, point it to the proper url
and simulate the click and inputs, according to the scenario.
Screenshots and screencasts during browser_js tests
@@ -3,7 +3,7 @@
import odoo.tests
class TestMonetaryAccess(odoo.tests.HttpCase):
class TestMonetaryAccess(odoo.tests.TransactionCase):
def test_monetary_access_create(self):
"""Monetary fields that depend on compute/related currency
@@ -3,6 +3,7 @@
import odoo.tests
@odoo.tests.tagged('-at_install', 'post_install')
class TestAccess(odoo.tests.HttpCase):
def setUp(self):
super(TestAccess, self).setUp()
@@ -12,7 +12,7 @@ from odoo import api
from odoo.addons.base.models.assetsbundle import AssetsBundle
from odoo.addons.base.models.ir_attachment import IrAttachment
from odoo.modules.module import get_resource_path
from odoo.tests import HttpCase
from odoo.tests import HttpCase, tagged
from odoo.tests.common import TransactionCase
GETMTINE = os.path.getmtime
@@ -512,11 +512,12 @@ class TestJavascriptAssetsBundle(FileTouchable):
</html>""").encode('utf8'))
@tagged('-at_install', 'post_install')
class TestAssetsBundleInBrowser(HttpCase):
def test_01_js_interpretation(self):
""" Checks that the javascript of a bundle is correctly interpreted.
"""
self.phantom_js(
self.browser_js(
"/test_assetsbundle/js",
"a + b + c === 6 ? console.log('test successful') : console.log('error')",
login="admin"
@@ -542,7 +543,7 @@ class TestAssetsBundleInBrowser(HttpCase):
})
self.env.user.flush()
self.phantom_js(
self.browser_js(
"/test_assetsbundle/js",
"a + b + c + d === 10 ? console.log('test successful') : console.log('error')",
login="admin",
@@ -17,6 +17,7 @@ class TestUi(odoo.tests.HttpCase):
'widget_x2many', step_delay=100, login="admin", timeout=120)
@odoo.tests.tagged('-at_install', 'post_install')
class TestUiTranslation(odoo.tests.HttpCase):
@mute_logger('odoo.sql_db', 'odoo.http')
+2 -1
View File
@@ -2,10 +2,11 @@
from functools import partial
from odoo.tests import common
from odoo.tests import common, tagged
from odoo.tools.misc import mute_logger
@tagged('-at_install', 'post_install')
class TestError(common.HttpCase):
def setUp(self):
super(TestError, self).setUp()
+2 -34
View File
@@ -87,37 +87,6 @@ def get_db_name():
DB = get_db_name()
def at_install(flag):
""" Sets the at-install state of a test, the flag is a boolean specifying
whether the test should (``True``) or should not (``False``) run during
module installation.
By default, tests are run right after installing the module, before
starting the installation of the next module.
.. deprecated:: 12.0
``at_install`` is now a flag, you can use :func:`tagged` to
add/remove it, although ``tagged`` only works on test classes
"""
return tagged('at_install' if flag else '-at_install')
def post_install(flag):
""" Sets the post-install state of a test. The flag is a boolean
specifying whether the test should or should not run after a set of
module installations.
By default, tests are *not* run after installation of all modules in the
current installation set.
.. deprecated:: 12.0
``post_install`` is now a flag, you can use :func:`tagged` to
add/remove it, although ``tagged`` only works on test classes
"""
return tagged('post_install' if flag else '-post_install')
def new_test_user(env, login='', groups='base.group_user', context=None, **kwargs):
""" Helper function to create a new test user. It allows to quickly create
users given its login and groups (being a comma separated list of xml ids).
@@ -955,7 +924,8 @@ class HttpCase(TransactionCase):
def setUp(self):
super(HttpCase, self).setUp()
if not self.env.registry.loaded:
self._logger.warning('HttpCase test should be in post_install only')
if self.registry_test_mode:
self.registry.enter_test_mode(self.cr)
self.addCleanup(self.registry.leave_test_mode)
@@ -1102,8 +1072,6 @@ class HttpCase(TransactionCase):
self.env.cache.invalidate()
return res
phantom_js = browser_js
def users(*logins):
""" Decorate a method to execute it once for each given user. """