diff --git a/addons/web/static/src/webclient/actions/action_service.js b/addons/web/static/src/webclient/actions/action_service.js index 8396063e903..ab5cf6b5f77 100644 --- a/addons/web/static/src/webclient/actions/action_service.js +++ b/addons/web/static/src/webclient/actions/action_service.js @@ -1237,6 +1237,7 @@ function makeActionManager(env) { * @returns {Promise} */ async function switchView(viewType, props = {}) { + await keepLast.add(Promise.resolve()); const controller = controllerStack[controllerStack.length - 1]; const view = _getView(viewType); if (!view) { @@ -1296,6 +1297,7 @@ function makeActionManager(env) { * @param {string} jsId */ async function restore(jsId) { + await keepLast.add(Promise.resolve()); let index; if (!jsId) { index = controllerStack.length - 2; diff --git a/addons/web/static/tests/webclient/actions/concurrency_tests.js b/addons/web/static/tests/webclient/actions/concurrency_tests.js index f54d76fcb00..6fdaf48b963 100644 --- a/addons/web/static/tests/webclient/actions/concurrency_tests.js +++ b/addons/web/static/tests/webclient/actions/concurrency_tests.js @@ -466,6 +466,84 @@ QUnit.module("ActionManager", (hooks) => { } ); + QUnit.test("restoring a controller when doing an action -- load_action slow", async function (assert) { + assert.expect(14); + let def; + const mockRPC = async (route, args) => { + assert.step((args && args.method) || route); + if (route === "/web/action/load") { + return Promise.resolve(def); + } + }; + const webClient = await createWebClient({ serverData, mockRPC }); + await doAction(webClient, 3); + assert.containsOnce(target, ".o_list_view"); + await click(target.querySelector(".o_list_view .o_data_cell")); + await legacyExtraNextTick(); + assert.containsOnce(target, ".o_form_view"); + def = makeDeferred(); + doAction(webClient, 4, { clearBreadcrumbs: true }); + await nextTick(); + await legacyExtraNextTick(); + assert.containsOnce(target, ".o_form_view", "should still contain the form view"); + await click(target.querySelector(".o_control_panel .breadcrumb-item a")); + def.resolve(); + await nextTick(); + await legacyExtraNextTick(); + assert.containsOnce(target, ".o_list_view"); + assert.strictEqual( + target.querySelector(".o_control_panel .breadcrumb-item").textContent, + "Partners" + ); + assert.containsNone(target, ".o_form_view"); + assert.verifySteps([ + "/web/webclient/load_menus", + "/web/action/load", + "load_views", + "/web/dataset/search_read", + "read", + "/web/action/load", + "/web/dataset/search_read", + ]); + }); + + QUnit.test("switching when doing an action -- load_action slow", async function (assert) { + assert.expect(12); + let def; + const mockRPC = async (route, args) => { + assert.step((args && args.method) || route); + if (route === "/web/action/load") { + return Promise.resolve(def); + } + }; + const webClient = await createWebClient({ serverData, mockRPC }); + await doAction(webClient, 3); + assert.containsOnce(target, ".o_list_view"); + def = makeDeferred(); + doAction(webClient, 4, { clearBreadcrumbs: true }); + await nextTick(); + await legacyExtraNextTick(); + assert.containsOnce(target, ".o_list_view", "should still contain the list view"); + await switchView(target, "kanban"); + def.resolve(); + await nextTick(); + await legacyExtraNextTick(); + assert.containsOnce(target, ".o_kanban_view"); + assert.strictEqual( + target.querySelector(".o_control_panel .breadcrumb-item").textContent, + "Partners" + ); + assert.containsNone(target, ".o_list_view"); + assert.verifySteps([ + "/web/webclient/load_menus", + "/web/action/load", + "load_views", + "/web/dataset/search_read", + "/web/action/load", + "/web/dataset/search_read", + ]); + }); + QUnit.test("switching when doing an action -- load_views slow", async function (assert) { assert.expect(13); let def;