diff --git a/addons/calendar/static/tests/systray_activity_menu_tests.js b/addons/calendar/static/tests/systray_activity_menu_tests.js index a8b0d24956c..3a0bcdd50f8 100644 --- a/addons/calendar/static/tests/systray_activity_menu_tests.js +++ b/addons/calendar/static/tests/systray_activity_menu_tests.js @@ -3,8 +3,10 @@ import { start, startServer } from '@mail/../tests/helpers/test_utils'; import ActivityMenu from '@mail/js/systray/systray_activity_menu'; +import { Items as legacySystrayItems } from 'web.SystrayMenu'; import testUtils from 'web.test_utils'; -import { patchDate } from "@web/../tests/helpers/utils"; +import { registerCleanup } from '@web/../tests/helpers/cleanup'; +import { patchDate, patchWithCleanup } from "@web/../tests/helpers/utils"; QUnit.module('calendar', {}, function () { QUnit.module('ActivityMenu'); @@ -29,23 +31,25 @@ QUnit.test('activity menu widget:today meetings', async function (assert) { attendee_ids: [calendarAttendeeId1], }, ]); - const { widget } = await start(); - - const activityMenu = new ActivityMenu(widget); - await activityMenu.appendTo($('#qunit-fixture')); - - assert.hasClass(activityMenu.$el, 'o_mail_systray_item', 'should be the instance of widget'); - - await testUtils.dom.click(activityMenu.$('.dropdown-toggle')); - - testUtils.mock.intercept(activityMenu, 'do_action', function (event) { - assert.strictEqual(event.data.action, "calendar.action_calendar_event", 'should open meeting calendar view in day mode'); + legacySystrayItems.push(ActivityMenu); + registerCleanup(() => legacySystrayItems.pop()); + const { wowlEnv: env } = await start({ + hasWebClient: true, }); - await testUtils.dom.click(activityMenu.$('.o_mail_preview')); + assert.containsOnce(document.body, '.o_mail_systray_item', 'should contain an instance of widget'); - assert.ok(activityMenu.$('.o_meeting_filter'), "should be a meeting"); - assert.containsN(activityMenu, '.o_meeting_filter', 2, 'there should be 2 meetings'); - assert.hasClass(activityMenu.$('.o_meeting_filter').eq(0), 'o_meeting_bold', 'this meeting is yet to start'); - assert.doesNotHaveClass(activityMenu.$('.o_meeting_filter').eq(1), 'o_meeting_bold', 'this meeting has been started'); + await testUtils.dom.click(document.querySelector('.dropdown-toggle[title="Activities"]')); + + patchWithCleanup(env.services.action, { + doAction(action) { + assert.strictEqual(action, "calendar.action_calendar_event", 'should open meeting calendar view in day mode'); + }, + }); + await testUtils.dom.click(document.querySelector('.o_mail_preview')); + + assert.ok(document.querySelector('.o_meeting_filter'), "should be a meeting"); + assert.containsN(document.body, '.o_meeting_filter', 2, 'there should be 2 meetings'); + assert.hasClass(document.querySelector('.o_meeting_filter'), 'o_meeting_bold', 'this meeting is yet to start'); + assert.doesNotHaveClass(document.querySelectorAll('.o_meeting_filter')[1], 'o_meeting_bold', 'this meeting has been started'); }); }); diff --git a/addons/mail/static/tests/helpers/test_utils.js b/addons/mail/static/tests/helpers/test_utils.js index 54e2d49da94..ed965ffaf03 100644 --- a/addons/mail/static/tests/helpers/test_utils.js +++ b/addons/mail/static/tests/helpers/test_utils.js @@ -189,6 +189,13 @@ async function getModelDefinitions() { } let pyEnv; +const VIEW_TYPE_TO_ARCH = { + activity: '', + form: '
', + list: '', + search: '', + kanban: '', +}; /** * Creates an environment that can be used to setup test data as well as * creating data after test start. @@ -198,6 +205,7 @@ let pyEnv; */ export async function startServer() { const data = { ...TEST_USER_IDS }; + const views = {}; const modelDefinitions = await modelDefinitionsPromise; const recordsToInsertRegistry = registry.category('mail.model.definitions').category('recordsToInsert'); for (const [modelName, fields] of modelDefinitions) { @@ -207,12 +215,20 @@ let pyEnv; records.push(...JSON.parse(JSON.stringify(recordsToInsertRegistry.get(modelName)))); } data[modelName] = { fields: { ...fields }, records }; + + // generate default views for this model. + for (const [viewType, viewArch] of Object.entries(VIEW_TYPE_TO_ARCH)) { + views[`${modelName},false,${viewType}`] = viewArch; + } } pyEnv = new Proxy( { ...TEST_USER_IDS, get currentPartner() { return this.mockServer.currentPartner; + }, + getViews() { + return views; } }, { @@ -761,6 +777,7 @@ async function start(param0 = {}) { if (hasWebClient) { param0.serverData = param0.serverData || getActionManagerServerData(); param0.serverData.models = data; + param0.serverData.views = { ...pyEnv.getViews(), ...param0.serverData.views }; } else { param0.data = data; } @@ -871,6 +888,7 @@ async function start(param0 = {}) { mockServer, pyEnv, widget, + wowlEnv: hasWebClient ? widget.env : undefined, }; if (hasTimeControl) { result['advanceTime'] = env.testUtils.advanceTime; @@ -898,7 +916,7 @@ async function start(param0 = {}) { result['discussWidget'] = discussWidget; } await waitUntilEventPromise; - const target = widget.el; + const target = hasWebClient ? webclientTarget : widget.el; return { ...result, afterNextRender, diff --git a/addons/note/static/tests/systray_activity_menu_tests.js b/addons/note/static/tests/systray_activity_menu_tests.js index 32dbdd9e85c..26c9567ef38 100644 --- a/addons/note/static/tests/systray_activity_menu_tests.js +++ b/addons/note/static/tests/systray_activity_menu_tests.js @@ -3,7 +3,9 @@ import ActivityMenu from '@mail/js/systray/systray_activity_menu'; import { start } from '@mail/../tests/helpers/test_utils'; +import { Items as legacySystrayItems } from 'web.SystrayMenu'; import testUtils from 'web.test_utils'; +import { registerCleanup } from '@web/../tests/helpers/cleanup'; QUnit.module('note', {}, function () { QUnit.module("ActivityMenu"); @@ -11,56 +13,56 @@ QUnit.module("ActivityMenu"); QUnit.test('note activity menu widget: create note from activity menu', async function (assert) { assert.expect(15); - const { widget } = await start(); + legacySystrayItems.push(ActivityMenu); + registerCleanup(() => legacySystrayItems.pop()); - const activityMenu = new ActivityMenu(widget); - await activityMenu.appendTo($('#qunit-fixture')); - assert.hasClass(activityMenu.$el, 'o_mail_systray_item', - 'should be the instance of widget'); + await start({ hasWebClient: true }); + assert.containsOnce(document.body, '.o_mail_systray_item', + 'should contain an instance of widget'); await testUtils.nextTick(); - assert.strictEqual(activityMenu.$('.o_notification_counter').text(), '0', + assert.strictEqual(document.querySelector('.o_notification_counter').innerText, '0', "should not have any activity notification initially"); // toggle quick create for note - await testUtils.dom.click(activityMenu.$('.dropdown-toggle')); - assert.containsOnce(activityMenu, '.o_no_activity', + await testUtils.dom.click(document.querySelector('.dropdown-toggle[title="Activities"]')); + assert.containsOnce(document.body, '.o_no_activity', "should not have any activity preview"); - assert.doesNotHaveClass(activityMenu.$('.o_note_show'), 'd-none', + assert.doesNotHaveClass(document.querySelector('.o_note_show'), 'd-none', 'ActivityMenu should have Add new note CTA'); - await testUtils.dom.click(activityMenu.$('.o_note_show')); - assert.hasClass(activityMenu.$('.o_note_show'), 'd-none', + await testUtils.dom.click(document.querySelector('.o_note_show')); + assert.hasClass(document.querySelector('.o_note_show'), 'd-none', 'ActivityMenu should hide CTA when entering a new note'); - assert.doesNotHaveClass(activityMenu.$('.o_note'), 'd-none', + assert.doesNotHaveClass(document.querySelector('.o_note'), 'd-none', 'ActivityMenu should display input for new note'); // creating quick note without date - await testUtils.fields.editInput(activityMenu.$("input.o_note_input"), "New Note"); - await testUtils.dom.click(activityMenu.$(".o_note_save")); - assert.strictEqual(activityMenu.$('.o_notification_counter').text(), '1', + await testUtils.fields.editInput(document.querySelector("input.o_note_input"), "New Note"); + await testUtils.dom.click(document.querySelector(".o_note_save")); + assert.strictEqual(document.querySelector('.o_notification_counter').innerText, '1', "should increment activity notification counter after creating a note"); - assert.containsOnce(activityMenu, '.o_mail_preview[data-res_model="note.note"]', + assert.containsOnce(document.body, '.o_mail_preview[data-res_model="note.note"]', "should have an activity preview that is a note"); - assert.strictEqual(activityMenu.$('.o_activity_filter_button[data-filter="today"]').text().trim(), + assert.strictEqual(document.querySelector('.o_activity_filter_button[data-filter="today"]').innerText.trim(), "1 Today", "should display one note for today"); - assert.doesNotHaveClass(activityMenu.$('.o_note_show'), 'd-none', + assert.doesNotHaveClass(document.querySelector('.o_note_show'), 'd-none', 'ActivityMenu add note button should be displayed'); - assert.hasClass(activityMenu.$('.o_note'), 'd-none', + assert.hasClass(document.querySelector('.o_note'), 'd-none', 'ActivityMenu add note input should be hidden'); // creating quick note with date - await testUtils.dom.click(activityMenu.$('.o_note_show')); - activityMenu.$('input.o_note_input').val("New Note"); - await testUtils.dom.click(activityMenu.$(".o_note_save")); - assert.strictEqual(activityMenu.$('.o_notification_counter').text(), '2', + await testUtils.dom.click(document.querySelector('.o_note_show')); + document.querySelector('input.o_note_input').value = "New Note"; + await testUtils.dom.click(document.querySelector(".o_note_save")); + assert.strictEqual(document.querySelector('.o_notification_counter').innerText, '2', "should increment activity notification counter after creating a second note"); - assert.strictEqual(activityMenu.$('.o_activity_filter_button[data-filter="today"]').text().trim(), + assert.strictEqual(document.querySelector('.o_activity_filter_button[data-filter="today"]').innerText.trim(), "2 Today", "should display 2 notes for today"); - assert.doesNotHaveClass(activityMenu.$('.o_note_show'), 'd-none', + assert.doesNotHaveClass(document.querySelector('.o_note_show'), 'd-none', 'ActivityMenu add note button should be displayed'); - assert.hasClass(activityMenu.$('.o_note'), 'd-none', + assert.hasClass(document.querySelector('.o_note'), 'd-none', 'ActivityMenu add note input should be hidden'); }); }); diff --git a/addons/test_mail/static/tests/systray_activity_menu_tests.js b/addons/test_mail/static/tests/systray_activity_menu_tests.js index 322e502df43..00690df9cd6 100644 --- a/addons/test_mail/static/tests/systray_activity_menu_tests.js +++ b/addons/test_mail/static/tests/systray_activity_menu_tests.js @@ -6,8 +6,13 @@ import { startServer, } from '@mail/../tests/helpers/test_utils'; +import session from 'web.session'; +import { Items as legacySystrayItems } from 'web.SystrayMenu'; import testUtils from 'web.test_utils'; import { date_to_str } from 'web.time'; +import { registerCleanup } from '@web/../tests/helpers/cleanup'; +import { patchWithCleanup } from '@web/../tests/helpers/utils'; + QUnit.module('test_mail', {}, function () { QUnit.module('systray_activity_menu_tests.js', { @@ -26,125 +31,130 @@ QUnit.module('systray_activity_menu_tests.js', { { date_deadline: date_to_str(tomorrow), res_id: mailTestActivityIds[2], res_model: 'mail.test.activity' }, { date_deadline: date_to_str(yesterday), res_id: mailTestActivityIds[3], res_model: 'mail.test.activity' }, ]); - this.session = { - uid: 10, - }; }, }); QUnit.test('activity menu widget: menu with no records', async function (assert) { assert.expect(1); - const { widget } = await start({ + legacySystrayItems.push(ActivityMenu); + registerCleanup(() => legacySystrayItems.pop()); + await start({ + hasWebClient: true, mockRPC: function (route, args) { if (args.method === 'systray_get_activities') { return Promise.resolve([]); } - return this._super(route, args); }, }); - const activityMenu = new ActivityMenu(widget); - await activityMenu.appendTo($('#qunit-fixture')); await testUtils.nextTick(); - assert.containsOnce(activityMenu, '.o_no_activity'); + assert.containsOnce(document.body, '.o_no_activity'); }); QUnit.test('activity menu widget: activity menu with 2 models', async function (assert) { assert.expect(10); - const { widget } = await start(); - var activityMenu = new ActivityMenu(widget); - await activityMenu.appendTo($('#qunit-fixture')); + legacySystrayItems.push(ActivityMenu); + registerCleanup(() => legacySystrayItems.pop()); + const { wowlEnv: env } = await start({ + hasWebClient: true, + }); + await testUtils.nextTick(); - assert.hasClass(activityMenu.$el, 'o_mail_systray_item', 'should be the instance of widget'); + assert.containsOnce(document.body, '.o_mail_systray_item', 'should contain an instance of widget'); // the assertion below has not been replace because there are includes of ActivityMenu that modify the length. - assert.ok(activityMenu.$('.o_mail_preview').length); - assert.containsOnce(activityMenu.$el, '.o_notification_counter', "widget should have notification counter"); - assert.strictEqual(parseInt(activityMenu.el.innerText), 5, "widget should have 5 notification counter"); + assert.ok(document.querySelectorAll('.o_mail_preview').length); + assert.containsOnce(document.body, '.o_notification_counter', "widget should have notification counter"); + assert.strictEqual(parseInt(document.querySelector('.o_notification_counter').innerText), 5, "widget should have 5 notification counter"); var context = {}; - testUtils.mock.intercept(activityMenu, 'do_action', function (event) { - assert.deepEqual(event.data.action.context, context, "wrong context value"); - }, true); + patchWithCleanup(env.services.action, { + doAction(action) { + assert.deepEqual(action.context, context, "wrong context value"); + }, + }); // case 1: click on "late" context = { force_search_count: 1, search_default_activities_overdue: 1, }; - await testUtils.dom.click(activityMenu.$('.dropdown-toggle')); - assert.hasClass(activityMenu.$el, 'show', 'ActivityMenu should be open'); - await testUtils.dom.click(activityMenu.$(".o_activity_filter_button[data-model_name='mail.test.activity'][data-filter='overdue']")); - assert.doesNotHaveClass(activityMenu.$el, 'show', 'ActivityMenu should be closed'); + await testUtils.dom.click(document.querySelector('.dropdown-toggle[title="Activities"]')); + assert.containsOnce(document.body, '.o_mail_systray_dropdown.show', 'ActivityMenu should be open'); + await testUtils.dom.click(document.querySelector(".o_activity_filter_button[data-model_name='mail.test.activity'][data-filter='overdue']")); + assert.containsNone(document.body, '.show', 'ActivityMenu should be closed'); // case 2: click on "today" context = { force_search_count: 1, search_default_activities_today: 1, }; - await testUtils.dom.click(activityMenu.$('.dropdown-toggle')); - await testUtils.dom.click(activityMenu.$(".o_activity_filter_button[data-model_name='mail.test.activity'][data-filter='today']")); + await testUtils.dom.click(document.querySelector('.dropdown-toggle[title="Activities"]')); + await testUtils.dom.click(document.querySelector(".o_activity_filter_button[data-model_name='mail.test.activity'][data-filter='today']")); // case 3: click on "future" context = { force_search_count: 1, search_default_activities_upcoming_all: 1, }; - await testUtils.dom.click(activityMenu.$('.dropdown-toggle')); - await testUtils.dom.click(activityMenu.$(".o_activity_filter_button[data-model_name='mail.test.activity'][data-filter='upcoming_all']")); + await testUtils.dom.click(document.querySelector('.dropdown-toggle[title="Activities"]')); + await testUtils.dom.click(document.querySelector(".o_activity_filter_button[data-model_name='mail.test.activity'][data-filter='upcoming_all']")); // case 4: click anywere else context = { force_search_count: 1, search_default_activities_overdue: 1, search_default_activities_today: 1, }; - await testUtils.dom.click(activityMenu.$('.dropdown-toggle')); - await testUtils.dom.click(activityMenu.$(".o_mail_systray_dropdown_items > div[data-model_name='mail.test.activity']")); + await testUtils.dom.click(document.querySelector('.dropdown-toggle[title="Activities"]')); + await testUtils.dom.click(document.querySelector(".o_mail_systray_dropdown_items > div[data-model_name='mail.test.activity']")); }); QUnit.test('activity menu widget: activity view icon', async function (assert) { assert.expect(14); - const { widget } = await start({ - session: this.session, + patchWithCleanup(session, { uid: 10 }); + legacySystrayItems.push(ActivityMenu); + registerCleanup(() => legacySystrayItems.pop()); + const { wowlEnv: env } = await start({ + hasWebClient: true, }); - var activityMenu = new ActivityMenu(widget); - await activityMenu.appendTo($('#qunit-fixture')); await testUtils.nextTick(); - assert.containsN(activityMenu, '.o_mail_activity_action', 2, + assert.containsN(document.body, '.o_mail_activity_action', 2, "widget should have 2 activity view icons"); - var $first = activityMenu.$('.o_mail_activity_action').eq(0); - var $second = activityMenu.$('.o_mail_activity_action').eq(1); - assert.strictEqual($first.data('model_name'), "res.partner", + var first = document.querySelector('.o_mail_activity_action'); + var second = document.querySelectorAll('.o_mail_activity_action')[1]; + assert.strictEqual(first.getAttribute('data-model_name'), "res.partner", "first activity action should link to 'res.partner'"); - assert.hasClass($first, 'fa-clock-o', "should display the activity action icon"); + assert.hasClass(first, 'fa-clock-o', "should display the activity action icon"); - assert.strictEqual($second.data('model_name'), "mail.test.activity", + assert.strictEqual(second.getAttribute('data-model_name'), "mail.test.activity", "Second activity action should link to 'mail.test.activity'"); - assert.hasClass($second, 'fa-clock-o', "should display the activity action icon"); + assert.hasClass(second, 'fa-clock-o', "should display the activity action icon"); - testUtils.mock.intercept(activityMenu, 'do_action', function (ev) { - if (ev.data.action.name) { - assert.ok(ev.data.action.domain, "should define a domain on the action"); - assert.deepEqual(ev.data.action.domain, [["activity_ids.user_id", "=", 10]], - "should set domain to user's activity only"); - assert.step('do_action:' + ev.data.action.name); - } else { - assert.step('do_action:' + ev.data.action); - } - }, true); + patchWithCleanup(env.services.action, { + doAction(action) { + if (action.name) { + assert.ok(action.domain, "should define a domain on the action"); + assert.deepEqual(action.domain, [["activity_ids.user_id", "=", 10]], + "should set domain to user's activity only"); + assert.step('do_action:' + action.name); + } else { + assert.step('do_action:' + action); + } + }, + }); // click on the "mail.test.activity" activity icon - await testUtils.dom.click(activityMenu.$('.dropdown-toggle')); - assert.hasClass(activityMenu.$('.dropdown-menu'), 'show', + await testUtils.dom.click(document.querySelector('.dropdown-toggle[title="Activities"]')); + assert.hasClass(document.querySelector('.dropdown-menu'), 'show', "dropdown should be expanded"); - await testUtils.dom.click(activityMenu.$(".o_mail_activity_action[data-model_name='mail.test.activity']")); - assert.doesNotHaveClass(activityMenu.$('.dropdown-menu'), 'show', + await testUtils.dom.click(document.querySelector(".o_mail_activity_action[data-model_name='mail.test.activity']")); + assert.doesNotHaveClass(document.querySelector('.dropdown-menu'), 'show', "dropdown should be collapsed"); // click on the "res.partner" activity icon - await testUtils.dom.click(activityMenu.$('.dropdown-toggle')); - await testUtils.dom.click(activityMenu.$(".o_mail_activity_action[data-model_name='res.partner']")); + await testUtils.dom.click(document.querySelector('.dropdown-toggle[title="Activities"]')); + await testUtils.dom.click(document.querySelector(".o_mail_activity_action[data-model_name='res.partner']")); assert.verifySteps([ 'do_action:mail.test.activity', @@ -155,22 +165,24 @@ QUnit.test('activity menu widget: activity view icon', async function (assert) { QUnit.test('activity menu widget: close on messaging menu click', async function (assert) { assert.expect(2); - const { click, createMessagingMenuComponent, widget } = await start(); + legacySystrayItems.push(ActivityMenu); + registerCleanup(() => legacySystrayItems.pop()); + const { click, createMessagingMenuComponent } = await start({ + hasWebClient: true, + }); await createMessagingMenuComponent(); - const activityMenu = new ActivityMenu(widget); - await activityMenu.appendTo($('#qunit-fixture')); await testUtils.nextTick(); - await testUtils.dom.click(activityMenu.$('.dropdown-toggle')); + await testUtils.dom.click(document.querySelector('.dropdown-toggle[title="Activities"]')); assert.hasClass( - activityMenu.el.querySelector('.o_mail_systray_dropdown'), + document.querySelector('.o_mail_systray_dropdown'), 'show', "activity menu should be shown after click on itself" ); await click(`.o_MessagingMenu_toggler`); assert.doesNotHaveClass( - activityMenu.el.querySelector('.o_mail_systray_dropdown'), + document.querySelector('.o_mail_systray_dropdown'), 'show', "activity menu should be hidden after click on messaging menu" );