[REF] web: remove top level await

This PR removes two top level await in test files and reorganizes a bit the tests setup as the module loading sequence has changed. This PR also fixes some bugs spotted during dev. The goal of removing async modules is to simplify the module loader in the future.

task id: 3265979

closes odoo/odoo#121185

Signed-off-by: Mathieu Duckerts-Antoine (dam) <dam@odoo.com>
This commit is contained in:
Odoo's Mergebot
2023-07-05 15:58:21 +02:00
committed by GitHub
11 changed files with 115 additions and 125 deletions
@@ -16,12 +16,11 @@ import { registerCleanup } from "@web/../tests/helpers/cleanup";
import {
clearRegistryWithCleanup,
registryNamesToCloneWithCleanup,
utils,
prepareRegistriesWithCleanup,
} from "@web/../tests/helpers/mock_env";
import { getFixture, makeDeferred, patchWithCleanup } from "@web/../tests/helpers/utils";
import { doAction, getActionManagerServerData } from "@web/../tests/webclient/helpers";
const { prepareRegistriesWithCleanup } = utils;
const { afterNextRender } = App;
// load emoji data once, when the test suite starts.
@@ -21,7 +21,6 @@ export function memoize(func) {
}[funcName];
}
let idCounter = 0;
/**
* Generate a unique integer id (unique within the entire client session).
* Useful for temporary DOM ids.
@@ -30,5 +29,7 @@ let idCounter = 0;
* @returns {string}
*/
export function uniqueId(prefix = "") {
return `${prefix}${++idCounter}`;
return `${prefix}${++uniqueId.nextId}`;
}
// set nextId on the function itself to be able to patch then
uniqueId.nextId = 0;
@@ -10,7 +10,7 @@ import { uiService } from "@web/core/ui/ui_service";
import { useSetupView } from "@web/views/view_hook";
import { ActionDialog } from "@web/webclient/actions/action_dialog";
import { hotkeyService } from "@web/core/hotkeys/hotkey_service";
import { makeTestEnv, utils } from "../../helpers/mock_env";
import { makeTestEnv, prepareRegistriesWithCleanup } from "../../helpers/mock_env";
import {
fakeCompanyService,
fakeCommandService,
@@ -33,7 +33,6 @@ import { editSearchView, editView, setDefaults, viewMetadata } from "@web/views/
import { fieldService } from "@web/core/field_service";
import { Component, xml } from "@odoo/owl";
const { prepareRegistriesWithCleanup } = utils;
export class DebugMenuParent extends Component {
setup() {
@@ -1,6 +1,7 @@
/** @odoo-module **/
import { memoize, uniqueId } from "@web/core/utils/functions";
import { patchWithCleanup } from "../../helpers/utils";
QUnit.module("utils", () => {
QUnit.module("Functions");
@@ -70,6 +71,7 @@ QUnit.module("utils", () => {
});
QUnit.test("uniqueId", (assert) => {
patchWithCleanup(uniqueId, { nextId: 0 });
assert.strictEqual(uniqueId("test_"), "test_1");
assert.strictEqual(uniqueId("bla"), "bla2");
assert.strictEqual(uniqueId("test_"), "test_3");
-12
View File
@@ -1,12 +0,0 @@
odoo.define(
"web.test_legacy",
["web.session", "web.SessionOverrideForTests", "web.test_utils"],
async (require) => {
require("web.SessionOverrideForTests");
require("web.test_utils");
const session = require("web.session");
await session.is_bound; // await for templates from server
return { legacyProm: session.is_bound };
}
);
+27 -25
View File
@@ -60,36 +60,38 @@ export const registryNamesToCloneWithCleanup = [
"wowlToLegacyServiceMappers",
];
function prepareRegistriesWithCleanup() {
// Clone registries
registryNamesToCloneWithCleanup.forEach((registryName) =>
cloneRegistryWithCleanup(registry.category(registryName))
);
export const utils = {
prepareRegistriesWithCleanup() {
// Clone registries
registryNamesToCloneWithCleanup.forEach((registryName) =>
cloneRegistryWithCleanup(registry.category(registryName))
);
// Clear registries
clearRegistryWithCleanup(registry.category("command_categories"));
clearRegistryWithCleanup(registry.category("debug"));
clearRegistryWithCleanup(registry.category("error_dialogs"));
clearRegistryWithCleanup(registry.category("favoriteMenu"));
clearRegistryWithCleanup(registry.category("ir.actions.report handlers"));
clearRegistryWithCleanup(registry.category("main_components"));
clearRegistryWithCleanup(registry.category("wowlToLegacyServiceMappers"));
// Clear registries
clearRegistryWithCleanup(registry.category("command_categories"));
clearRegistryWithCleanup(registry.category("debug"));
clearRegistryWithCleanup(registry.category("error_dialogs"));
clearRegistryWithCleanup(registry.category("favoriteMenu"));
clearRegistryWithCleanup(registry.category("ir.actions.report handlers"));
clearRegistryWithCleanup(registry.category("main_components"));
clearRegistryWithCleanup(registry.category("wowlToLegacyServiceMappers"));
clearRegistryWithCleanup(registry.category("services"));
clearServicesMetadataWithCleanup();
clearRegistryWithCleanup(registry.category("services"));
clearServicesMetadataWithCleanup();
clearRegistryWithCleanup(registry.category("systray"));
clearRegistryWithCleanup(registry.category("user_menuitems"));
clearRegistryWithCleanup(registry.category("kanban_examples"));
clearRegistryWithCleanup(registry.category("__processed_archs__"));
// fun fact: at least one registry is missing... this shows that we need a
// better design for the way we clear these registries...
}
clearRegistryWithCleanup(registry.category("systray"));
clearRegistryWithCleanup(registry.category("user_menuitems"));
clearRegistryWithCleanup(registry.category("kanban_examples"));
clearRegistryWithCleanup(registry.category("__processed_archs__"));
// fun fact: at least one registry is missing... this shows that we need a
// better design for the way we clear these registries...
},
};
// This is exported in a utils object to allow for patching
export const utils = {
prepareRegistriesWithCleanup,
};
export function prepareRegistriesWithCleanup() {
return utils.prepareRegistriesWithCleanup();
}
/**
* @typedef {import("@web/env").OdooEnv} OdooEnv
+1 -1
View File
@@ -1,4 +1,4 @@
/** @odoo-module alias=web.SessionOverrideForTests **/
/** @odoo-module **/
// Override the Session.session_reload function
// The wowl test infrastructure does set a correct odoo global value before each test
@@ -1,5 +1,4 @@
odoo.define('web.test_utils', ["web.session", "web.test_utils_create", "web.test_utils_control_panel", "web.test_utils_dom", "web.test_utils_fields", "web.test_utils_file", "web.test_utils_form", "web.test_utils_graph", "web.test_utils_kanban", "web.test_utils_mock", "web.test_utils_modal", "web.test_utils_pivot", "web.tools"], async function (require) {
"use strict";
/** @odoo-module alias=web.test_utils **/
/**
* Test Utils
@@ -10,19 +9,18 @@ odoo.define('web.test_utils', ["web.session", "web.test_utils_create", "web.test
* instance of a view, appended in the dom, ready to be tested.
*/
const session = require('web.session');
const testUtilsCreate = require('web.test_utils_create');
const testUtilsControlPanel = require('web.test_utils_control_panel');
const testUtilsDom = require('web.test_utils_dom');
const testUtilsFields = require('web.test_utils_fields');
const testUtilsFile = require('web.test_utils_file');
const testUtilsForm = require('web.test_utils_form');
const testUtilsGraph = require('web.test_utils_graph');
const testUtilsKanban = require('web.test_utils_kanban');
const testUtilsMock = require('web.test_utils_mock');
const testUtilsModal = require('web.test_utils_modal');
const testUtilsPivot = require('web.test_utils_pivot');
const tools = require('web.tools');
import testUtilsCreate from "web.test_utils_create";
import testUtilsControlPanel from "web.test_utils_control_panel";
import testUtilsDom from "web.test_utils_dom";
import testUtilsFields from "web.test_utils_fields";
import testUtilsFile from "web.test_utils_file";
import testUtilsForm from "web.test_utils_form";
import testUtilsGraph from "web.test_utils_graph";
import testUtilsKanban from "web.test_utils_kanban";
import testUtilsMock from "web.test_utils_mock";
import testUtilsModal from "web.test_utils_modal";
import testUtilsPivot from "web.test_utils_pivot";
import tools from "web.tools";
function deprecated(fn, type) {
@@ -113,15 +111,7 @@ odoo.define('web.test_utils', ["web.session", "web.test_utils_create", "web.test
return testUtilsDom.returnAfterNextAnimationFrame();
}
// Loading static files cannot be properly simulated when their real content is
// really needed. This is the case for static XML files so we load them here,
// before starting the qunit test suite.
// (session.js is in charge of loading the static xml bundle and we also have
// to load xml files that are normally lazy loaded by specific widgets).
// Assets can also contain static xml files. They are loaded when the session
// is launched.
await session.is_bound;
return {
export default {
mock: {
addMockEnvironment: testUtilsMock.addMockEnvironment,
addMockEnvironmentOwl: testUtilsMock.addMockEnvironmentOwl,
@@ -266,4 +256,3 @@ odoo.define('web.test_utils', ["web.session", "web.test_utils_create", "web.test
triggerPositionalMouseEvent: deprecated(testUtilsDom.triggerPositionalMouseEvent, 'dom'),
unpatch: deprecated(testUtilsMock.unpatch, 'mock'),
};
});
+52 -52
View File
@@ -7,9 +7,8 @@ import { assets, templates } from "@web/core/assets";
import { browser, makeRAMLocalStorage } from "@web/core/browser/browser";
import { nextTick, patchTimeZone, patchWithCleanup } from "@web/../tests/helpers/utils";
import { memoize } from "@web/core/utils/functions";
import { legacyProm } from "web.test_legacy";
import { registerCleanup } from "./helpers/cleanup";
import { utils } from "./helpers/mock_env";
import { prepareRegistriesWithCleanup } from "./helpers/mock_env";
import { session as sessionInfo } from "@web/session";
import { config as transitionConfig } from "@web/core/transition";
import { loadLanguages } from "@web/core/l10n/translation";
@@ -19,8 +18,7 @@ transitionConfig.disabled = true;
import { patch } from "@web/core/utils/patch";
import { App, whenReady } from "@odoo/owl";
import { currencies } from "@web/core/currency";
const { prepareRegistriesWithCleanup } = utils;
import "./helpers/session";
function stringifyObjectValues(obj, properties) {
let res = "";
@@ -300,59 +298,52 @@ function removeUnwantedAttrsFromTemplates(attrs) {
}
}
// alt attribute causes issues with scroll tests. Indeed, alt is
// displayed between the time we scroll programatically and the time
// we assert for the scroll position. The src attribute is removed
// as well to make sure images won't trigger a GET request on the
// server.
// Clean up templates that have already been added.
removeUnwantedAttrsFromTemplates(["alt", "src"]);
const { loadXML, getBundle, loadJS, loadCSS } = assets;
patch(assets, "TestAssetsLoadXML", {
loadXML: function (templates) {
console.log("%c[assets] fetch XML ressource", "color: #66e; font-weight: bold;");
// Clean up new templates that might be added later.
loadXML(templates);
removeUnwantedAttrsFromTemplates(["alt", "src"]);
},
getBundle: memoize(async function (xmlID) {
console.log(
"%c[assets] fetch libs from xmlID: " + xmlID,
"color: #66e; font-weight: bold;"
);
return getBundle(xmlID);
}),
loadJS: memoize(async function (ressource) {
if (ressource.match(/\/static(\/\S+\/|\/)libs?/)) {
function patchAssets() {
const { loadXML, getBundle, loadJS, loadCSS } = assets;
patch(assets, "TestAssetsLoadXML", {
loadXML: function (templates) {
console.log("%c[assets] fetch XML ressource", "color: #66e; font-weight: bold;");
// Clean up new templates that might be added later.
loadXML(templates);
removeUnwantedAttrsFromTemplates(["alt", "src"]);
},
getBundle: memoize(async function (xmlID) {
console.log(
"%c[assets] fetch (mock) JS ressource: " + ressource,
"%c[assets] fetch libs from xmlID: " + xmlID,
"color: #66e; font-weight: bold;"
);
return nextTick();
}
console.log(
"%c[assets] fetch JS ressource: " + ressource,
"color: #66e; font-weight: bold;"
);
return loadJS(ressource);
}),
loadCSS: memoize(async function (ressource) {
if (ressource.match(/\/static(\/\S+\/|\/)libs?/)) {
return getBundle(xmlID);
}),
loadJS: memoize(async function (ressource) {
if (ressource.match(/\/static(\/\S+\/|\/)libs?/)) {
console.log(
"%c[assets] fetch (mock) JS ressource: " + ressource,
"color: #66e; font-weight: bold;"
);
return nextTick();
}
console.log(
"%c[assets] fetch (mock) CSS ressource: " + ressource,
"%c[assets] fetch JS ressource: " + ressource,
"color: #66e; font-weight: bold;"
);
return nextTick();
}
console.log(
"%c[assets] fetch CSS ressource: " + ressource,
"color: #66e; font-weight: bold;"
);
return loadCSS(ressource);
}),
});
return loadJS(ressource);
}),
loadCSS: memoize(async function (ressource) {
if (ressource.match(/\/static(\/\S+\/|\/)libs?/)) {
console.log(
"%c[assets] fetch (mock) CSS ressource: " + ressource,
"color: #66e; font-weight: bold;"
);
return nextTick();
}
console.log(
"%c[assets] fetch CSS ressource: " + ressource,
"color: #66e; font-weight: bold;"
);
return loadCSS(ressource);
}),
});
}
export async function setupTests() {
// uncomment to debug memory leaks in qunit suite
@@ -389,7 +380,16 @@ export async function setupTests() {
patchOwlApp();
});
await Promise.all([whenReady(), legacyProm]);
await Promise.all([whenReady(), session.is_bound]);
// alt attribute causes issues with scroll tests. Indeed, alt is
// displayed between the time we scroll programatically and the time
// we assert for the scroll position. The src attribute is removed
// as well to make sure images won't trigger a GET request on the
// server.
// Clean up templates that have already been added.
removeUnwantedAttrsFromTemplates(["alt", "src"]);
patchAssets();
// make sure images do not trigger a GET on the server
new MutationObserver((mutations) => {
@@ -13041,6 +13041,13 @@ QUnit.module("Views", (hooks) => {
QUnit.test(
"coming to an action with an error from a form view with a dirty x2m",
async function (assert) {
const handler = (ev) => {
// need to preventDefault to remove error from console (so python test pass)
ev.preventDefault();
};
window.addEventListener("unhandledrejection", handler);
registerCleanup(() => window.removeEventListener("unhandledrejection", handler));
class TestClientAction extends Component {
setup() {
throw new Error("Something went wrong");
@@ -13124,6 +13131,13 @@ QUnit.module("Views", (hooks) => {
QUnit.test(
"coming to an action with an error from a form view with a record in creation",
async function (assert) {
const handler = (ev) => {
// need to preventDefault to remove error from console (so python test pass)
ev.preventDefault();
};
window.addEventListener("unhandledrejection", handler);
registerCleanup(() => window.removeEventListener("unhandledrejection", handler));
class TestClientAction extends Component {
setup() {
throw new Error("Something went wrong");
@@ -19,10 +19,6 @@ import { effectService } from "@web/core/effects/effect_service";
import { hotkeyService } from "@web/core/hotkeys/hotkey_service";
import { menuService } from "@web/webclient/menus/menu_service";
import { WebClient } from "@web/webclient/webclient";
// This import is needed because of it's sideeffects, for exemple :
// web.test_utils easyload xml templates at line : 124:130.
// Also it set the autocomplete delay time for the field Many2One at 0 for the tests at line : 132:137
import "web.test_legacy";
import AbstractService from "web.AbstractService";
import ActionMenus from "web.ActionMenus";
import basicFields from "web.basic_fields";