From 79f1da291b64c5c0e6d60228f08cc61cc533ecf0 Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Wed, 5 Oct 2022 09:04:34 +0000 Subject: [PATCH] [FIX] web: remove recursive errors in tests Before this commit, in debug=assets, if a test crashed for instance because we try to click on an element that doesn't exist, we tried to load the stacktrace js lib, via loadJS. However, in the test environment, loadJS is patched to go through mockRPC. If in that particular test, mockRPC did an assertion (e.g. assert.step), we entered an infinite loop of loadJS calls, which obviously made the tab crash. With this commit, we ensure to use the real loadJS function when we want to fetch the stacktrace lib. closes odoo/odoo#102295 X-original-commit: 0661c8fa1dad88b1f9c9e177e25ddb97211f55a2 Signed-off-by: Samuel Degueldre Signed-off-by: Aaron Bohy (aab) --- addons/web/static/src/core/assets.js | 74 +++++++++---------- .../web/static/src/core/errors/error_utils.js | 4 +- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/addons/web/static/src/core/assets.js b/addons/web/static/src/core/assets.js index 705f0110227..2a2599db9de 100644 --- a/addons/web/static/src/core/assets.js +++ b/addons/web/static/src/core/assets.js @@ -20,7 +20,7 @@ class AssetsLoadingError extends Error {} * @param {string} url the url of the script * @returns {Promise} resolved when the script has been loaded */ -assets.loadJS = memoize(function loadJS(url) { +export const _loadJS = (assets.loadJS = memoize(function loadJS(url) { if (document.querySelector(`script[src="${url}"]`)) { // Already in the DOM and wasn't loaded through this function // Unfortunately there is no way to check whether a script has loaded @@ -39,7 +39,7 @@ assets.loadJS = memoize(function loadJS(url) { reject(new AssetsLoadingError(`The loading of ${url} failed`)); }); }); -}); +})); /** * Loads the given url as a stylesheet. @@ -47,7 +47,7 @@ assets.loadJS = memoize(function loadJS(url) { * @param {string} url the url of the stylesheet * @returns {Promise} resolved when the stylesheet has been loaded */ -assets.loadCSS = memoize(function loadCSS(url) { +export const _loadCSS = (assets.loadCSS = memoize(function loadCSS(url) { if (document.querySelector(`link[href="${url}"]`)) { // Already in the DOM and wasn't loaded through this function // Unfortunately there is no way to check whether a link has loaded @@ -66,7 +66,7 @@ assets.loadCSS = memoize(function loadCSS(url) { reject(new AssetsLoadingError(`The loading of ${url} failed`)); }); }); -}); +})); /** * Container dom containing all the owl templates that have been loaded. @@ -84,30 +84,30 @@ let defaultApp; * can be changed with setLoadXmlDefaultApp method) * @returns {Promise} resolved when the template xml has been loaded */ - assets.loadXML = function loadXML (xml, app=defaultApp) { +export const _loadXML = (assets.loadXML = function loadXML(xml, app = defaultApp) { const doc = new DOMParser().parseFromString(xml, "text/xml"); - if (doc.querySelector('parsererror')) { - throw doc.querySelector('parsererror div').textContent.split(':')[0]; + if (doc.querySelector("parsererror")) { + throw doc.querySelector("parsererror div").textContent.split(":")[0]; } for (const element of doc.querySelectorAll("templates > [t-name][owl]")) { element.removeAttribute("owl"); - const name = element.getAttribute('t-name'); + const name = element.getAttribute("t-name"); const previous = templates.querySelector(`[t-name="${name}"]`); if (previous) { - console.debug('Override template: ' + name); + console.debug("Override template: " + name); previous.replaceWith(element); } else { templates.documentElement.appendChild(element); } } if (app || defaultApp) { - console.debug('Add templates in Owl app.'); + console.debug("Add templates in Owl app."); app.addTemplates(templates, app || defaultApp); } else { - console.debug('Add templates on window Owl container.'); + console.debug("Add templates on window Owl container."); } -}; +}); /** * Update the default app to load templates. * @@ -123,7 +123,7 @@ export function setLoadXmlDefaultApp(app) { * @param {string} bundleName Name of the bundle containing the list of files * @returns {Promise<{cssLibs, cssContents, jsLibs, jsContents}>} */ -assets.getBundle = memoize(async function getBundle(bundleName) { +export const _getBundle = (assets.getBundle = memoize(async function getBundle(bundleName) { const url = new URL(`/web/bundle/${bundleName}`, location.origin); for (const [key, value] of Object.entries(session.bundle_params || {})) { url.searchParams.set(key, value); @@ -138,9 +138,9 @@ assets.getBundle = memoize(async function getBundle(bundleName) { }; for (const key in json) { const file = json[key]; - if (file.type === 'link') { + if (file.type === "link") { assets.cssLibs.push(file.src); - } else if (file.type === 'style') { + } else if (file.type === "style") { assets.cssContents.push(file.content); } else { if (file.src) { @@ -151,7 +151,7 @@ assets.getBundle = memoize(async function getBundle(bundleName) { } } return assets; -}); +})); /** * Loads the given js/css libraries and asset bundles. Note that no library or @@ -181,24 +181,24 @@ assets.getBundle = memoize(async function getBundle(bundleName) { * * @returns {Promise} */ -assets.loadBundle = memoize(async function loadBundle(desc) { +export const _loadBundle = (assets.loadBundle = memoize(async function loadBundle(desc) { // Load css in parallel const promiseCSS = Promise.all((desc.cssLibs || []).map(assets.loadCSS)).then(() => { if (desc.cssContents && desc.cssContents.length) { const style = document.createElement("style"); - style.textContent = desc.cssContents.join('\n'); + style.textContent = desc.cssContents.join("\n"); document.head.appendChild(style); } }); // Load JavaScript (don't wait for the css loading) for (const urlData of desc.jsLibs || []) { - if (typeof urlData === 'string') { + if (typeof urlData === "string") { // serial loading await assets.loadJS(urlData); // Wait template if the JavaScript come from bundle. - const bundle = urlData.match(/\/web\/assets\/.*\/([^\/]+?)(\.min)?\.js/); + const bundle = urlData.match(/\/web\/assets\/.*\/([^/]+?)(\.min)?\.js/); if (bundle) { - await odoo.ready(bundle[1] + '.bundle.xml'); + await odoo.ready(bundle[1] + ".bundle.xml"); } } else { // parallel loading @@ -209,44 +209,44 @@ assets.loadBundle = memoize(async function loadBundle(desc) { if (desc.jsContents && desc.jsContents.length) { const script = document.createElement("script"); script.type = "text/javascript"; - script.textContent = desc.jsContents.join('\n'); + script.textContent = desc.jsContents.join("\n"); document.head.appendChild(script); } // Wait for the scc loading to be completed before loading the other bundle await promiseCSS; // Load other desc for (const bundleName of desc.assetLibs || []) { - if (typeof bundleName === 'string') { + if (typeof bundleName === "string") { // serial loading const desc = await assets.getBundle(bundleName); await assets.loadBundle(desc); } else { // parallel loading - await Promise.all(bundleName.map(async bundleName => { - const desc = await assets.getBundle(bundleName); - return assets.loadBundle(desc); - })); + await Promise.all( + bundleName.map(async (bundleName) => { + const desc = await assets.getBundle(bundleName); + return assets.loadBundle(desc); + }) + ); } } -}); - +})); export const loadJS = function (url) { return assets.loadJS(url); -} +}; export const loadCSS = function (url) { return assets.loadCSS(url); -} -export const loadXML = function (xml, app=defaultApp) { - return assets.loadXML(xml, app=app); -} +}; +export const loadXML = function (xml, app = defaultApp) { + return assets.loadXML(xml, app); +}; export const getBundle = function (bundleName) { return assets.getBundle(bundleName); -} +}; export const loadBundle = function (desc) { return assets.loadBundle(desc); -} - +}; const { Component, xml, onWillStart } = owl; /** diff --git a/addons/web/static/src/core/errors/error_utils.js b/addons/web/static/src/core/errors/error_utils.js index d63d722562a..8ba710c9821 100644 --- a/addons/web/static/src/core/errors/error_utils.js +++ b/addons/web/static/src/core/errors/error_utils.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { loadJS } from "../assets"; +import { _loadJS } from "../assets"; // use the real, non patched (in tests), loadJS import { isBrowserChrome } from "../browser/feature_detection"; /** @typedef {import("./error_service").UncaughtError} UncaughtError */ @@ -147,7 +147,7 @@ export function formatTraceback(error) { export async function annotateTraceback(error) { const traceback = formatTraceback(error); try { - await loadJS("/web/static/lib/stacktracejs/stacktrace.js"); + await _loadJS("/web/static/lib/stacktracejs/stacktrace.js"); } catch (_e) { return traceback; }