From 210c03fde05574a7731481e7cd342166e771aa63 Mon Sep 17 00:00:00 2001 From: Julien Mougenot Date: Thu, 2 Nov 2023 11:29:08 +0100 Subject: [PATCH] [FIX] web_tour: ensure tours are run only once Before this commit, tours could be resumed AND started in the same sequence, causing object mismatches in the tour service internals and resulting in multiple tooltips being displayed at the same time. This commit ensures that a tour instance can only be run once at a time. closes odoo/odoo#140664 Signed-off-by: Mathieu Duckerts-Antoine (dam) --- .../static/src/tour_service/tour_service.js | 18 ++++++++++++++---- .../static/tests/tour_service_tests.js | 11 ++++++++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/addons/web_tour/static/src/tour_service/tour_service.js b/addons/web_tour/static/src/tour_service/tour_service.js index 6380af3fae7..6522094400b 100644 --- a/addons/web_tour/static/src/tour_service/tour_service.js +++ b/addons/web_tour/static/src/tour_service/tour_service.js @@ -66,14 +66,13 @@ export const tourService = { tours[name] = { name: tour.saveAs || name, get steps() { - if(typeof tour.steps === "function") { + if (typeof tour.steps === "function") { return tour.steps().map((step) => { step.shadow_dom = step.shadow_dom ?? tour.shadow_dom; return step; }); - } - else { - throw new Error(`tour.steps has to be a function that returns TourStep[]`) + } else { + throw new Error(`tour.steps has to be a function that returns TourStep[]`); } }, shadow_dom: tour.shadow_dom, @@ -106,6 +105,8 @@ export const tourService = { const consumedTours = new Set(session.web_tours); const pointers = reactive({}); + /** @type {Set} */ + const runningTours = new Set(); function createPointer(tourName, config) { const { state: pointerState, methods } = createPointerState(); @@ -214,6 +215,7 @@ export const tourService = { pointer.stop(); // Used to signal the python test runner that the tour finished without error. browser.console.log("test successful"); + runningTours.delete(name); }, }); } @@ -259,6 +261,10 @@ export const tourService = { } function startTour(tourName, options = {}) { + if (runningTours.has(tourName)) { + return; + } + runningTours.add(tourName); const defaultOptions = { stepDelay: 0, keepWatchBrowser: false, @@ -303,6 +309,10 @@ export const tourService = { } function resumeTour(tourName) { + if (runningTours.has(tourName)) { + return; + } + runningTours.add(tourName); const tour = tours[tourName]; const stepDelay = tourState.get(tourName, "stepDelay"); const keepWatchBrowser = tourState.get(tourName, "keepWatchBrowser"); diff --git a/addons/web_tour/static/tests/tour_service_tests.js b/addons/web_tour/static/tests/tour_service_tests.js index 66186929af7..8543ec3b066 100644 --- a/addons/web_tour/static/tests/tour_service_tests.js +++ b/addons/web_tour/static/tests/tour_service_tests.js @@ -365,7 +365,7 @@ QUnit.module("Tour service", (hooks) => { QUnit.test("perform edit on next step", async function (assert) { registry.category("web_tour.tours").add("tour1", { sequence: 10, - steps:() => [ + steps: () => [ { trigger: ".interval input", }, @@ -435,6 +435,15 @@ QUnit.module("Tour service", (hooks) => { }); QUnit.test("should show only 1 pointer at a time", async function (assert) { + const storage = new Map(); + patchWithCleanup(browser.localStorage, { + getItem: (key) => storage.get(key), + setItem: (key, value) => storage.set(key, value), + removeItem: (key) => storage.delete(key), + tour__tour1__sequence: 0, + tour__tour2__sequence: 0, + }); + registry.category("web_tour.tours").add("tour1", { sequence: 10, steps: () => [