odoo.define('web_tour.tour_manager_tests', async function (require) { "use strict"; const core = require("web.core"); const KanbanView = require('web.KanbanView'); const TourManager = require('web_tour.TourManager'); const testUtils = require('web.test_utils'); const createView = testUtils.createView; /** * Create a widget and a TourManager instance with a list of given Tour objects. * @see `TourManager.register()` for more details on the Tours registry system. * @param {Object} params aside from the parameters defined below, passed * to {@see addMockEnvironment}. * @param {string[]} [params.consumed_tours] * @param {boolean} [params.debug] also passed along * @param {boolean} [params.disabled] * @param {string} params.template inner HTML content of the widget * @param {Object[]} params.tours { {string} name, {Object} option, {Object[]} steps } */ async function createTourManager({ consumed_tours, disabled, template, tours, ...params }) { const parent = await testUtils.createParent(params); const tourManager = new TourManager(parent, consumed_tours, disabled); tourManager.running_step_delay = 0; for (const { name, options, steps } of tours) { tourManager.register(name, options, steps); } const _destroy = tourManager.destroy; tourManager.destroy = function () { tourManager.destroy = _destroy; parent.destroy(); }; await parent.prependTo(testUtils.prepareTarget(params.debug)); parent.el.innerHTML = template; await tourManager._register_all(true); // Wait for possible tooltips to be loaded and appended. await testUtils.nextTick(); return tourManager; } QUnit.module("Tours", function () { QUnit.module("Tour manager"); QUnit.test("Tours sequence", async function (assert) { assert.expect(2); const tourManager = await createTourManager({ template: ` <button class="btn anchor">Anchor</button>`, tours: [ { name: "Tour 1", options: { sequence: 10 }, steps: [{ trigger: '.anchor' }] }, { name: "Tour 2", options: {}, steps: [{ trigger: '.anchor' }] }, { name: "Tour 3", options: { sequence: 5 }, steps: [{ trigger: '.anchor', content: "Oui" }] }, ], // Use this test in "debug" mode because the tips need to be in // the viewport to be able to test their normal content // (otherwise, the tips would indicate to the users that they // have to scroll). debug: true, }); assert.containsOnce(document.body, '.o_tooltip:visible'); assert.strictEqual($('.o_tooltip_content:visible').text(), "Oui", "content should be that of the third tour"); tourManager.destroy(); }); QUnit.test("Displays a rainbow man by default at the end of tours", async function (assert) { assert.expect(3); function onShowEffect(params) { assert.deepEqual(params, { fadeout: "medium", message: owl.markup("<strong><b>Good job!</b> You went through all steps of this tour.</strong>"), type: "rainbow_man" }); } core.bus.on("show-effect", null, onShowEffect); const tourManager = await createTourManager({ data: { 'web_tour.tour': { fields: {}, consume() {} } }, template: `<button class="btn anchor">Anchor</button>`, tours: [{ name: "Some tour", options: {}, steps: [{ trigger: '.anchor', content: "anchor" }], }], // Use this test in "debug" mode because the tips need to be in // the viewport to be able to test their normal content // (otherwise, the tips would indicate to the users that they // have to scroll). debug: true, }); assert.containsOnce(document.body, '.o_tooltip'); await testUtils.dom.click($('.anchor')); assert.containsNone(document.body, '.o_tooltip'); tourManager.destroy(); core.bus.off("show-effect", onShowEffect); }); QUnit.test("Click on invisible tip consumes it", async function (assert) { assert.expect(5); const tourManager = await createTourManager({ data: { 'web_tour.tour': { fields: {}, consume() {} } }, template: ` <button class="btn anchor1">Anchor</button> <button class="btn anchor2">Anchor</button> `, tours: [{ name: "Tour 1", options: { rainbowMan: false, sequence: 10 }, steps: [{ trigger: '.anchor1', content: "1" }], }, { name: "Tour 2", options: { rainbowMan: false, sequence: 5 }, steps: [{ trigger: '.anchor2', content: "2" }], }], // Use this test in "debug" mode because the tips need to be in // the viewport to be able to test their normal content // (otherwise, the tips would indicate to the users that they // have to scroll). debug: true, }); assert.containsN(document.body, '.o_tooltip', 2); assert.strictEqual($('.o_tooltip_content:visible').text(), "2"); await testUtils.dom.click($('.anchor1')); assert.containsOnce(document.body, '.o_tooltip'); assert.strictEqual($('.o_tooltip_content:visible').text(), "2"); await testUtils.dom.click($('.anchor2')); assert.containsNone(document.body, '.o_tooltip'); tourManager.destroy(); }); QUnit.test("Step anchor replaced", async function (assert) { assert.expect(3); const tourManager = await createTourManager({ observe: true, template: `<input class="anchor"/>`, tours: [{ name: "Tour", options: { rainbowMan: false }, steps: [{ trigger: "input.anchor" }], }], }); assert.containsOnce(document.body, '.o_tooltip:visible'); const $anchor = $(".anchor"); const $parent = $anchor.parent(); $parent.empty(); $parent.append($anchor); // Simulates the observer picking up the mutation and triggering an update tourManager.update(); await testUtils.nextTick(); assert.containsOnce(document.body, '.o_tooltip:visible'); await testUtils.fields.editInput($('.anchor'), "AAA"); assert.containsNone(document.body, '.o_tooltip:visible'); tourManager.destroy(); }); QUnit.test("kanban quick create VS tour tooltips", async function (assert) { assert.expect(3); const kanban = await createView({ View: KanbanView, model: 'partner', data: { partner: { fields: { foo: {string: "Foo", type: "char"}, bar: {string: "Bar", type: "boolean"}, }, records: [ {id: 1, bar: true, foo: "yop"}, ] } }, arch: `<kanban> <field name="bar"/> <templates><t t-name="kanban-box"> <div><field name="foo"/></div> </t></templates> </kanban>`, groupBy: ['bar'], }); // click to add an element await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); assert.containsOnce(kanban, '.o_kanban_quick_create', "should have open the quick create widget"); // create tour manager targeting the kanban quick create in its steps const tourManager = await createTourManager({ observe: true, template: kanban.$el.html(), tours: [{ name: "Tour", options: { rainbowMan: false }, steps: [{ trigger: "input[name='display_name']" }], }], }); assert.containsOnce(document.body, '.o_tooltip:visible'); await testUtils.dom.click($('.o_tooltip:visible')); assert.containsOnce(kanban, '.o_kanban_quick_create', "the quick create should not have been destroyed when tooltip is clicked"); kanban.destroy(); tourManager.destroy(); }); QUnit.test("Automatic tour disabling", async function (assert) { assert.expect(2); const options = { template: `<button class="btn anchor">Anchor</button>`, tours: [{ name: "Tour", options: {}, steps: [{ trigger: '.anchor' }] }], }; const enabledTM = await createTourManager({ disabled: false, ...options }); assert.containsOnce(document.body, '.o_tooltip:visible'); enabledTM.destroy(); const disabledTM = await createTourManager({ disabled: true, ...options }); assert.containsNone(document.body, '.o_tooltip:visible'); disabledTM.destroy(); }); }); });