diff --git a/addons/account/static/tests/account_move_form_tests.js b/addons/account/static/tests/account_move_form_tests.js index e40c7efac4a..d50601008ee 100644 --- a/addons/account/static/tests/account_move_form_tests.js +++ b/addons/account/static/tests/account_move_form_tests.js @@ -1,19 +1,20 @@ -/** @odoo-module **/ +/* @odoo-module */ -import { start, startServer } from "@mail/../tests/helpers/test_utils"; -import { triggerHotkey } from "@web/../tests/helpers/utils"; -import { accountMove as accountMoveService} from '@account/components/account_move_service/account_move_service'; +import { accountMove as accountMoveService } from "@account/components/account_move_service/account_move_service"; -QUnit.module("Views", {}, function (hooks) { - QUnit.module('MoveFormView'); +import { click, insertText, start, startServer } from "@mail/../tests/helpers/test_utils"; + +import { makeDeferred, triggerHotkey } from "@web/../tests/helpers/utils"; + +QUnit.module("Views", {}, function () { + QUnit.module("MoveFormView"); QUnit.test("When I switch tabs, it saves", async (assert) => { const pyEnv = await startServer(); - const accountMove = pyEnv['account.move'].create([{ name: "move0" }]); + const accountMove = pyEnv["account.move"].create([{ name: "move0" }]); const views = { - 'account.move,false,form': - `
+ "account.move,false,form": ` @@ -24,28 +25,28 @@ QUnit.module("Views", {}, function (hooks) {
`, }; - const { click, insertText, openView } = await start({ + const def = makeDeferred(); + const { openFormView } = await start({ serverData: { views }, services: { - 'account_move': accountMoveService, + account_move: accountMoveService, }, async mockRPC(route) { if (route === "/web/dataset/call_kw/account.move/write") { assert.step("tab saved"); + def.resolve(); } }, }); - await openView({ - res_id: accountMove, - res_model: 'account.move', - views: [[false, 'form']], - }); + openFormView("account.move", accountMove); await insertText("[name='name'] input", "somebody save me!"); - triggerHotkey("Enter") + triggerHotkey("Enter"); await click('a[name="aml_tab"]'); - assert.verifySteps(["tab saved"], - "When clicking on a tab, the saving method should be called and succeed"); + await def; + assert.verifySteps( + ["tab saved"], + "When clicking on a tab, the saving method should be called and succeed" + ); }); - }); diff --git a/addons/calendar/static/tests/activity_menu_tests.js b/addons/calendar/static/tests/activity_menu_tests.js index 854c384df37..8d734434818 100644 --- a/addons/calendar/static/tests/activity_menu_tests.js +++ b/addons/calendar/static/tests/activity_menu_tests.js @@ -1,6 +1,7 @@ -/** @odoo-module **/ +/* @odoo-module */ + +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; -import { start, startServer, click } from "@mail/../tests/helpers/test_utils"; import { getFixture, patchDate, patchWithCleanup } from "@web/../tests/helpers/utils"; let target; @@ -29,7 +30,7 @@ QUnit.test("activity menu widget:today meetings", async function (assert) { }, ]); const { env } = await start(); - assert.containsOnce(target, ".o_menu_systray i[aria-label='Activities']"); + await contains(".o_menu_systray i[aria-label='Activities']"); await click(".o_menu_systray i[aria-label='Activities']"); patchWithCleanup(env.services.action, { doAction(action) { @@ -37,10 +38,10 @@ QUnit.test("activity menu widget:today meetings", async function (assert) { assert.step("action"); }, }); - assert.containsOnce(target, ".o-mail-ActivityGroup:contains(Today's Meetings)"); - assert.containsN(target, ".o-mail-ActivityGroup .o-calendar-metting", 2); - assert.containsOnce(target, ".o-calendar-metting:contains(meeting1)"); - assert.containsOnce(target, ".o-calendar-metting:contains(meeting2)"); + await contains(".o-mail-ActivityGroup:contains(Today's Meetings)"); + await contains(".o-mail-ActivityGroup .o-calendar-metting", 2); + await contains(".o-calendar-metting:contains(meeting1)"); + await contains(".o-calendar-metting:contains(meeting2)"); assert.hasClass($(target).find("span:contains(meeting1)"), "fw-bold"); assert.doesNotHaveClass($(target).find("span:contains(meeting2)"), "fw-bold"); await click(".o-mail-ActivityMenu .o-mail-ActivityGroup"); diff --git a/addons/calendar/static/tests/activity_tests.js b/addons/calendar/static/tests/activity_tests.js index ed29eead240..ae13debe588 100644 --- a/addons/calendar/static/tests/activity_tests.js +++ b/addons/calendar/static/tests/activity_tests.js @@ -1,17 +1,8 @@ -/** @odoo-module **/ +/* @odoo-module */ -import { click, start, startServer } from "@mail/../tests/helpers/test_utils"; -import { getFixture } from "@web/../tests/helpers/utils"; +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; -let target; - -QUnit.module("activity", { - async beforeEach() { - target = getFixture(); - }, -}); - -QUnit.test("activity click on Reschedule", async function (assert) { +QUnit.test("activity click on Reschedule", async () => { const pyEnv = await startServer(); const resPartnerId = pyEnv["res.partner"].create({}); const meetingActivityTypeId = pyEnv["mail.activity.type"].create({ @@ -36,7 +27,7 @@ QUnit.test("activity click on Reschedule", async function (assert) { calendar_event_id: calendaMeetingId, }); const { openFormView } = await start(); - await openFormView("res.partner", resPartnerId); + openFormView("res.partner", resPartnerId); await click(".btn:contains('Reschedule')"); - assert.containsOnce(target, ".o_calendar_view"); + await contains(".o_calendar_view"); }); diff --git a/addons/calendar/static/tests/activity_widget_tests.js b/addons/calendar/static/tests/activity_widget_tests.js index ba51161ad8a..f79c74538ba 100644 --- a/addons/calendar/static/tests/activity_widget_tests.js +++ b/addons/calendar/static/tests/activity_widget_tests.js @@ -1,6 +1,6 @@ -/** @odoo-module **/ +/* @odoo-module */ -import { click, start, startServer } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; import { patchWithCleanup } from "@web/../tests/helpers/utils"; import { ListController } from "@web/views/list/list_controller"; @@ -65,6 +65,6 @@ QUnit.test("list activity widget: reschedule button in dropdown", async (assert) assert.strictEqual($(".o-mail-ListActivity-summary")[0].innerText, "OXP"); await click(".o-mail-ActivityButton"); // open the popover - assert.containsNone($, ".o-mail-ActivityListPopoverItem-editbtn .fa-pencil"); - assert.containsOnce($, ".o-mail-ActivityListPopoverItem-editbtn .fa-calendar"); + await contains(".o-mail-ActivityListPopoverItem-editbtn .fa-pencil", 0); + await contains(".o-mail-ActivityListPopoverItem-editbtn .fa-calendar"); }); diff --git a/addons/im_livechat/static/tests/channel_invite_tests.js b/addons/im_livechat/static/tests/channel_invite_tests.js index 0089557aa1e..cbe3f635fbb 100644 --- a/addons/im_livechat/static/tests/channel_invite_tests.js +++ b/addons/im_livechat/static/tests/channel_invite_tests.js @@ -3,11 +3,11 @@ import { startServer } from "@bus/../tests/helpers/mock_python_environment"; import { Command } from "@mail/../tests/helpers/command"; -import { click, start } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start } from "@mail/../tests/helpers/test_utils"; QUnit.module("Channel invite"); -QUnit.test("Can invite a partner to a livechat channel", async (assert) => { +QUnit.test("Can invite a partner to a livechat channel", async () => { const pyEnv = await startServer(); const userId = pyEnv["res.users"].create({ name: "James" }); pyEnv["res.partner"].create({ @@ -25,12 +25,13 @@ QUnit.test("Can invite a partner to a livechat channel", async (assert) => { livechat_operator_id: pyEnv.currentPartnerId, }); const { openDiscuss } = await start(); - await openDiscuss(channelId); + openDiscuss(channelId); await click("button[title='Add Users']"); await click(".o-discuss-ChannelInvitation-selectable:contains(James) input"); - await click("button:contains(Invite)"); + await click("button:contains(Invite):not(:disabled)"); + await contains(".o-discuss-ChannelInvitation", 0); await click("button[title='Show Member List']"); - assert.containsOnce($, ".o-discuss-ChannelMember:contains(James)"); + await contains(".o-discuss-ChannelMember:contains(James)"); }); QUnit.test("Available operators come first", async (assert) => { @@ -60,7 +61,7 @@ QUnit.test("Available operators come first", async (assert) => { const { openDiscuss } = await start(); await openDiscuss(channelId); await click("button[title='Add Users']"); - const partnerSuggestions = document.querySelectorAll(".o-discuss-ChannelInvitation-selectable"); + const partnerSuggestions = await contains(".o-discuss-ChannelInvitation-selectable", 2); assert.ok(partnerSuggestions[0].textContent.includes("Ron")); assert.ok(partnerSuggestions[1].textContent.includes("Harry")); }); @@ -101,10 +102,10 @@ QUnit.test("Partners invited most frequently by the current user come first", as await click(".o-mail-DiscussSidebarChannel:contains(Visitor #1)"); await click("button[title='Add Users']"); await click(".o-discuss-ChannelInvitation-selectable:contains(John) input"); - await click("button:contains(Invite)"); + await click("button:contains(Invite):not(:disabled)"); await click(".o-mail-DiscussSidebarChannel:contains(Visitor #2)"); await click("button[title='Add Users']"); - const partnerSuggestions = document.querySelectorAll(".o-discuss-ChannelInvitation-selectable"); + const partnerSuggestions = await contains(".o-discuss-ChannelInvitation-selectable", 2); assert.ok(partnerSuggestions[0].textContent.includes("John")); assert.ok(partnerSuggestions[1].textContent.includes("Albert")); }); diff --git a/addons/im_livechat/static/tests/chat_window_patch_tests.js b/addons/im_livechat/static/tests/chat_window_patch_tests.js index 8002cc2767d..8145ba31a25 100644 --- a/addons/im_livechat/static/tests/chat_window_patch_tests.js +++ b/addons/im_livechat/static/tests/chat_window_patch_tests.js @@ -1,6 +1,6 @@ /* @odoo-module */ -import { click, start, startServer } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; QUnit.module("chat window (patch)"); @@ -18,9 +18,9 @@ QUnit.test("No call buttons", async (assert) => { await start(); await click(".o_menu_systray i[aria-label='Messages']"); await click(".o-mail-NotificationItem"); - assert.containsOnce($, ".o-mail-ChatWindow"); - assert.containsNone($, ".o-mail-ChatWindow-header .o-mail-ChatWindow-command i.fa-phone"); - assert.containsNone($, ".o-mail-ChatWindow-header .o-mail-ChatWindow-command i.fa-gear"); + await contains(".o-mail-ChatWindow"); + await contains(".o-mail-ChatWindow-header .o-mail-ChatWindow-command i.fa-phone", 0); + await contains(".o-mail-ChatWindow-header .o-mail-ChatWindow-command i.fa-gear", 0); }); QUnit.test("closing a chat window with no message from admin side unpins it", async (assert) => { diff --git a/addons/im_livechat/static/tests/composer_patch_tests.js b/addons/im_livechat/static/tests/composer_patch_tests.js index 1eec45f4a55..b73a6c2a0af 100644 --- a/addons/im_livechat/static/tests/composer_patch_tests.js +++ b/addons/im_livechat/static/tests/composer_patch_tests.js @@ -5,12 +5,13 @@ import { startServer } from "@bus/../tests/helpers/mock_python_environment"; import { afterNextRender, click, + contains, dragenterFiles, insertText, start, } from "@mail/../tests/helpers/test_utils"; -import { editInput, nextTick, triggerHotkey } from "@web/../tests/helpers/utils"; +import { nextTick, triggerHotkey } from "@web/../tests/helpers/utils"; QUnit.module("composer (patch)"); @@ -22,8 +23,8 @@ QUnit.test("No add attachments button", async (assert) => { }); const { openDiscuss } = await start(); await openDiscuss(channelId); - assert.containsOnce($, ".o-mail-Composer"); - assert.containsNone($, "button[title='Attach files']"); + await contains(".o-mail-Composer"); + await contains("button[title='Attach files']", 0); }); QUnit.test("Attachment upload via drag and drop disabled", async (assert) => { @@ -36,10 +37,10 @@ QUnit.test("Attachment upload via drag and drop disabled", async (assert) => { }); const { openDiscuss } = await start(); await openDiscuss(channelId); - assert.containsOnce($, ".o-mail-Composer"); + await contains(".o-mail-Composer"); dragenterFiles($(".o-mail-Composer-input")[0]); await nextTick(); - assert.containsNone($, ".o-mail-Dropzone"); + await contains(".o-mail-Dropzone", 0); }); QUnit.test("Can execute help command on livechat channels", async (assert) => { @@ -64,9 +65,8 @@ QUnit.test("Can execute help command on livechat channels", async (assert) => { }); await click(".o_menu_systray i[aria-label='Messages']"); await click(".o-mail-NotificationItem"); - await editInput(document.body, ".o-mail-Composer-input", "/help"); + await insertText(".o-mail-Composer-input", "/help"); triggerHotkey("Enter"); - await nextTick(); assert.verifySteps(["execute_command_help"]); }); @@ -94,10 +94,10 @@ QUnit.test('Receives visitor typing status "is typing"', async (assert) => { }) ) ); - assert.containsOnce($, ".o-discuss-Typing:contains(Visitor 20 is typing...)"); + await contains(".o-discuss-Typing:contains(Visitor 20 is typing...)"); }); -QUnit.test('display canned response suggestions on typing ":"', async (assert) => { +QUnit.test('display canned response suggestions on typing ":"', async () => { const pyEnv = await startServer(); const channelId = pyEnv["discuss.channel"].create({ anonymous_name: "Mario", @@ -114,9 +114,10 @@ QUnit.test('display canned response suggestions on typing ":"', async (assert) = }); const { openDiscuss } = await start(); await openDiscuss(channelId); - assert.containsNone($, ".o-mail-Composer-suggestionList .o-open"); + await contains(".o-mail-Composer-input"); + await contains(".o-mail-Composer-suggestionList .o-open", 0); await insertText(".o-mail-Composer-input", ":"); - assert.containsOnce($, ".o-mail-Composer-suggestionList .o-open"); + await contains(".o-mail-Composer-suggestionList .o-open"); }); QUnit.test("use a canned response", async (assert) => { @@ -136,11 +137,12 @@ QUnit.test("use a canned response", async (assert) => { }); const { openDiscuss } = await start(); await openDiscuss(channelId); - assert.containsNone($, ".o-mail-Composer-suggestionList .o-open"); + await contains(".o-mail-Composer-suggestionList"); + await contains(".o-mail-Composer-suggestionList .o-open", 0); assert.strictEqual($(".o-mail-Composer-input").val(), ""); await insertText(".o-mail-Composer-input", ":"); - assert.containsOnce($, ".o-mail-Composer-suggestion"); await click(".o-mail-Composer-suggestion"); + await contains(".o-mail-Composer-suggestion", 0); assert.strictEqual( $(".o-mail-Composer-input").val().replace(/\s/, " "), "Hello! How are you? ", @@ -165,13 +167,14 @@ QUnit.test("use a canned response some text", async (assert) => { }); const { openDiscuss } = await start(); await openDiscuss(channelId); - assert.containsNone($, ".o-mail-Composer-suggestion"); + await contains(".o-mail-Composer-suggestionList"); + await contains(".o-mail-Composer-suggestion", 0); assert.strictEqual($(".o-mail-Composer-input").val(), ""); await insertText(".o-mail-Composer-input", "bluhbluh "); assert.strictEqual($(".o-mail-Composer-input").val(), "bluhbluh "); await insertText(".o-mail-Composer-input", ":"); - assert.containsOnce($, ".o-mail-Composer-suggestion"); await click(".o-mail-Composer-suggestion"); + await contains(".o-mail-Composer-suggestion", 0); assert.strictEqual( $(".o-mail-Composer-input").val().replace(/\s/, " "), "bluhbluh Hello! How are you? ", @@ -196,11 +199,12 @@ QUnit.test("add an emoji after a canned response", async (assert) => { }); const { openDiscuss } = await start(); await openDiscuss(channelId); - assert.containsNone($, ".o-mail-Composer-suggestion"); + await contains(".o-mail-Composer-suggestionList"); + await contains(".o-mail-Composer-suggestion", 0); assert.strictEqual($(".o-mail-Composer-input").val(), ""); await insertText(".o-mail-Composer-input", ":"); - assert.containsOnce($, ".o-mail-Composer-suggestion"); await click(".o-mail-Composer-suggestion"); + await contains(".o-mail-Composer-suggestion", 0); assert.strictEqual( $(".o-mail-Composer-input").val().replace(/\s/, " "), "Hello! How are you? ", @@ -208,6 +212,7 @@ QUnit.test("add an emoji after a canned response", async (assert) => { ); await click("button[aria-label='Emojis']"); await click(".o-Emoji:contains(😊)"); + await contains(".o-Emoji", 0); assert.strictEqual( $(".o-mail-Composer-input").val().replace(/\s/, " "), "Hello! How are you? 😊" diff --git a/addons/im_livechat/static/tests/discuss_patch_tests.js b/addons/im_livechat/static/tests/discuss_patch_tests.js index e405a54ce27..cccaaafc381 100644 --- a/addons/im_livechat/static/tests/discuss_patch_tests.js +++ b/addons/im_livechat/static/tests/discuss_patch_tests.js @@ -4,6 +4,7 @@ import { Command } from "@mail/../tests/helpers/command"; import { afterNextRender, click, + contains, insertText, start, startServer, @@ -128,7 +129,7 @@ QUnit.test("reaction button should not be present on livechat", async (assert) = const { insertText, openDiscuss } = await start(); await openDiscuss(channelId); await insertText(".o-mail-Composer-input", "Test"); - await click(".o-mail-Composer-send"); + await click(".o-mail-Composer-send:not(:disabled)"); await click(".o-mail-Message"); assert.containsNone($, "[title='Add a Reaction']"); }); @@ -189,14 +190,14 @@ QUnit.test( ]); const { openDiscuss } = await start(); await openDiscuss(); - assert.strictEqual($(".o-mail-DiscussSidebarChannel:eq(0)").text(), "Visitor 12"); - assert.strictEqual($(".o-mail-DiscussSidebarChannel:eq(1)").text(), "Visitor 11"); + await contains(".o-mail-DiscussSidebarChannel:eq(0):contains(Visitor 12)"); + await contains(".o-mail-DiscussSidebarChannel:eq(1):contains(Visitor 11)"); // post a new message on the last channel await click(".o-mail-DiscussSidebarChannel:eq(1)"); await insertText(".o-mail-Composer-input", "Blabla"); - await click(".o-mail-Composer-send"); - assert.containsN($, ".o-mail-DiscussSidebarChannel", 2); - assert.strictEqual($(".o-mail-DiscussSidebarChannel:eq(0)").text(), "Visitor 11"); - assert.strictEqual($(".o-mail-DiscussSidebarChannel:eq(1)").text(), "Visitor 12"); + await click(".o-mail-Composer-send:not(:disabled)"); + await contains(".o-mail-DiscussSidebarChannel", 2); + await contains(".o-mail-DiscussSidebarChannel:eq(0):contains(Visitor 11)"); + await contains(".o-mail-DiscussSidebarChannel:eq(1):contains(Visitor 12)"); } ); diff --git a/addons/im_livechat/static/tests/embed/autopopup_tests.js b/addons/im_livechat/static/tests/embed/autopopup_tests.js index ef58519f511..2e1ce014b66 100644 --- a/addons/im_livechat/static/tests/embed/autopopup_tests.js +++ b/addons/im_livechat/static/tests/embed/autopopup_tests.js @@ -7,11 +7,9 @@ import { start, setCookie, loadDefaultConfig } from "@im_livechat/../tests/embed import { Command } from "@mail/../tests/helpers/command"; import { contains } from "@mail/../tests/helpers/test_utils"; -import { nextTick } from "@web/../tests/helpers/utils"; - QUnit.module("autopopup"); -QUnit.test("persisted session", async (assert) => { +QUnit.test("persisted session", async () => { const pyEnv = await startServer(); const livechatChannelId = await loadDefaultConfig(); const channelId = pyEnv["discuss.channel"].create({ @@ -29,10 +27,10 @@ QUnit.test("persisted session", async (assert) => { await contains(".o-mail-ChatWindow"); }); -QUnit.test("rule received in init", async (assert) => { +QUnit.test("rule received in init", async () => { await startServer(); await loadDefaultConfig(); - await start({ + start({ mockRPC(route) { if (route === "/im_livechat/init") { return { @@ -42,6 +40,5 @@ QUnit.test("rule received in init", async (assert) => { } }, }); - await nextTick(); - assert.containsOnce($, ".o-mail-ChatWindow"); + await contains(".o-mail-ChatWindow"); }); diff --git a/addons/im_livechat/static/tests/embed/feedback_panel_tests.js b/addons/im_livechat/static/tests/embed/feedback_panel_tests.js index 39a117c8402..b372b97216b 100644 --- a/addons/im_livechat/static/tests/embed/feedback_panel_tests.js +++ b/addons/im_livechat/static/tests/embed/feedback_panel_tests.js @@ -5,26 +5,26 @@ import { startServer } from "@bus/../tests/helpers/mock_python_environment"; import { RATING } from "@im_livechat/embed/core/livechat_service"; import { loadDefaultConfig, start } from "@im_livechat/../tests/embed/helper/test_utils"; -import { afterNextRender, click, insertText } from "@mail/../tests/helpers/test_utils"; +import { click, contains, insertText } from "@mail/../tests/helpers/test_utils"; import { triggerHotkey } from "@web/../tests/helpers/utils"; QUnit.module("feedback panel"); -QUnit.test("Do not ask feedback if empty", async (assert) => { +QUnit.test("Do not ask feedback if empty", async () => { await startServer(); await loadDefaultConfig(); - await start(); + start(); await click(".o-livechat-LivechatButton"); - assert.containsOnce($, ".o-mail-ChatWindow"); + await contains(".o-mail-ChatWindow"); await click("[title='Close Chat Window']"); - assert.containsNone($, ".o-livechat-LivechatButton"); + await contains(".o-livechat-LivechatButton", 0); }); QUnit.test("Close without feedback", async (assert) => { await startServer(); await loadDefaultConfig(); - await start({ + start({ mockRPC(route) { if (route === "/im_livechat/visitor_leave_session") { assert.step(route); @@ -35,19 +35,20 @@ QUnit.test("Close without feedback", async (assert) => { }, }); await click(".o-livechat-LivechatButton"); - assert.containsOnce($, ".o-mail-ChatWindow"); + await contains(".o-mail-ChatWindow"); await insertText(".o-mail-Composer-input", "Hello World!"); - await afterNextRender(() => triggerHotkey("Enter")); + triggerHotkey("Enter"); + await contains(".o-mail-Message:contains(Hello World!)"); await click("[title='Close Chat Window']"); await click("button:contains('Close')"); - assert.containsNone($, ".o-livechat-LivechatButton"); + await contains(".o-livechat-LivechatButton", 0); assert.verifySteps(["/im_livechat/visitor_leave_session"]); }); QUnit.test("Feedback with rating and comment", async (assert) => { await startServer(); await loadDefaultConfig(); - await start({ + start({ mockRPC(route, args) { if (route === "/im_livechat/visitor_leave_session") { assert.step(route); @@ -60,28 +61,30 @@ QUnit.test("Feedback with rating and comment", async (assert) => { }, }); await click(".o-livechat-LivechatButton"); - assert.containsOnce($, ".o-mail-ChatWindow"); + await contains(".o-mail-ChatWindow"); await insertText(".o-mail-Composer-input", "Hello World!"); - await afterNextRender(() => triggerHotkey("Enter")); + triggerHotkey("Enter"); + await contains(".o-mail-Message:contains(Hello World!)"); await click("[title='Close Chat Window']"); assert.verifySteps(["/im_livechat/visitor_leave_session"]); await click(`img[data-alt="${RATING.GOOD}"]`); await insertText("textarea[placeholder='Explain your note']", "Good job!"); - await click("button:contains(Send)"); - assert.containsOnce($, "p:contains(Thank you for your feedback)"); + await click("button:contains(Send):not(:disabled)"); + await contains("p:contains(Thank you for your feedback)"); assert.verifySteps(["/im_livechat/feedback"]); }); -QUnit.test("Closing folded chat window should open it with feedback", async (assert) => { +QUnit.test("Closing folded chat window should open it with feedback", async () => { await startServer(); await loadDefaultConfig(); await start(); await click(".o-livechat-LivechatButton"); await insertText(".o-mail-Composer-input", "Hello World!"); - await afterNextRender(() => triggerHotkey("Enter")); + triggerHotkey("Enter"); + await contains(".o-mail-Message:contains(Hello World!)"); await click("[title='Fold']"); - assert.containsOnce($, ".o-mail-ChatWindow.o-folded"); + await contains(".o-mail-ChatWindow.o-folded"); await click("[title='Close Chat Window']"); - assert.containsNone($, ".o-mail-ChatWindow.o-folded"); - assert.containsOnce($, ".o-mail-ChatWindow:contains(Did we correctly answer your question?)"); + await contains(".o-mail-ChatWindow.o-folded", 0); + await contains(".o-mail-ChatWindow:contains(Did we correctly answer your question?)"); }); diff --git a/addons/im_livechat/static/tests/embed/livechat_button_tests.js b/addons/im_livechat/static/tests/embed/livechat_button_tests.js index b4eee0de872..f1edae97507 100644 --- a/addons/im_livechat/static/tests/embed/livechat_button_tests.js +++ b/addons/im_livechat/static/tests/embed/livechat_button_tests.js @@ -4,46 +4,47 @@ import { startServer } from "@bus/../tests/helpers/mock_python_environment"; import { loadDefaultConfig, start } from "@im_livechat/../tests/embed/helper/test_utils"; -import { afterNextRender, click, insertText } from "@mail/../tests/helpers/test_utils"; +import { click, contains, insertText } from "@mail/../tests/helpers/test_utils"; import { triggerHotkey } from "@web/../tests/helpers/utils"; -QUnit.test("open/close temporary channel", async (assert) => { +QUnit.test("open/close temporary channel", async () => { await startServer(); await loadDefaultConfig(); - await start(); - assert.containsOnce($, ".o-livechat-LivechatButton"); + start(); await click(".o-livechat-LivechatButton"); - assert.containsOnce($, ".o-mail-ChatWindow"); - assert.containsNone($, ".o-livechat-LivechatButton"); + await contains(".o-mail-ChatWindow"); + await contains(".o-livechat-LivechatButton", 0); await click("[title='Close Chat Window']"); - assert.containsNone($, ".o-mail-ChatWindow"); - assert.containsNone($, ".o-livechat-LivechatButton"); + await contains(".o-mail-ChatWindow", 0); + await contains(".o-livechat-LivechatButton", 0); }); -QUnit.test("open/close persisted channel", async (assert) => { +QUnit.test("open/close persisted channel", async () => { await startServer(); await loadDefaultConfig(); - await start(); - assert.containsOnce($, ".o-livechat-LivechatButton"); + start(); await click(".o-livechat-LivechatButton"); - await insertText(".o-mail-Composer-input", "Hello"); - await afterNextRender(() => triggerHotkey("Enter")); + await insertText(".o-mail-Composer-input", "How can I help?"); + triggerHotkey("Enter"); + await contains(".o-mail-Message:contains(How can I help?)"); await click("[title='Close Chat Window']"); + await contains(".o-mail-ChatWindow-content:contains(Did we correctly answer your question?)"); await click("[title='Close Chat Window']"); - assert.containsNone($, ".o-mail-ChatWindow"); - assert.containsNone($, ".o-livechat-LivechatButton"); + await contains(".o-mail-ChatWindow", 0); + await contains(".o-livechat-LivechatButton", 0); }); -QUnit.test("livechat not available", async (assert) => { +QUnit.test("livechat not available", async () => { await startServer(); await loadDefaultConfig(); - await start({ + start({ mockRPC(route) { if (route === "/im_livechat/init") { return { available_for_me: false }; } }, }); - assert.containsNone($, ".o-livechat-LivechatButton"); + await contains(".o-mail-ChatWindowContainer"); + await contains(".o-livechat-LivechatButton", 0); }); diff --git a/addons/im_livechat/static/tests/embed/livechat_service_tests.js b/addons/im_livechat/static/tests/embed/livechat_service_tests.js index 6e002f38713..9e902494fa7 100644 --- a/addons/im_livechat/static/tests/embed/livechat_service_tests.js +++ b/addons/im_livechat/static/tests/embed/livechat_service_tests.js @@ -5,11 +5,11 @@ import { startServer } from "@bus/../tests/helpers/mock_python_environment"; import { loadDefaultConfig, setCookie, start } from "@im_livechat/../tests/embed/helper/test_utils"; import { Command } from "@mail/../tests/helpers/command"; -import { click } from "@mail/../tests/helpers/test_utils"; +import { click, contains } from "@mail/../tests/helpers/test_utils"; QUnit.module("livechat service"); -QUnit.test("persisted session history", async (assert) => { +QUnit.test("persisted session history", async () => { const pyEnv = await startServer(); const livechatChannelId = await loadDefaultConfig(); const channelId = pyEnv["discuss.channel"].create({ @@ -30,19 +30,18 @@ QUnit.test("persisted session history", async (assert) => { model: "discuss.channel", message_type: "comment", }); - - await start(); - assert.containsOnce($, ".o-mail-Message:contains(Old message in history)"); + start(); + await contains(".o-mail-Message:contains(Old message in history)"); }); -QUnit.test("previous operator prioritized", async (assert) => { +QUnit.test("previous operator prioritized", async () => { const pyEnv = await startServer(); const livechatChannelId = await loadDefaultConfig(); const userId = pyEnv["res.users"].create({ name: "John Doe", im_status: "online" }); const previousOperatorId = pyEnv["res.partner"].create({ user_ids: [userId] }); pyEnv["im_livechat.channel"].write([livechatChannelId], { user_ids: [Command.link(userId)] }); setCookie("im_livechat_previous_operator_pid", JSON.stringify(previousOperatorId)); - await start(); - await click(".o-livechat-LivechatButton"); - assert.containsOnce($, ".o-mail-Message-author:contains(John Doe)"); + start(); + click(".o-livechat-LivechatButton"); + await contains(".o-mail-Message-author:contains(John Doe)"); }); diff --git a/addons/im_livechat/static/tests/embed/livechat_session_tests.js b/addons/im_livechat/static/tests/embed/livechat_session_tests.js index da4c83dab3c..3a52c24712f 100644 --- a/addons/im_livechat/static/tests/embed/livechat_session_tests.js +++ b/addons/im_livechat/static/tests/embed/livechat_session_tests.js @@ -6,13 +6,13 @@ import { loadDefaultConfig, setCookie, start } from "@im_livechat/../tests/embed import { LivechatButton } from "@im_livechat/embed/core_ui/livechat_button"; import { Command } from "@mail/../tests/helpers/command"; -import { afterNextRender, click, insertText } from "@mail/../tests/helpers/test_utils"; +import { click, contains, insertText } from "@mail/../tests/helpers/test_utils"; import { mockTimeout, triggerHotkey } from "@web/../tests/helpers/utils"; QUnit.module("livechat session"); -QUnit.test("Unsuccessful message post shows session expired", async (assert) => { +QUnit.test("Unsuccessful message post shows session expired", async () => { const pyEnv = await startServer(); const livechatChannelId = await loadDefaultConfig(); const channelId = pyEnv["discuss.channel"].create({ @@ -26,7 +26,7 @@ QUnit.test("Unsuccessful message post shows session expired", async (assert) => }); const [channelInfo] = pyEnv.mockServer._mockDiscussChannelChannelInfo([channelId]); setCookie("im_livechat_session", JSON.stringify(channelInfo)); - await start({ + start({ mockRPC(route) { if (route === "/im_livechat/chat_post") { return false; @@ -34,16 +34,16 @@ QUnit.test("Unsuccessful message post shows session expired", async (assert) => }, }); await insertText(".o-mail-Composer-input", "Hello World!"); - await afterNextRender(() => triggerHotkey("Enter")); - assert.containsOnce($, ".o_notification:contains(Session expired)"); - assert.containsNone($, ".o-mail-ChatWindow"); + triggerHotkey("Enter"); + await contains(".o_notification:contains(Session expired)"); + await contains(".o-mail-ChatWindow", 0); }); QUnit.test("Session is reset after failing to persist the channel", async (assert) => { await startServer(); await loadDefaultConfig(); const { advanceTime } = mockTimeout(); - await start({ + start({ mockRPC(route, args) { if (route === "/im_livechat/get_session" && args.persisted) { return false; @@ -52,15 +52,12 @@ QUnit.test("Session is reset after failing to persist the channel", async (asser }); await click(".o-livechat-LivechatButton"); await insertText(".o-mail-Composer-input", "Hello World!"); - await afterNextRender(() => triggerHotkey("Enter")); - assert.containsOnce( - $, - ".o_notification:contains(No available collaborator, please try again later.)" - ); - assert.containsOnce($, ".o-livechat-LivechatButton"); + triggerHotkey("Enter"); + await contains(".o_notification:contains(No available collaborator, please try again later.)"); + await contains(".o-livechat-LivechatButton"); await advanceTime(LivechatButton.DEBOUNCE_DELAY + 10); await click(".o-livechat-LivechatButton"); - assert.containsOnce($, ".o-mail-ChatWindow"); + await contains(".o-mail-ChatWindow"); }); QUnit.test("Thread state is saved on the session", async (assert) => { @@ -68,10 +65,13 @@ QUnit.test("Thread state is saved on the session", async (assert) => { await loadDefaultConfig(); const env = await start(); await click(".o-livechat-LivechatButton"); + await contains(".o-mail-ChatWindow-content"); assert.strictEqual(env.services["im_livechat.livechat"].sessionCookie.state, "open"); await click(".o-mail-ChatWindow-header"); + await contains(".o-mail-ChatWindow-content", 0); assert.strictEqual(env.services["im_livechat.livechat"].sessionCookie.state, "folded"); await click(".o-mail-ChatWindow-header"); + await contains(".o-mail-ChatWindow-content"); assert.strictEqual(env.services["im_livechat.livechat"].sessionCookie.state, "open"); }); @@ -82,7 +82,8 @@ QUnit.test("Seen message is saved on the session", async (assert) => { await click(".o-livechat-LivechatButton"); assert.notOk(env.services["im_livechat.livechat"].sessionCookie.seen_message_id); await insertText(".o-mail-Composer-input", "Hello World!"); - await afterNextRender(() => triggerHotkey("Enter")); + triggerHotkey("Enter"); + await contains(".o-mail-Message", 2); assert.strictEqual( env.services["im_livechat.livechat"].sessionCookie.seen_message_id, env.services["im_livechat.livechat"].thread.newestMessage.id diff --git a/addons/im_livechat/static/tests/embed/transcript_sender_tests.js b/addons/im_livechat/static/tests/embed/transcript_sender_tests.js index d0fcd926c0b..54123e27596 100644 --- a/addons/im_livechat/static/tests/embed/transcript_sender_tests.js +++ b/addons/im_livechat/static/tests/embed/transcript_sender_tests.js @@ -4,7 +4,7 @@ import { startServer } from "@bus/../tests/helpers/mock_python_environment"; import { loadDefaultConfig, start } from "@im_livechat/../tests/embed/helper/test_utils"; -import { afterNextRender, click, insertText } from "@mail/../tests/helpers/test_utils"; +import { click, contains, insertText } from "@mail/../tests/helpers/test_utils"; import { triggerHotkey } from "@web/../tests/helpers/utils"; @@ -13,7 +13,7 @@ QUnit.module("transcript sender"); QUnit.test("send", async (assert) => { await startServer(); await loadDefaultConfig(); - await start({ + start({ mockRPC(route, args) { if (route === "/im_livechat/email_livechat_transcript") { assert.step(`send_transcript - ${args.email}`); @@ -22,20 +22,21 @@ QUnit.test("send", async (assert) => { }); await click(".o-livechat-LivechatButton"); await insertText(".o-mail-Composer-input", "Hello World!"); - await afterNextRender(() => triggerHotkey("Enter")); + triggerHotkey("Enter"); + await contains(".o-mail-Message:contains(Hello World!)"); await click(".o-mail-ChatWindow-command[title*='Close']"); - assert.containsOnce($, ".form-text:contains(Receive a copy of this conversation)"); - assert.containsOnce($, "button[data-action='sendTranscript']:disabled"); + await contains(".form-text:contains(Receive a copy of this conversation)"); + await contains("button[data-action='sendTranscript']:disabled"); await insertText("input[placeholder='mail@example.com']", "odoobot@odoo.com"); - await click("button[data-action='sendTranscript']"); + await click("button[data-action='sendTranscript']:not(:disabled)"); + await contains(".form-text:contains(The conversation was sent)"); assert.verifySteps(["send_transcript - odoobot@odoo.com"]); - assert.containsOnce($, ".form-text:contains(The conversation was sent)"); }); -QUnit.test("send failed", async (assert) => { +QUnit.test("send failed", async () => { await startServer(); await loadDefaultConfig(); - await start({ + start({ mockRPC(route) { if (route === "/im_livechat/email_livechat_transcript") { throw new Error(); @@ -44,9 +45,10 @@ QUnit.test("send failed", async (assert) => { }); await click(".o-livechat-LivechatButton"); await insertText(".o-mail-Composer-input", "Hello World!"); - await afterNextRender(() => triggerHotkey("Enter")); + triggerHotkey("Enter"); + await contains(".o-mail-Message:contains(Hello World!)"); await click(".o-mail-ChatWindow-command[title*='Close']"); await insertText("input[placeholder='mail@example.com']", "odoobot@odoo.com"); - await click("button[data-action='sendTranscript']"); - assert.containsOnce($, ".form-text:contains(An error occurred. Please try again.)"); + await click("button[data-action='sendTranscript']:not(:disabled)"); + await contains(".form-text:contains(An error occurred. Please try again.)"); }); diff --git a/addons/im_livechat/static/tests/messaging_menu_patch_tests.js b/addons/im_livechat/static/tests/messaging_menu_patch_tests.js index d40c8796887..19576e44e6b 100644 --- a/addons/im_livechat/static/tests/messaging_menu_patch_tests.js +++ b/addons/im_livechat/static/tests/messaging_menu_patch_tests.js @@ -1,11 +1,11 @@ /* @odoo-module */ -import { click, start, startServer } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; import { patchUiSize } from "@mail/../tests/helpers/patch_ui_size"; QUnit.module("messaging menu (patch)"); -QUnit.test('livechats should be in "chat" filter', async (assert) => { +QUnit.test('livechats should be in "chat" filter', async () => { const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -18,15 +18,14 @@ QUnit.test('livechats should be in "chat" filter', async (assert) => { }); await start(); await click(".o_menu_systray i[aria-label='Messages']"); - assert.containsOnce($, ".o-mail-MessagingMenu button:contains(All)"); - assert.hasClass($(".o-mail-MessagingMenu button:contains(All)"), "fw-bolder"); - assert.containsOnce($, ".o-mail-NotificationItem:contains(Visitor 11)"); + await contains(".o-mail-MessagingMenu button:contains(All).fw-bolder"); + await contains(".o-mail-NotificationItem:contains(Visitor 11)"); await click(".o-mail-MessagingMenu button:contains(Chat)"); - assert.hasClass($(".o-mail-MessagingMenu button:contains(Chat)"), "fw-bolder"); - assert.containsOnce($, ".o-mail-NotificationItem:contains(Visitor 11)"); + await contains(".o-mail-MessagingMenu button:contains(Chat).fw-bolder"); + await contains(".o-mail-NotificationItem:contains(Visitor 11)"); }); -QUnit.test('livechats should be in "livechat" tab in mobile', async (assert) => { +QUnit.test('livechats should be in "livechat" tab in mobile', async () => { patchUiSize({ height: 360, width: 640 }); const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ @@ -41,7 +40,7 @@ QUnit.test('livechats should be in "livechat" tab in mobile', async (assert) => await start(); await click(".o_menu_systray i[aria-label='Messages']"); await click("button:contains(Livechat)"); - assert.containsOnce($, ".o-mail-NotificationItem:contains(Visitor 11)"); + await contains(".o-mail-NotificationItem:contains(Visitor 11)"); await click("button:contains(Chat)"); - assert.containsNone($, ".o-mail-NotificationItem:contains(Visitor 11)"); + await contains(".o-mail-NotificationItem:contains(Visitor 11)", 0); }); diff --git a/addons/im_livechat/static/tests/mobile_messaging_menu_patch_tests.js b/addons/im_livechat/static/tests/mobile_messaging_menu_patch_tests.js index 0105c3460bf..ee65f396d90 100644 --- a/addons/im_livechat/static/tests/mobile_messaging_menu_patch_tests.js +++ b/addons/im_livechat/static/tests/mobile_messaging_menu_patch_tests.js @@ -1,7 +1,7 @@ /* @odoo-module */ import { patchUiSize, SIZES } from "@mail/../tests/helpers/patch_ui_size"; -import { click, start, startServer } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; QUnit.module("mobile messaging menu (patch)", { beforeEach() { @@ -9,29 +9,26 @@ QUnit.module("mobile messaging menu (patch)", { }, }); -QUnit.test("Livechat button is not present when there is no livechat thread", async (assert) => { +QUnit.test("Livechat button is not present when there is no livechat thread", async () => { await start(); await click(".o_menu_systray i[aria-label='Messages']"); - assert.containsOnce($, ".o-mail-MessagingMenu"); - assert.containsNone($, ".o-mail-MessagingMenu-navbar:contains(Livechat)"); + await contains(".o-mail-MessagingMenu"); + await contains(".o-mail-MessagingMenu-navbar:contains(Livechat)", 0); }); -QUnit.test( - "Livechat button is present when there is at least one livechat thread", - async (assert) => { - const pyEnv = await startServer(); - pyEnv["discuss.channel"].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: "livechat", - livechat_operator_id: pyEnv.currentPartnerId, - }); - await start(); - await click(".o_menu_systray i[aria-label='Messages']"); - assert.containsOnce($, ".o-mail-MessagingMenu"); - assert.containsOnce($, ".o-mail-MessagingMenu-navbar:contains(Livechat)"); - } -); +QUnit.test("Livechat button is present when there is at least one livechat thread", async () => { + const pyEnv = await startServer(); + pyEnv["discuss.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + await start(); + await click(".o_menu_systray i[aria-label='Messages']"); + await contains(".o-mail-MessagingMenu"); + await contains(".o-mail-MessagingMenu-navbar:contains(Livechat)"); +}); diff --git a/addons/im_livechat/static/tests/sidebar_patch_tests.js b/addons/im_livechat/static/tests/sidebar_patch_tests.js index 6ea3f43bba3..589db4c154d 100644 --- a/addons/im_livechat/static/tests/sidebar_patch_tests.js +++ b/addons/im_livechat/static/tests/sidebar_patch_tests.js @@ -1,13 +1,12 @@ /* @odoo-module */ -import { afterNextRender, click, start, startServer } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; -import { makeFakeNotificationService } from "@web/../tests/helpers/mock_services"; import { nextTick } from "@web/../tests/helpers/utils"; QUnit.module("discuss sidebar (patch)"); -QUnit.test("Unknown visitor", async (assert) => { +QUnit.test("Unknown visitor", async () => { const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -19,12 +18,12 @@ QUnit.test("Unknown visitor", async (assert) => { livechat_operator_id: pyEnv.currentPartnerId, }); const { openDiscuss } = await start(); - await openDiscuss(); - assert.containsOnce($, ".o-mail-DiscussSidebar .o-mail-DiscussSidebarCategory-livechat"); - assert.containsOnce($, ".o-mail-DiscussSidebarChannel:contains(Visitor 11)"); + openDiscuss(); + await contains(".o-mail-DiscussSidebar .o-mail-DiscussSidebarCategory-livechat"); + await contains(".o-mail-DiscussSidebarChannel:contains(Visitor 11)"); }); -QUnit.test("Known user with country", async (assert) => { +QUnit.test("Known user with country", async () => { const pyEnv = await startServer(); const countryId = pyEnv["res.country"].create({ code: "be", @@ -43,11 +42,11 @@ QUnit.test("Known user with country", async (assert) => { livechat_operator_id: pyEnv.currentPartnerId, }); const { openDiscuss } = await start(); - await openDiscuss(); - assert.containsOnce($, ".o-mail-DiscussSidebarChannel:contains(Jean (Belgium))"); + openDiscuss(); + await contains(".o-mail-DiscussSidebarChannel:contains(Jean (Belgium))"); }); -QUnit.test("Do not show channel when visitor is typing", async (assert) => { +QUnit.test("Do not show channel when visitor is typing", async () => { const pyEnv = await startServer(); pyEnv["res.users"].write([pyEnv.currentUserId], { im_status: "online" }); const livechatChannelId = pyEnv["im_livechat.channel"].create({ @@ -70,8 +69,9 @@ QUnit.test("Do not show channel when visitor is typing", async (assert) => { livechat_operator_id: pyEnv.currentPartnerId, }); const { env, openDiscuss } = await start(); - await openDiscuss(); - assert.containsNone($, ".o-mail-DiscussSidebarCategory-livechat"); + openDiscuss(); + await contains(".o-mail-DiscussSidebarCategory", 2); + await contains(".o-mail-DiscussSidebarCategory-livechat", 0); // simulate livechat visitor typing const channel = pyEnv["discuss.channel"].searchRead([["id", "=", channelId]])[0]; await pyEnv.withUser(pyEnv.publicUserId, () => @@ -80,8 +80,9 @@ QUnit.test("Do not show channel when visitor is typing", async (assert) => { uuid: channel.uuid, }) ); + // weak test, no guaranteed that we waited long enough for the livechat to potentially appear await nextTick(); - assert.containsNone($, ".o-mail-DiscussSidebarCategory-livechat"); + await contains(".o-mail-DiscussSidebarCategory-livechat", 0); }); QUnit.test("Close should update the value on the server", async (assert) => { @@ -101,7 +102,7 @@ QUnit.test("Close should update the value on the server", async (assert) => { }); const currentUserId = pyEnv.currentUserId; const { env, openDiscuss } = await start(); - await openDiscuss(); + openDiscuss(); const initalSettings = await env.services.orm.call( "res.users.settings", "_find_or_create_for_user", @@ -134,7 +135,7 @@ QUnit.test("Open should update the value on the server", async (assert) => { }); const currentUserId = pyEnv.currentUserId; const { env, openDiscuss } = await start(); - await openDiscuss(); + openDiscuss(); const initalSettings = await env.services.orm.call( "res.users.settings", "_find_or_create_for_user", @@ -150,7 +151,7 @@ QUnit.test("Open should update the value on the server", async (assert) => { assert.ok(newSettings.is_discuss_sidebar_category_livechat_open); }); -QUnit.test("Open from the bus", async (assert) => { +QUnit.test("Open from the bus", async () => { const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -166,26 +167,19 @@ QUnit.test("Open from the bus", async (assert) => { is_discuss_sidebar_category_livechat_open: false, }); const { openDiscuss } = await start(); - await openDiscuss(); - assert.containsNone( - $, - ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel" - ); - await afterNextRender(() => { - pyEnv["bus.bus"]._sendone(pyEnv.currentPartner, "mail.record/insert", { - "res.users.settings": { - id: settingsId, - is_discuss_sidebar_category_livechat_open: true, - }, - }); + openDiscuss(); + await contains(".o-mail-DiscussSidebarCategory-livechat"); + await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel", 0); + pyEnv["bus.bus"]._sendone(pyEnv.currentPartner, "mail.record/insert", { + "res.users.settings": { + id: settingsId, + is_discuss_sidebar_category_livechat_open: true, + }, }); - assert.containsOnce( - $, - ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel" - ); + await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel"); }); -QUnit.test("Close from the bus", async (assert) => { +QUnit.test("Close from the bus", async () => { const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -201,26 +195,18 @@ QUnit.test("Close from the bus", async (assert) => { is_discuss_sidebar_category_livechat_open: true, }); const { openDiscuss } = await start(); - await openDiscuss(); - assert.containsOnce( - $, - ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel" - ); - await afterNextRender(() => { - pyEnv["bus.bus"]._sendone(pyEnv.currentPartner, "mail.record/insert", { - "res.users.settings": { - id: settingsId, - is_discuss_sidebar_category_livechat_open: false, - }, - }); + openDiscuss(); + await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel"); + pyEnv["bus.bus"]._sendone(pyEnv.currentPartner, "mail.record/insert", { + "res.users.settings": { + id: settingsId, + is_discuss_sidebar_category_livechat_open: false, + }, }); - assert.containsNone( - $, - ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel" - ); + await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel", 0); }); -QUnit.test("Smiley face avatar for an anonymous livechat item", async (assert) => { +QUnit.test("Smiley face avatar for an anonymous livechat item", async () => { const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -232,15 +218,13 @@ QUnit.test("Smiley face avatar for an anonymous livechat item", async (assert) = livechat_operator_id: pyEnv.currentPartnerId, }); const { openDiscuss } = await start(); - await openDiscuss(); - assert.strictEqual( - $(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel img")[0].dataset - .src, - "/mail/static/src/img/smiley/avatar.jpg" + openDiscuss(); + await contains( + ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel img[data-src='/mail/static/src/img/smiley/avatar.jpg']" ); }); -QUnit.test("Partner profile picture for livechat item linked to a partner", async (assert) => { +QUnit.test("Partner profile picture for livechat item linked to a partner", async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({ name: "Jean" }); const channelId = pyEnv["discuss.channel"].create({ @@ -252,15 +236,13 @@ QUnit.test("Partner profile picture for livechat item linked to a partner", asyn livechat_operator_id: pyEnv.currentPartnerId, }); const { openDiscuss } = await start(); - await openDiscuss(channelId); - assert.strictEqual( - $(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel img")[0].dataset - .src, - `/web/image/res.partner/${partnerId}/avatar_128` + openDiscuss(channelId); + await contains( + `.o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel img[data-src='/web/image/res.partner/${partnerId}/avatar_128']` ); }); -QUnit.test("No counter if the category is unfolded and with unread messages", async (assert) => { +QUnit.test("No counter if the category is unfolded and with unread messages", async () => { const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -279,15 +261,12 @@ QUnit.test("No counter if the category is unfolded and with unread messages", as livechat_operator_id: pyEnv.currentPartnerId, }); const { openDiscuss } = await start(); - await openDiscuss(); - assert.containsNone( - $, - ".o-mail-DiscussSidebarCategory-livechat .o-mail-Discuss-category-counter", - "should not have a counter if the category is unfolded and with unread messages" - ); + openDiscuss(); + await contains(".o-mail-DiscussSidebarCategory-livechat"); + await contains(".o-mail-DiscussSidebarCategory-livechat .o-mail-Discuss-category-counter", 0); }); -QUnit.test("No counter if category is folded and without unread messages", async (assert) => { +QUnit.test("No counter if category is folded and without unread messages", async () => { const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -303,17 +282,14 @@ QUnit.test("No counter if category is folded and without unread messages", async is_discuss_sidebar_category_livechat_open: false, }); const { openDiscuss } = await start(); - await openDiscuss(); - assert.containsNone( - $, - ".o-mail-DiscussSidebarCategory-livechat .o-discuss-badge", - "should not have a counter if the category is unfolded and with unread messages" - ); + openDiscuss(); + await contains(".o-mail-DiscussSidebarCategory-livechat"); + await contains(".o-mail-DiscussSidebarCategory-livechat .o-discuss-badge", 0); }); QUnit.test( "Counter should have correct value of unread threads if category is folded and with unread messages", - async (assert) => { + async () => { const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -336,15 +312,12 @@ QUnit.test( is_discuss_sidebar_category_livechat_open: false, }); const { openDiscuss } = await start(); - await openDiscuss(); - assert.strictEqual( - $(".o-mail-DiscussSidebarCategory-livechat .o-discuss-badge").text(), - "1" - ); + openDiscuss(); + await contains(".o-mail-DiscussSidebarCategory-livechat .o-discuss-badge:contains(1)"); } ); -QUnit.test("Close manually by clicking the title", async (assert) => { +QUnit.test("Close manually by clicking the title", async () => { const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -360,18 +333,14 @@ QUnit.test("Close manually by clicking the title", async (assert) => { is_discuss_sidebar_category_livechat_open: true, }); const { openDiscuss } = await start(); - await openDiscuss(); - assert.containsOnce( - $, - ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel", - "Category is unfolded initially" - ); + openDiscuss(); + await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel"); // fold the livechat category await click(".o-mail-DiscussSidebarCategory-livechat .btn"); - assert.containsNone($, ".o-mail-DiscussSidebarChannel"); + await contains(".o-mail-DiscussSidebarChannel", 0); }); -QUnit.test("Open manually by clicking the title", async (assert) => { +QUnit.test("Open manually by clicking the title", async () => { const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -387,21 +356,15 @@ QUnit.test("Open manually by clicking the title", async (assert) => { is_discuss_sidebar_category_livechat_open: false, }); const { openDiscuss } = await start(); - await openDiscuss(); - assert.containsNone( - $, - ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel", - "Category is folded initially" - ); + openDiscuss(); + await contains(".o-mail-DiscussSidebarCategory-livechat"); + await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel", 0); // open the livechat category await click(".o-mail-DiscussSidebarCategory-livechat .btn"); - assert.containsOnce( - $, - ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel" - ); + await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel"); }); -QUnit.test("Category item should be invisible if the category is closed", async (assert) => { +QUnit.test("Category item should be invisible if the category is closed", async () => { const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -413,51 +376,13 @@ QUnit.test("Category item should be invisible if the category is closed", async livechat_operator_id: pyEnv.currentPartnerId, }); const { openDiscuss } = await start(); - await openDiscuss(); - assert.containsOnce( - $, - ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel" - ); + openDiscuss(); + await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel"); await click(".o-mail-DiscussSidebarCategory-livechat .btn"); - assert.containsNone( - $, - ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel" - ); + await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel", 0); }); -QUnit.test( - "Active category item should be visible even if the category is closed", - async (assert) => { - const pyEnv = await startServer(); - pyEnv["discuss.channel"].create({ - anonymous_name: "Visitor 11", - channel_member_ids: [ - [0, 0, { partner_id: pyEnv.currentPartnerId }], - [0, 0, { partner_id: pyEnv.publicPartnerId }], - ], - channel_type: "livechat", - livechat_operator_id: pyEnv.currentPartnerId, - }); - const { openDiscuss } = await start(); - await openDiscuss(); - assert.containsOnce( - $, - ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel" - ); - await click(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel"); - assert.containsOnce( - $, - ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel.o-active" - ); - await click(".o-mail-DiscussSidebarCategory-livechat .btn"); - assert.containsOnce( - $, - ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel" - ); - } -); - -QUnit.test("Clicking on unpin button unpins the channel", async (assert) => { +QUnit.test("Active category item should be visible even if the category is closed", async () => { const pyEnv = await startServer(); pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -468,17 +393,35 @@ QUnit.test("Clicking on unpin button unpins the channel", async (assert) => { channel_type: "livechat", livechat_operator_id: pyEnv.currentPartnerId, }); - const { openDiscuss } = await start({ - services: { - notification: makeFakeNotificationService((message) => assert.step(message)), - }, - }); - await openDiscuss(); - await click(".o-mail-DiscussSidebarChannel [title='Unpin Conversation']"); - assert.verifySteps(["You unpinned your conversation with Visitor 11"]); + const { openDiscuss } = await start(); + openDiscuss(); + await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel"); + await click(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel"); + await contains( + ".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel.o-active" + ); + await click(".o-mail-DiscussSidebarCategory-livechat .btn"); + await contains(".o-mail-DiscussSidebarCategory-livechat + .o-mail-DiscussSidebarChannel"); }); -QUnit.test("Message unread counter", async (assert) => { +QUnit.test("Clicking on unpin button unpins the channel", async () => { + const pyEnv = await startServer(); + pyEnv["discuss.channel"].create({ + anonymous_name: "Visitor 11", + channel_member_ids: [ + [0, 0, { partner_id: pyEnv.currentPartnerId }], + [0, 0, { partner_id: pyEnv.publicPartnerId }], + ], + channel_type: "livechat", + livechat_operator_id: pyEnv.currentPartnerId, + }); + const { openDiscuss } = await start(); + openDiscuss(); + await click(".o-mail-DiscussSidebarChannel [title='Unpin Conversation']"); + await contains(".o_notification:contains(You unpinned your conversation with Visitor 11)"); +}); + +QUnit.test("Message unread counter", async () => { const pyEnv = await startServer(); const channelId = pyEnv["discuss.channel"].create({ anonymous_name: "Visitor 11", @@ -490,14 +433,12 @@ QUnit.test("Message unread counter", async (assert) => { livechat_operator_id: pyEnv.currentPartnerId, }); const { env, openDiscuss } = await start(); - await openDiscuss(); - await afterNextRender(() => - pyEnv.withUser(pyEnv.publicUserId, () => - env.services.rpc("/im_livechat/chat_post", { - message_content: "hu", - uuid: pyEnv["discuss.channel"].searchRead([["id", "=", channelId]])[0].uuid, - }) - ) + openDiscuss(); + pyEnv.withUser(pyEnv.publicUserId, () => + env.services.rpc("/im_livechat/chat_post", { + message_content: "hu", + uuid: pyEnv["discuss.channel"].searchRead([["id", "=", channelId]])[0].uuid, + }) ); - assert.containsOnce($, ".o-mail-DiscussSidebarChannel .badge:contains(1)"); + await contains(".o-mail-DiscussSidebarChannel .badge:contains(1)"); }); diff --git a/addons/im_livechat/static/tests/suggestions_tests.js b/addons/im_livechat/static/tests/suggestions_tests.js index 201183b662e..c96fd46fbd8 100644 --- a/addons/im_livechat/static/tests/suggestions_tests.js +++ b/addons/im_livechat/static/tests/suggestions_tests.js @@ -1,11 +1,11 @@ /* @odoo-module */ import { Command } from "@mail/../tests/helpers/command"; -import { insertText, start, startServer } from "@mail/../tests/helpers/test_utils"; +import { contains, insertText, start, startServer } from "@mail/../tests/helpers/test_utils"; QUnit.module("suggestion"); -QUnit.test("Suggestions are shown after delimiter was used in text (:)", async (assert) => { +QUnit.test("Suggestions are shown after delimiter was used in text (:)", async () => { const pyEnv = await startServer(); pyEnv["mail.shortcode"].create({ source: "hello", @@ -22,10 +22,10 @@ QUnit.test("Suggestions are shown after delimiter was used in text (:)", async ( const { openDiscuss } = await start(); await openDiscuss(channelId); await insertText(".o-mail-Composer-input", ":"); - assert.containsOnce($, ".o-mail-Composer-suggestion"); + await contains(".o-mail-Composer-suggestion"); await insertText(".o-mail-Composer-input", ")"); - assert.containsNone($, ".o-mail-Composer-suggestion"); + await contains(".o-mail-Composer-suggestion", 0); await insertText(".o-mail-Composer-input", " "); await insertText(".o-mail-Composer-input", ":"); - assert.containsOnce($, ".o-mail-Composer-suggestion:contains(hello)"); + await contains(".o-mail-Composer-suggestion:contains(hello)"); }); diff --git a/addons/im_livechat/static/tests/thread_model_patch_tests.js b/addons/im_livechat/static/tests/thread_model_patch_tests.js index 25a26469e47..3a5dffef76d 100644 --- a/addons/im_livechat/static/tests/thread_model_patch_tests.js +++ b/addons/im_livechat/static/tests/thread_model_patch_tests.js @@ -3,11 +3,11 @@ import { startServer } from "@bus/../tests/helpers/mock_python_environment"; import { Command } from "@mail/../tests/helpers/command"; -import { click, start } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start } from "@mail/../tests/helpers/test_utils"; QUnit.module("Thread model"); -QUnit.test("Thread name unchanged when inviting new users", async (assert) => { +QUnit.test("Thread name unchanged when inviting new users", async () => { const pyEnv = await startServer(); const userId = pyEnv["res.users"].create({ name: "James" }); pyEnv["res.partner"].create({ @@ -25,11 +25,12 @@ QUnit.test("Thread name unchanged when inviting new users", async (assert) => { }); const { openDiscuss } = await start(); await openDiscuss(channelId); - assert.containsOnce($, ".o-mail-Discuss-threadName[title='Visitor #20']"); + await contains(".o-mail-Discuss-threadName[title='Visitor #20']"); await click("button[title='Add Users']"); await click(".o-discuss-ChannelInvitation-selectable:contains(James) input"); - await click("button:contains(Invite)"); + await click("button:contains(Invite):not(:disabled)"); + await contains(".o-discuss-ChannelInvitation", 0); await click("button[title='Show Member List']"); - assert.containsOnce($, ".o-discuss-ChannelMember:contains(James)"); - assert.containsOnce($, ".o-mail-Discuss-threadName[title='Visitor #20']"); + await contains(".o-discuss-ChannelMember:contains(James)"); + await contains(".o-mail-Discuss-threadName[title='Visitor #20']"); }); diff --git a/addons/mail/static/src/core/common/attachment_model.js b/addons/mail/static/src/core/common/attachment_model.js index 3c8a730e0ee..66554a80bab 100644 --- a/addons/mail/static/src/core/common/attachment_model.js +++ b/addons/mail/static/src/core/common/attachment_model.js @@ -132,9 +132,9 @@ export class Attachment { return assignDefined( {}, { - access_token: this.accessToken, + access_token: this.accessToken || undefined, filename: this.name || undefined, - unique: this.checksum, + unique: this.checksum || undefined, } ); } diff --git a/addons/mail/static/src/core/common/composer.js b/addons/mail/static/src/core/common/composer.js index 76afb4d11af..1814efbedcc 100644 --- a/addons/mail/static/src/core/common/composer.js +++ b/addons/mail/static/src/core/common/composer.js @@ -495,7 +495,7 @@ export class Composer extends Component { const el = this.ref.el; const attachments = this.props.composer.attachments; if ( - el.value.trim() || + this.props.composer.textInputContent.trim() || (attachments.length > 0 && attachments.every(({ uploading }) => !uploading)) || (this.message && this.message.attachments.length > 0) ) { @@ -503,7 +503,7 @@ export class Composer extends Component { return; } this.state.active = false; - await cb(el.value); + await cb(this.props.composer.textInputContent); if (this.props.onPostCallback) { this.props.onPostCallback(); } @@ -556,7 +556,10 @@ export class Composer extends Component { } async editMessage() { - if (this.ref.el.value || this.props.composer.message.attachments.length > 0) { + if ( + this.props.composer.textInputContent || + this.props.composer.message.attachments.length > 0 + ) { await this.processMessage(async (value) => this.messageService.edit( this.props.composer.message, @@ -577,7 +580,7 @@ export class Composer extends Component { } addEmoji(str) { - const textContent = this.ref.el.value; + const textContent = this.props.composer.textInputContent; const firstPart = textContent.slice(0, this.props.composer.selection.start); const secondPart = textContent.slice(this.props.composer.selection.end, textContent.length); this.props.composer.textInputContent = firstPart + str + secondPart; diff --git a/addons/mail/static/src/core/common/discuss.xml b/addons/mail/static/src/core/common/discuss.xml index e6e40d5f22e..ef60cbc2d80 100644 --- a/addons/mail/static/src/core/common/discuss.xml +++ b/addons/mail/static/src/core/common/discuss.xml @@ -39,7 +39,7 @@ /> -
+
`, }; - const { openView } = await start({ serverData: { views } }); - await openView({ res_model: "res.partner", views: [[false, "form"]] }); + const { openFormView } = await start({ serverData: { views } }); + openFormView("res.partner"); await click("button:contains(Activities)"); - assert.containsOnce($, ".o_dialog:contains(Schedule Activity)"); + await contains(".o_dialog:contains(Schedule Activity)"); } ); -QUnit.test("upload attachment on draft record", async (assert) => { +QUnit.test("upload attachment on draft record", async () => { const views = { "res.partner,false,form": `
diff --git a/addons/mail/static/tests/web/chatter_topbar_tests.js b/addons/mail/static/tests/web/chatter_topbar_tests.js index b2d1c33d3ac..fc15cd10806 100644 --- a/addons/mail/static/tests/web/chatter_topbar_tests.js +++ b/addons/mail/static/tests/web/chatter_topbar_tests.js @@ -1,12 +1,11 @@ /* @odoo-module */ import { - afterNextRender, click, + contains, nextAnimationFrame, start, startServer, - waitUntil, } from "@mail/../tests/helpers/test_utils"; import { DELAY_FOR_SPINNER } from "@mail/core/web/chatter"; @@ -14,22 +13,21 @@ import { makeDeferred } from "@web/../tests/helpers/utils"; QUnit.module("chatter topbar"); -QUnit.test("base rendering", async (assert) => { +QUnit.test("base rendering", async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); const { openView } = await start(); - await openView({ + openView({ res_id: partnerId, res_model: "res.partner", views: [[false, "form"]], }); - - assert.containsOnce($, ".o-mail-Chatter-topbar"); - assert.containsOnce($, "button:contains(Send message)"); - assert.containsOnce($, "button:contains(Log note)"); - assert.containsOnce($, "button:contains(Activities)"); - assert.containsOnce($, "button[aria-label='Attach files']"); - assert.containsOnce($, ".o-mail-Followers"); + await contains(".o-mail-Chatter-topbar"); + await contains("button:contains(Send message)"); + await contains("button:contains(Log note)"); + await contains("button:contains(Activities)"); + await contains("button[aria-label='Attach files']"); + await contains(".o-mail-Followers"); }); QUnit.test("rendering with multiple partner followers", async (assert) => { @@ -52,109 +50,106 @@ QUnit.test("rendering with multiple partner followers", async (assert) => { }, ]); const { openView } = await start(); - await openView({ + openView({ res_id: partnerId_3, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsOnce($, ".o-mail-Followers"); - assert.containsOnce($, ".o-mail-Followers-button"); + await contains(".o-mail-Followers"); + await contains(".o-mail-Followers-button"); await click(".o-mail-Followers-button"); - assert.containsOnce($, ".o-mail-Followers-dropdown"); - assert.containsN($, ".o-mail-Follower", 2); + await contains(".o-mail-Followers-dropdown"); + await contains(".o-mail-Follower", 2); assert.strictEqual($(".o-mail-Follower:eq(0)").text().trim(), "Jean Michang"); assert.strictEqual($(".o-mail-Follower:eq(1)").text().trim(), "Eden Hazard"); }); -QUnit.test("log note toggling", async (assert) => { +QUnit.test("log note toggling", async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); const { openView } = await start(); - await openView({ + openView({ res_id: partnerId, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsOnce($, "button:contains(Log note)"); - assert.doesNotHaveClass($("button:contains(Log note)"), "active"); - assert.containsNone($, ".o-mail-Composer"); + await contains("button:contains(Log note)"); + await contains("button:contains(Log note):not(.active)"); + await contains(".o-mail-Composer", 0); await click("button:contains(Log note)"); - assert.hasClass($("button:contains(Log note)"), "active"); - assert.containsOnce( - $, - ".o-mail-Composer .o-mail-Composer-input[placeholder='Log an internal note...']" - ); + await contains("button:contains(Log note).active"); + await contains(".o-mail-Composer .o-mail-Composer-input[placeholder='Log an internal note…']"); await click("button:contains(Log note)"); - assert.doesNotHaveClass($("button:contains(Log note)"), "active"); - assert.containsNone($, ".o-mail-Composer"); + await contains("button:contains(Log note):not(.active)"); + await contains(".o-mail-Composer", 0); }); -QUnit.test("send message toggling", async (assert) => { +QUnit.test("send message toggling", async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); const { openView } = await start(); - await openView({ + openView({ res_id: partnerId, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsOnce($, "button:contains(Send message)"); - assert.doesNotHaveClass($("button:contains(Send message)"), "active"); - assert.containsNone($, ".o-mail-Composer"); + await contains("button:contains(Send message)"); + await contains("button:contains(Send message):not(.active)"); + await contains(".o-mail-Composer", 0); await click("button:contains(Send message)"); - assert.hasClass($("button:contains(Send message)"), "active"); - assert.containsOnce($, ".o-mail-Composer-input[placeholder='Send a message to followers...']"); + await contains("button:contains(Send message).active"); + await contains(".o-mail-Composer-input[placeholder='Send a message to followers…']"); await click("button:contains(Send message)"); - assert.doesNotHaveClass($("button:contains(Send message)"), "active"); - assert.containsNone($, ".o-mail-Composer"); + await contains("button:contains(Send message):not(.active)"); + await contains(".o-mail-Composer", 0); }); -QUnit.test("log note/send message switching", async (assert) => { +QUnit.test("log note/send message switching", async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); const { openView } = await start(); - await openView({ + openView({ res_id: partnerId, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsOnce($, "button:contains(Send message)"); - assert.doesNotHaveClass($("button:contains(Send message)"), "active"); - assert.containsOnce($, "button:contains(Log note)"); - assert.doesNotHaveClass($("button:contains(Log note)"), "active"); - assert.containsNone($, ".o-mail-Composer"); + await contains("button:contains(Send message)"); + await contains("button:contains(Send message):not(.active)"); + await contains("button:contains(Log note)"); + await contains("button:contains(Log note):not(.active)"); + await contains(".o-mail-Composer", 0); await click("button:contains(Send message)"); - assert.hasClass($("button:contains(Send message)"), "active"); - assert.doesNotHaveClass($("button:contains(Log note)"), "active"); - assert.containsOnce($, ".o-mail-Composer-input[placeholder='Send a message to followers...']"); + await contains("button:contains(Send message).active"); + await contains("button:contains(Log note):not(.active)"); + await contains(".o-mail-Composer-input[placeholder='Send a message to followers…']"); await click("button:contains(Log note)"); - assert.doesNotHaveClass($("button:contains(Send message)"), "active"); - assert.hasClass($("button:contains(Log note)"), "active"); - assert.containsOnce($, ".o-mail-Composer-input[placeholder='Log an internal note...']"); + await contains("button:contains(Send message):not(.active)"); + await contains("button:contains(Log note).active"); + await contains(".o-mail-Composer-input[placeholder='Log an internal note…']"); }); -QUnit.test("attachment counter without attachments", async (assert) => { +QUnit.test("attachment counter without attachments", async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); const { openView } = await start(); - await openView({ + openView({ res_id: partnerId, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsOnce($, "button[aria-label='Attach files']"); - assert.containsNone($, "button[aria-label='Attach files']:contains(0)"); + await contains("button[aria-label='Attach files']"); + await contains("button[aria-label='Attach files']:contains(0)", 0); }); -QUnit.test("attachment counter with attachments", async (assert) => { +QUnit.test("attachment counter with attachments", async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); pyEnv["ir.attachment"].create([ @@ -172,15 +167,15 @@ QUnit.test("attachment counter with attachments", async (assert) => { }, ]); const { openView } = await start(); - await openView({ + openView({ res_id: partnerId, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsOnce($, "button[aria-label='Attach files']:contains(2)"); + await contains("button[aria-label='Attach files']:contains(2)"); }); -QUnit.test("attachment counter while loading attachments", async (assert) => { +QUnit.test("attachment counter while loading attachments", async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); const { advanceTime, openView } = await start({ @@ -191,17 +186,18 @@ QUnit.test("attachment counter while loading attachments", async (assert) => { } }, }); - await openView({ + openView({ res_id: partnerId, res_model: "res.partner", views: [[false, "form"]], }); + await contains("button[aria-label='Attach files']"); await advanceTime(DELAY_FOR_SPINNER); - await waitUntil("button[aria-label='Attach files'] .fa-spin"); - assert.containsNone($, "button[aria-label='Attach files']:contains(0)"); + await contains("button[aria-label='Attach files'] .fa-spin"); + await contains("button[aria-label='Attach files']:contains(0)", 0); }); -QUnit.test("attachment counter transition when attachments become loaded", async (assert) => { +QUnit.test("attachment counter transition when attachments become loaded", async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); const deferred = makeDeferred(); @@ -213,37 +209,37 @@ QUnit.test("attachment counter transition when attachments become loaded", async } }, }); - await openView({ + openView({ res_id: partnerId, res_model: "res.partner", views: [[false, "form"]], }); + await contains("button[aria-label='Attach files']"); await advanceTime(DELAY_FOR_SPINNER); - await waitUntil("button[aria-label='Attach files'] .fa-spin"); - - await afterNextRender(() => deferred.resolve()); - assert.containsNone($, "button[aria-label='Attach files'] .fa-spin"); + await contains("button[aria-label='Attach files'] .fa-spin"); + deferred.resolve(); + await contains("button[aria-label='Attach files'] .fa-spin", 0); }); QUnit.test( "attachment icon open directly the file uploader if there is no attachment yet", - async (assert) => { + async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); const { openView } = await start(); - await openView({ + openView({ res_id: partnerId, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsOnce($, ".o-mail-Chatter-fileUploader"); - assert.containsNone($, ".o-mail-AttachmentBox"); + await contains(".o-mail-Chatter-fileUploader"); + await contains(".o-mail-AttachmentBox", 0); } ); QUnit.test( "attachment icon open the attachment box when there is at least 1 attachment", - async (assert) => { + async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); pyEnv["ir.attachment"].create([ @@ -255,33 +251,36 @@ QUnit.test( }, ]); const { openView } = await start(); - await openView({ + openView({ res_id: partnerId, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsNone($, ".o-mail-Chatter-fileUploader"); + await contains("button[aria-label='Attach files']"); + await contains(".o-mail-AttachmentBox", 0); + await contains(".o-mail-Chatter-fileUploader", 0); await click("button[aria-label='Attach files']"); - assert.containsOnce($, ".o-mail-AttachmentBox"); + await contains(".o-mail-AttachmentBox"); + await contains(".o-mail-Chatter-fileUploader"); } ); -QUnit.test("composer state conserved when clicking on another topbar button", async (assert) => { +QUnit.test("composer state conserved when clicking on another topbar button", async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); const { openFormView } = await start(); await openFormView("res.partner", partnerId); - assert.containsOnce($, ".o-mail-Chatter-topbar"); - assert.containsOnce($, "button:contains(Send message)"); - assert.containsOnce($, "button:contains(Log note)"); - assert.containsOnce($, "button[aria-label='Attach files']"); + await contains(".o-mail-Chatter-topbar"); + await contains("button:contains(Send message)"); + await contains("button:contains(Log note)"); + await contains("button[aria-label='Attach files']"); await click("button:contains(Log note)"); - assert.containsOnce($, "button:contains(Log note).active"); - assert.containsNone($, "button:contains(Send message).active"); + await contains("button:contains(Log note).active"); + await contains("button:contains(Send message).active", 0); $(`button[aria-label='Attach files']`)[0].click(); await nextAnimationFrame(); - assert.containsOnce($, "button:contains(Log note).active"); - assert.containsNone($, "button:contains(Send message).active"); + await contains("button:contains(Log note).active"); + await contains("button:contains(Send message).active", 0); }); diff --git a/addons/mail/static/tests/web/fields/avatar_tests.js b/addons/mail/static/tests/web/fields/avatar_tests.js index e47493d8ed6..6828bfce810 100644 --- a/addons/mail/static/tests/web/fields/avatar_tests.js +++ b/addons/mail/static/tests/web/fields/avatar_tests.js @@ -1,7 +1,7 @@ /* @odoo-module */ import { Avatar } from "@mail/views/web/fields/avatar/avatar"; -import { click, start } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start } from "@mail/../tests/helpers/test_utils"; import { getFixture, mount } from "@web/../tests/helpers/utils"; @@ -17,13 +17,13 @@ QUnit.test("basic rendering", async (assert) => { displayName: "User display name", }, }); - assert.containsOnce($, ".o-mail-Avatar"); - assert.containsOnce($, ".o-mail-Avatar img"); + await contains(".o-mail-Avatar"); + await contains(".o-mail-Avatar img"); assert.strictEqual($(".o-mail-Avatar img")[0].dataset.src, "/web/image/res.users/2/avatar_128"); - assert.containsOnce($, ".o-mail-Avatar span"); + await contains(".o-mail-Avatar span"); assert.strictEqual($(".o-mail-Avatar span")[0].innerText, "User display name"); assert.containsNone($, ".o-mail-ChatWindow"); await click(".o-mail-Avatar img"); - assert.containsOnce($, ".o-mail-ChatWindow"); + await contains(".o-mail-ChatWindow"); }); diff --git a/addons/mail/static/tests/web/follow_button_tests.js b/addons/mail/static/tests/web/follow_button_tests.js index f5dc61f59a4..5a75423fe63 100644 --- a/addons/mail/static/tests/web/follow_button_tests.js +++ b/addons/mail/static/tests/web/follow_button_tests.js @@ -1,20 +1,20 @@ /* @odoo-module */ -import { afterNextRender, click, start, startServer } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; QUnit.module("follow button"); -QUnit.test("base rendering not editable", async (assert) => { +QUnit.test("base rendering not editable", async () => { const { openView, pyEnv } = await start(); - await openView({ + openView({ res_id: pyEnv.currentPartnerId, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsOnce($, ".o-mail-Chatter-follow"); + await contains(".o-mail-Chatter-follow"); }); -QUnit.test("hover following button", async (assert) => { +QUnit.test("hover following button", async () => { const pyEnv = await startServer(); const threadId = pyEnv["res.partner"].create({}); pyEnv["mail.followers"].create({ @@ -24,37 +24,35 @@ QUnit.test("hover following button", async (assert) => { res_model: "res.partner", }); const { openView } = await start(); - await openView({ + openView({ res_id: threadId, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsOnce($, "button:contains(Following)"); - assert.containsNone($, ".fa-times + span:contains(Following)"); - assert.containsOnce($, ".fa-check + span:contains(Following)"); + await contains("button:contains(Following)"); + await contains(".fa-times + span:contains(Following)", 0); + await contains(".fa-check + span:contains(Following)"); - await afterNextRender(() => { - $("button:contains(Following)")[0].dispatchEvent(new window.MouseEvent("mouseenter")); - }); - assert.containsOnce($, "button:contains(Unfollow)"); - assert.containsOnce($, ".fa-times + span:contains(Unfollow)"); - assert.containsNone($, ".fa-check + span:contains(Unfollow)"); + $("button:contains(Following)")[0].dispatchEvent(new window.MouseEvent("mouseenter")); + await contains("button:contains(Unfollow)"); + await contains(".fa-times + span:contains(Unfollow)"); + await contains(".fa-check + span:contains(Unfollow)", 0); }); -QUnit.test('click on "follow" button', async (assert) => { +QUnit.test('click on "follow" button', async () => { const { openView, pyEnv } = await start(); - await openView({ + openView({ res_id: pyEnv.currentPartnerId, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsOnce($, "button:contains(Follow)"); + await contains("button:contains(Follow)"); await click("button:contains(Follow)"); - assert.containsOnce($, "button:contains(Following)"); + await contains("button:contains(Following)"); }); -QUnit.test('Click on "follow" button should save draft record', async (assert) => { +QUnit.test('Click on "follow" button should save draft record', async () => { const views = { "res.partner,false,form": ` @@ -67,15 +65,14 @@ QUnit.test('Click on "follow" button should save draft record', async (assert) =
`, }; const { openFormView } = await start({ serverData: { views } }); - await openFormView("res.partner"); - assert.containsOnce($, "button:contains(Follow)"); - assert.containsOnce($, "div.o_field_char"); - + openFormView("res.partner"); + await contains("button:contains(Follow)"); + await contains("div.o_field_char"); await click("button:contains(Follow)"); - assert.containsOnce($, "div.o_field_invalid"); + await contains("div.o_field_invalid"); }); -QUnit.test('click on "unfollow" button', async (assert) => { +QUnit.test('click on "unfollow" button', async () => { const pyEnv = await startServer(); const threadId = pyEnv["res.partner"].create({}); pyEnv["mail.followers"].create({ @@ -85,13 +82,11 @@ QUnit.test('click on "unfollow" button', async (assert) => { res_model: "res.partner", }); const { openView } = await start(); - await openView({ + openView({ res_id: threadId, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsOnce($, "button:contains(Following)"); - await click("button:contains(Following)"); - assert.containsOnce($, "button:contains(Follow)"); + await contains("button:contains(Follow)"); }); diff --git a/addons/mail/static/tests/web/follower_list_menu_tests.js b/addons/mail/static/tests/web/follower_list_menu_tests.js index 62eed990930..ea1fbe548f2 100644 --- a/addons/mail/static/tests/web/follower_list_menu_tests.js +++ b/addons/mail/static/tests/web/follower_list_menu_tests.js @@ -1,29 +1,31 @@ /* @odoo-module */ -import { afterNextRender, click, start, startServer } from "@mail/../tests/helpers/test_utils"; +import { + click, + contains, + nextAnimationFrame, + start, + startServer, +} from "@mail/../tests/helpers/test_utils"; import { patchWithCleanup } from "@web/../tests/helpers/utils"; -import { nextTick } from "@web/../tests/legacy/helpers/test_utils"; QUnit.module("follower list menu"); -QUnit.test("base rendering not editable", async (assert) => { +QUnit.test("base rendering not editable", async () => { const { openView } = await start(); - await openView( + openView( { res_model: "res.partner", views: [[false, "form"]], }, { mode: "edit" } ); - assert.containsOnce($, ".o-mail-Followers"); - assert.containsOnce($, ".o-mail-Followers-button"); - assert.ok($(".o-mail-Followers-button")[0].disabled); - assert.containsNone($, ".o-mail-Followers-dropdown"); - - $(".o-mail-Followers-button")[0].click(); - await nextTick(); - assert.containsNone($, ".o-mail-Followers-dropdown"); + await contains(".o-mail-Followers"); + await contains(".o-mail-Followers-button:disabled"); + await contains(".o-mail-Followers-dropdown", 0); + await click(".o-mail-Followers-button"); + await contains(".o-mail-Followers-dropdown", 0); }); QUnit.test("base rendering editable", async (assert) => { @@ -39,18 +41,18 @@ QUnit.test("base rendering editable", async (assert) => { } }, }); - await openView({ + openView({ res_id: partnerId, res_model: "res.partner", views: [[false, "form"]], }); - assert.containsOnce($, ".o-mail-Followers"); - assert.containsOnce($, ".o-mail-Followers-button"); + await contains(".o-mail-Followers"); + await contains(".o-mail-Followers-button"); assert.notOk($(".o-mail-Followers-button")[0].disabled); - assert.containsNone($, ".o-mail-Followers-dropdown"); + await contains(".o-mail-Followers-dropdown", 0); await click(".o-mail-Followers-button"); - assert.containsOnce($, ".o-mail-Followers-dropdown"); + await contains(".o-mail-Followers-dropdown"); }); QUnit.test('click on "add followers" button', async (assert) => { @@ -78,7 +80,7 @@ QUnit.test('click on "add followers" button', async (assert) => { } }, }); - await openView({ + openView({ res_id: partnerId_1, res_model: "res.partner", views: [[false, "form"]], @@ -102,21 +104,21 @@ QUnit.test('click on "add followers" button', async (assert) => { }, }); - assert.containsOnce($, ".o-mail-Followers"); - assert.containsOnce($, ".o-mail-Followers-button"); + await contains(".o-mail-Followers"); + await contains(".o-mail-Followers-button"); assert.strictEqual($(".o-mail-Followers-counter").text(), "1"); await click(".o-mail-Followers-button"); - assert.containsOnce($, ".o-mail-Followers-dropdown"); - assert.containsOnce($, "a:contains(Add Followers)"); + await contains(".o-mail-Followers-dropdown"); + await contains("a:contains(Add Followers)"); await click("a:contains(Add Followers)"); - assert.containsNone($, ".o-mail-Followers-dropdown"); + await contains(".o-mail-Followers-dropdown", 0); assert.verifySteps(["action:open_view"]); assert.strictEqual($(".o-mail-Followers-counter").text(), "2"); await click(".o-mail-Followers-button"); - assert.containsN($, ".o-mail-Follower", 2); + await contains(".o-mail-Follower", 2); assert.strictEqual($(".o-mail-Follower").text(), "François PerussePartner3"); }); @@ -148,24 +150,24 @@ QUnit.test("click on remove follower", async (assert) => { } }, }); - await openView({ + openView({ res_id: partnerId_1, res_model: "res.partner", views: [[false, "form"]], }); await click(".o-mail-Followers-button"); - assert.containsOnce($, ".o-mail-Follower"); - assert.containsOnce($, "button[title='Remove this follower']"); + await contains(".o-mail-Follower"); + await contains("button[title='Remove this follower']"); await click("button[title='Remove this follower']"); assert.verifySteps(["message_unsubscribe"]); - assert.containsNone($, ".o-mail-Follower"); + await contains(".o-mail-Follower", 0); }); QUnit.test( 'Hide "Add follower" and subtypes edition/removal buttons except own user on read only record', - async (assert) => { + async () => { const pyEnv = await startServer(); const [partnerId_1, partnerId_2] = pyEnv["res.partner"].create([ { name: "Partner1" }, @@ -195,23 +197,22 @@ QUnit.test( } }, }); - await openView({ + openView({ res_id: partnerId_1, res_model: "res.partner", views: [[false, "form"]], }); await click(".o-mail-Followers-button"); - assert.containsNone($, "a:contains(Add Followers)"); - const $followers = $(".o-mail-Follower"); - assert.containsOnce($followers[0], "button[title='Edit subscription']"); - assert.containsOnce($followers[0], "button[title='Remove this follower']"); - assert.containsNone($followers[1], "button[title='Edit subscription']"); - assert.containsNone($followers[1], "button[title='Remove this follower']"); + await contains("a:contains(Add Followers)", 0); + await contains(".o-mail-Follower:eq(0) button[title='Edit subscription']"); + await contains(".o-mail-Follower:eq(0) button[title='Remove this follower']"); + await contains(".o-mail-Follower:eq(1):not(:has(button[title='Edit subscription']))"); + await contains(".o-mail-Follower:eq(1):not(:has(button[title='Remove this follower']))"); } ); -QUnit.test("Load 100 followers at once", async (assert) => { +QUnit.test("Load 100 followers at once", async () => { const pyEnv = await startServer(); const partnerIds = pyEnv["res.partner"].create( [...Array(210).keys()].map((i) => ({ display_name: `Partner${i}`, name: `Partner${i}` })) @@ -228,22 +229,17 @@ QUnit.test("Load 100 followers at once", async (assert) => { ); const { openFormView } = await start(); await openFormView("res.partner", partnerIds[0]); - assert.containsOnce($, "button[title='Show Followers']:contains(210)"); + await contains("button[title='Show Followers']:contains(210)"); await click("button[title='Show Followers']"); - assert.containsOnce($, ".o-mail-Follower:contains(Mitchell Admin)"); - assert.containsN($, ".o-mail-Follower", 100); - assert.containsOnce($, ".o-mail-Followers-dropdown span:contains(Load more)"); - await afterNextRender(() => - $(".o-mail-Followers-dropdown span:contains(Load more)")[0].scrollIntoView() - ); - assert.containsN($, ".o-mail-Follower", 200); - assert.containsOnce($, ".o-mail-Followers-dropdown span:contains(Load more)"); - await afterNextRender(() => - $(".o-mail-Followers-dropdown span:contains(Load more)")[0].scrollIntoView() - ); - assert.containsN($, ".o-mail-Follower", 210); - assert.containsNone($, ".o-mail-Followers-dropdown span:contains(Load more)"); + await contains(".o-mail-Follower:contains(Mitchell Admin)"); + await contains(".o-mail-Follower", 100); + $(".o-mail-Followers-dropdown span:contains(Load more)")[0].scrollIntoView(); + await contains(".o-mail-Follower", 200); + await nextAnimationFrame(); // give enough time for the Load more button to scroll out of view + $(".o-mail-Followers-dropdown span:contains(Load more)")[0].scrollIntoView(); + await contains(".o-mail-Follower", 210); + await contains(".o-mail-Followers-dropdown span:contains(Load more)", 0); }); QUnit.test("Load 100 recipients at once", async (assert) => { @@ -267,26 +263,18 @@ QUnit.test("Load 100 recipients at once", async (assert) => { ); const { openFormView } = await start(); await openFormView("res.partner", partnerIds[0]); - assert.containsOnce($, "button[title='Show Followers']:contains(210)"); + await contains("button[title='Show Followers']:contains(210)"); await click("button:contains(Send message)"); - assert.containsOnce( - $, - ".o-mail-Chatter:contains('me, partner1, partner2, partner3, partner4, …')" - ); - assert.containsOnce($, "button[title='Show all recipients']"); + await contains(".o-mail-Chatter:contains('me, partner1, partner2, partner3, partner4, …')"); + await contains("button[title='Show all recipients']"); await click("button[title='Show all recipients']"); - assert.containsN($, ".o-mail-RecipientList li", 100); - assert.containsOnce($, ".o-mail-RecipientList span:contains(Load more)"); - await afterNextRender(() => - $(".o-mail-RecipientList span:contains(Load more)")[0].scrollIntoView() - ); - assert.containsN($, ".o-mail-RecipientList li", 200); - assert.containsOnce($, ".o-mail-RecipientList span:contains(Load more)"); - await afterNextRender(() => - $(".o-mail-RecipientList span:contains(Load more)")[0].scrollIntoView() - ); - assert.containsN($, ".o-mail-RecipientList li", 210); - assert.containsNone($, ".o-mail-RecipientList span:contains(Load more)"); + await contains(".o-mail-RecipientList li", 100); + $(".o-mail-RecipientList span:contains(Load more)")[0].scrollIntoView(); + await contains(".o-mail-RecipientList li", 200); + await nextAnimationFrame(); // give enough time for the Load more button to scroll out of view + $(".o-mail-RecipientList span:contains(Load more)")[0].scrollIntoView(); + await contains(".o-mail-RecipientList li", 210); + await contains(".o-mail-RecipientList span:contains(Load more)", 0); }); QUnit.test( @@ -321,14 +309,14 @@ QUnit.test( } }, }); - await openView({ + openView({ res_id: partnerId_1, res_model: "res.partner", views: [[false, "form"]], }); await click(".o-mail-Followers-button"); - assert.containsOnce($, "a:contains(Add Followers)"); + await contains("a:contains(Add Followers)"); const $followers = $(".o-mail-Follower"); assert.containsOnce($followers[0], "button[title='Edit subscription']"); assert.containsOnce($followers[0], "button[title='Remove this follower']"); @@ -352,13 +340,13 @@ QUnit.test( } }, }); - await openView({ + openView({ res_id: partnerId, res_model: "res.partner", views: [[false, "form"]], }); await click(".o-mail-Followers-button"); - assert.containsOnce($, "div:contains(No Followers).disabled"); + await contains("div:contains(No Followers).disabled"); } ); diff --git a/addons/mail/static/tests/web/follower_subtype_tests.js b/addons/mail/static/tests/web/follower_subtype_tests.js index 7c99f85bf24..1348f265b7a 100644 --- a/addons/mail/static/tests/web/follower_subtype_tests.js +++ b/addons/mail/static/tests/web/follower_subtype_tests.js @@ -1,12 +1,10 @@ /* @odoo-module */ -import { click, start, startServer } from "@mail/../tests/helpers/test_utils"; - -import { makeFakeNotificationService } from "@web/../tests/helpers/mock_services"; +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; QUnit.module("follower subtype"); -QUnit.test("simplest layout of a followed subtype", async (assert) => { +QUnit.test("simplest layout of a followed subtype", async () => { const pyEnv = await startServer(); const subtypeId = pyEnv["mail.message.subtype"].create({ default: true, @@ -31,128 +29,114 @@ QUnit.test("simplest layout of a followed subtype", async (assert) => { } }, }); - await openView({ + openView({ res_model: "res.partner", res_id: pyEnv.currentPartnerId, views: [[false, "form"]], }); await click(".o-mail-Followers-button"); await click("button[title='Edit subscription']"); - assert.containsOnce($, ".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype)"); - assert.containsOnce($(".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype)"), "label"); - assert.containsOnce( - $(".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype)"), - "input[type='checkbox']" + await contains( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId}] label:contains(TestSubtype)` ); - assert.strictEqual( - $(".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype) label").text(), - "TestSubtype" - ); - assert.ok( - $(".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype) input[type='checkbox']")[0] - .checked + await contains( + $( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId}] input[type='checkbox']:checked` + ) ); }); -QUnit.test("simplest layout of a not followed subtype", async (assert) => { - const pyEnv = await startServer(); - pyEnv["mail.message.subtype"].create({ - default: true, - name: "TestSubtype", - }); - const followerId = pyEnv["mail.followers"].create({ - display_name: "François Perusse", - partner_id: pyEnv.currentPartnerId, - res_model: "res.partner", - res_id: pyEnv.currentPartnerId, - }); - pyEnv["res.partner"].write([pyEnv.currentPartnerId], { message_follower_ids: [followerId] }); - const { openView } = await start({ - // FIXME: should adapt mock server code to provide "hasWriteAccess" - async mockRPC(route, args, performRPC) { - if (route === "/mail/thread/data") { - // mimic user with write access - const res = await performRPC(...arguments); - res["hasWriteAccess"] = true; - return res; - } - }, - }); - await openView({ - res_model: "res.partner", - res_id: pyEnv.currentPartnerId, - views: [[false, "form"]], - }); - await click(".o-mail-Followers-button"); - await click("button[title='Edit subscription']"); - assert.notOk( - $(".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype) input[type='checkbox']")[0] - .checked, - "checkbox should not be checked as follower subtype is not followed" - ); -}); - -QUnit.test("toggle follower subtype checkbox", async (assert) => { - const pyEnv = await startServer(); - pyEnv["mail.message.subtype"].create({ - default: true, - name: "TestSubtype", - }); - const followerId = pyEnv["mail.followers"].create({ - display_name: "François Perusse", - partner_id: pyEnv.currentPartnerId, - res_model: "res.partner", - res_id: pyEnv.currentPartnerId, - }); - pyEnv["res.partner"].write([pyEnv.currentPartnerId], { message_follower_ids: [followerId] }); - const { openView } = await start({ - // FIXME: should adapt mock server code to provide "hasWriteAccess" - async mockRPC(route, args, performRPC) { - if (route === "/mail/thread/data") { - // mimic user with write access - const res = await performRPC(...arguments); - res["hasWriteAccess"] = true; - return res; - } - }, - }); - await openView({ - res_model: "res.partner", - res_id: pyEnv.currentPartnerId, - views: [[false, "form"]], - }); - await click(".o-mail-Followers-button"); - await click("button[title='Edit subscription']"); - assert.notOk( - $(".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype) input[type='checkbox']")[0] - .checked, - "checkbox should not be checked as follower subtype is not followed" - ); - - await click( - ".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype) input[type='checkbox']" - ); - assert.ok( - $(".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype) input[type='checkbox']")[0] - .checked - ); - - await click( - ".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype) input[type='checkbox']" - ); - assert.notOk( - $(".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype) input[type='checkbox']")[0] - .checked - ); -}); - -QUnit.test("follower subtype apply", async (assert) => { +QUnit.test("simplest layout of a not followed subtype", async () => { const pyEnv = await startServer(); const subtypeId = pyEnv["mail.message.subtype"].create({ + default: true, + name: "TestSubtype", + }); + const followerId = pyEnv["mail.followers"].create({ + display_name: "François Perusse", + partner_id: pyEnv.currentPartnerId, + res_model: "res.partner", + res_id: pyEnv.currentPartnerId, + }); + pyEnv["res.partner"].write([pyEnv.currentPartnerId], { message_follower_ids: [followerId] }); + const { openView } = await start({ + // FIXME: should adapt mock server code to provide "hasWriteAccess" + async mockRPC(route, args, performRPC) { + if (route === "/mail/thread/data") { + // mimic user with write access + const res = await performRPC(...arguments); + res["hasWriteAccess"] = true; + return res; + } + }, + }); + openView({ + res_model: "res.partner", + res_id: pyEnv.currentPartnerId, + views: [[false, "form"]], + }); + await click(".o-mail-Followers-button"); + await click("button[title='Edit subscription']"); + await contains( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId}] input[type='checkbox']:not(:checked)` + ); +}); + +QUnit.test("toggle follower subtype checkbox", async () => { + const pyEnv = await startServer(); + const subtypeId = pyEnv["mail.message.subtype"].create({ + default: true, + name: "TestSubtype", + }); + const followerId = pyEnv["mail.followers"].create({ + display_name: "François Perusse", + partner_id: pyEnv.currentPartnerId, + res_model: "res.partner", + res_id: pyEnv.currentPartnerId, + }); + pyEnv["res.partner"].write([pyEnv.currentPartnerId], { message_follower_ids: [followerId] }); + const { openView } = await start({ + // FIXME: should adapt mock server code to provide "hasWriteAccess" + async mockRPC(route, args, performRPC) { + if (route === "/mail/thread/data") { + // mimic user with write access + const res = await performRPC(...arguments); + res["hasWriteAccess"] = true; + return res; + } + }, + }); + openView({ + res_model: "res.partner", + res_id: pyEnv.currentPartnerId, + views: [[false, "form"]], + }); + await click(".o-mail-Followers-button"); + await click("button[title='Edit subscription']"); + await contains( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId}] input[type='checkbox']:not(:checked)` + ); + await click( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId}] input[type='checkbox']` + ); + await contains( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId}] input[type='checkbox']:checked` + ); + await click( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId}] input[type='checkbox']` + ); + await contains( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId}] input[type='checkbox']:not(:checked)` + ); +}); + +QUnit.test("follower subtype apply", async () => { + const pyEnv = await startServer(); + const subtypeId1 = pyEnv["mail.message.subtype"].create({ default: true, name: "TestSubtype1", }); - pyEnv["mail.message.subtype"].create({ + const subtypeId2 = pyEnv["mail.message.subtype"].create({ default: true, name: "TestSubtype2", }); @@ -161,20 +145,11 @@ QUnit.test("follower subtype apply", async (assert) => { partner_id: pyEnv.currentPartnerId, res_model: "res.partner", res_id: pyEnv.currentPartnerId, - subtype_ids: [subtypeId], + subtype_ids: [subtypeId1], }); pyEnv["res.partner"].write([pyEnv.currentPartnerId], { message_follower_ids: [followerId] }); - const { openView } = await start({ - services: { - notification: makeFakeNotificationService((message) => { - assert.strictEqual( - message, - "The subscription preferences were successfully applied." - ); - }), - }, - }); - await openView({ + const { openView } = await start(); + openView({ res_model: "res.partner", res_id: pyEnv.currentPartnerId, views: [[false, "form"]], @@ -182,15 +157,26 @@ QUnit.test("follower subtype apply", async (assert) => { await click(".o-mail-Followers-button"); await click("button[title='Edit subscription']"); - const subtype1 = - ".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype1) input[type='checkbox']"; - const subtype2 = - ".o-mail-FollowerSubtypeDialog-subtype:contains(TestSubtype2) input[type='checkbox']"; - assert.ok($(subtype1)[0].checked); - assert.notOk($(subtype2)[0].checked); - await click(subtype1); - assert.notOk($(subtype1)[0].checked); - await click(subtype2); - assert.ok($(subtype2)[0].checked); + await contains( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId1}] input[type='checkbox']:checked` + ); + await contains( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId2}] input[type='checkbox']:not(:checked)` + ); + await click( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId1}] input[type='checkbox']` + ); + await contains( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId1}] input[type='checkbox']:not(:checked)` + ); + await click( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId2}] input[type='checkbox']` + ); + await contains( + `.o-mail-FollowerSubtypeDialog-subtype[data-follower-subtype-id=${subtypeId2}] input[type='checkbox']:checked` + ); await click(".modal-footer button:contains(Apply)"); + await contains( + ".o_notification:contains(The subscription preferences were successfully applied.)" + ); }); diff --git a/addons/mail/static/tests/web/follower_tests.js b/addons/mail/static/tests/web/follower_tests.js index 228334e7456..16f91892d70 100644 --- a/addons/mail/static/tests/web/follower_tests.js +++ b/addons/mail/static/tests/web/follower_tests.js @@ -1,12 +1,12 @@ /* @odoo-module */ -import { click, nextAnimationFrame, start, startServer } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; import { editInput, makeDeferred, patchWithCleanup } from "@web/../tests/helpers/utils"; QUnit.module("follower"); -QUnit.test("base rendering not editable", async (assert) => { +QUnit.test("base rendering not editable", async () => { const pyEnv = await startServer(); const [threadId, partnerId] = pyEnv["res.partner"].create([{}, {}]); pyEnv["mail.followers"].create({ @@ -25,19 +25,19 @@ QUnit.test("base rendering not editable", async (assert) => { } }, }); - await openView({ + openView({ res_id: threadId, res_model: "res.partner", views: [[false, "form"]], }); await click(".o-mail-Followers-button"); - assert.containsOnce($, ".o-mail-Follower"); - assert.containsOnce($, ".o-mail-Follower-details"); - assert.containsOnce($, ".o-mail-Follower-avatar"); - assert.containsNone($, ".o-mail-Follower-action"); + await contains(".o-mail-Follower"); + await contains(".o-mail-Follower-details"); + await contains(".o-mail-Follower-avatar"); + await contains(".o-mail-Follower-action", 0); }); -QUnit.test("base rendering editable", async (assert) => { +QUnit.test("base rendering editable", async () => { const pyEnv = await startServer(); const [threadId, partnerId] = pyEnv["res.partner"].create([{}, {}]); pyEnv["mail.followers"].create({ @@ -47,18 +47,18 @@ QUnit.test("base rendering editable", async (assert) => { res_model: "res.partner", }); const { openView } = await start(); - await openView({ + openView({ res_id: threadId, res_model: "res.partner", views: [[false, "form"]], }); await click(".o-mail-Followers-button"); - assert.containsOnce($, ".o-mail-Follower"); - assert.containsOnce($, ".o-mail-Follower-details"); - assert.containsOnce($, ".o-mail-Follower-avatar"); - assert.containsOnce($, ".o-mail-Follower"); - assert.containsOnce($, "button[title='Edit subscription']"); - assert.containsOnce($, "button[title='Remove this follower']"); + await contains(".o-mail-Follower"); + await contains(".o-mail-Follower-details"); + await contains(".o-mail-Follower-avatar"); + await contains(".o-mail-Follower"); + await contains("button[title='Edit subscription']"); + await contains("button[title='Remove this follower']"); }); QUnit.test("click on partner follower details", async (assert) => { @@ -72,7 +72,7 @@ QUnit.test("click on partner follower details", async (assert) => { }); const openFormDef = makeDeferred(); const { env, openView } = await start(); - await openView({ + openView({ res_id: threadId, res_model: "res.partner", views: [[false, "form"]], @@ -87,8 +87,8 @@ QUnit.test("click on partner follower details", async (assert) => { }, }); await click(".o-mail-Followers-button"); - assert.containsOnce($, ".o-mail-Follower"); - assert.containsOnce($, ".o-mail-Follower-details"); + await contains(".o-mail-Follower"); + await contains(".o-mail-Follower-details"); $(".o-mail-Follower-details")[0].click(); await openFormDef; @@ -111,19 +111,19 @@ QUnit.test("click on edit follower", async (assert) => { } }, }); - await openView({ + openView({ res_id: threadId, res_model: "res.partner", views: [[false, "form"]], }); await click(".o-mail-Followers-button"); - assert.containsOnce($, ".o-mail-Follower"); - assert.containsOnce($, "button[title='Edit subscription']"); + await contains(".o-mail-Follower"); + await contains("button[title='Edit subscription']"); await click("button[title='Edit subscription']"); - assert.containsNone($, ".o-mail-Follower"); + await contains(".o-mail-Follower", 0); assert.verifySteps(["fetch_subtypes"]); - assert.containsOnce($, ".o-mail-FollowerSubtypeDialog"); + await contains(".o-mail-FollowerSubtypeDialog"); }); QUnit.test("edit follower and close subtype dialog", async (assert) => { @@ -142,21 +142,21 @@ QUnit.test("edit follower and close subtype dialog", async (assert) => { } }, }); - await openView({ + openView({ res_id: threadId, res_model: "res.partner", views: [[false, "form"]], }); await click(".o-mail-Followers-button"); - assert.containsOnce($, ".o-mail-Follower"); - assert.containsOnce($, "button[title='Edit subscription']"); + await contains(".o-mail-Follower"); + await contains("button[title='Edit subscription']"); await click("button[title='Edit subscription']"); + await contains(".o-mail-FollowerSubtypeDialog"); assert.verifySteps(["fetch_subtypes"]); - assert.containsOnce($, ".o-mail-FollowerSubtypeDialog"); await click(".o-mail-FollowerSubtypeDialog button:contains(Cancel)"); - assert.containsNone($, ".o-mail-FollowerSubtypeDialog"); + await contains(".o-mail-FollowerSubtypeDialog", 0); }); QUnit.test("remove a follower in a dirty form view", async (assert) => { @@ -181,19 +181,17 @@ QUnit.test("remove a follower in a dirty form view", async (assert) => { `, }; const { openFormView } = await start({ serverData: { views } }); - await openFormView("res.partner", threadId); - click(".o_field_many2many_tags[name='channel_ids'] input").catch(() => {}); - await nextAnimationFrame(); - click(".dropdown-item:contains(General)").catch(() => {}); - await nextAnimationFrame(); - assert.containsOnce($, ".o_tag:contains(General)"); - assert.strictEqual($(".o-mail-Followers-counter")[0].innerText, "1"); + openFormView("res.partner", threadId); + await click(".o_field_many2many_tags[name='channel_ids'] input"); + await click(".dropdown-item:contains(General)"); + await contains(".o_tag:contains(General)"); + await contains(".o-mail-Followers-counter:contains(1)"); await editInput(document.body, ".o_field_char[name=name] input", "some value"); await click(".o-mail-Followers-button"); await click("button[title='Remove this follower']"); - assert.strictEqual($(".o-mail-Followers-counter")[0].innerText, "0"); + await contains(".o-mail-Followers-counter:contains(0)"); assert.strictEqual($(".o_field_char[name=name] input").val(), "some value"); - assert.containsOnce($, ".o_tag:contains(General)"); + await contains(".o_tag:contains(General)"); }); QUnit.test("removing a follower should reload form view", async function (assert) { @@ -212,9 +210,11 @@ QUnit.test("removing a follower should reload form view", async function (assert } }, }); - await openFormView("res.partner", threadId); + openFormView("res.partner", threadId); + await contains(".o-mail-Followers-button"); assert.verifySteps([`read ${threadId}`]); await click(".o-mail-Followers-button"); await click("button[title='Remove this follower']"); + await contains(".o-mail-Followers-counter:contains(0)"); assert.verifySteps([`read ${threadId}`]); }); diff --git a/addons/mail/static/tests/web/form_renderer_tests.js b/addons/mail/static/tests/web/form_renderer_tests.js index fdc3139e4c2..ccead229f9c 100644 --- a/addons/mail/static/tests/web/form_renderer_tests.js +++ b/addons/mail/static/tests/web/form_renderer_tests.js @@ -1,37 +1,10 @@ /* @odoo-module */ import { patchUiSize, SIZES } from "@mail/../tests/helpers/patch_ui_size"; -import { click, start, startServer } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; QUnit.module("Form renderer"); -QUnit.test( - "schedule activities on draft record should prompt with scheduling an activity (proceed with action)", - async (assert) => { - const pyEnv = await startServer(); - const partnerId = pyEnv["res.partner"].create({}); - const views = { - "res.partner,false,form": ` -
- - - -
- -
-
`, - }; - const { openView } = await start({ serverData: { views } }); - await openView({ - res_id: partnerId, - res_model: "res.partner", - views: [[false, "form"]], - }); - await click("button:contains(Activities)"); - assert.containsOnce($, ".o_dialog:contains(Schedule Activity)"); - } -); - QUnit.test("Form view not scrolled when switching record", async (assert) => { const pyEnv = await startServer(); const [partnerId_1, partnerId_2] = pyEnv["res.partner"].create([ @@ -62,7 +35,7 @@ QUnit.test("Form view not scrolled when switching record", async (assert) => { }; patchUiSize({ size: SIZES.LG }); const { openView } = await start({ serverData: { views } }); - await openView( + openView( { res_model: "res.partner", res_id: partnerId_1, @@ -70,12 +43,12 @@ QUnit.test("Form view not scrolled when switching record", async (assert) => { }, { resIds: [partnerId_1, partnerId_2] } ); - assert.strictEqual($(".o_breadcrumb .active").text(), "Partner 1"); + await contains(".o_breadcrumb .active:contains(Partner 1)"); assert.strictEqual($(".o_content")[0].scrollTop, 0); $(".o_content")[0].scrollTop = 150; await click(".o_pager_next"); - assert.strictEqual($(".o_breadcrumb .active").text(), "Partner 2"); + await contains(".o_breadcrumb .active:contains(Partner 2)"); assert.strictEqual($(".o_content")[0].scrollTop, 0); await click(".o_pager_previous"); @@ -84,7 +57,7 @@ QUnit.test("Form view not scrolled when switching record", async (assert) => { QUnit.test( "Attachments that have been unlinked from server should be visually unlinked from record", - async (assert) => { + async () => { // Attachments that have been fetched from a record at certain time and then // removed from the server should be reflected on the UI when the current // partner accesses this record again. @@ -117,7 +90,7 @@ QUnit.test( `, }; const { openView } = await start({ serverData: { views } }); - await openView( + openView( { res_model: "res.partner", res_id: partnerId_1, @@ -128,21 +101,21 @@ QUnit.test( resIds: [partnerId_1, partnerId_2], } ); - assert.containsOnce($, ".o-mail-Chatter button:contains(2)"); - + await contains("button[aria-label='Attach files']:contains(2)"); // The attachment links are updated on (re)load, // so using pager is a way to reload the record "Partner1". await click(".o_pager_next"); + await contains("button[aria-label='Attach files']:not(:has(span))"); // Simulate unlinking attachment 1 from Partner 1. pyEnv["ir.attachment"].write([attachmentId_1], { res_id: 0 }); await click(".o_pager_previous"); - assert.containsOnce($, ".o-mail-Chatter button:contains(1)"); + await contains("button[aria-label='Attach files']:contains(1)"); } ); QUnit.test( "read more/less links are not duplicated when switching from read to edit mode", - async (assert) => { + async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); pyEnv["mail.message"].create({ @@ -179,10 +152,10 @@ QUnit.test( res_id: partnerId, views: [[false, "form"]], }; - await openView(openViewAction); - assert.containsOnce($, ".o-mail-Chatter"); - assert.containsOnce($, ".o-mail-Message"); - assert.containsOnce($, ".o-mail-read-more-less"); + openView(openViewAction); + await contains(".o-mail-Chatter"); + await contains(".o-mail-Message"); + await contains(".o-mail-read-more-less"); } ); @@ -225,18 +198,18 @@ QUnit.test("read more links becomes read less after being clicked", async (asser res_id: partnerId, views: [[false, "form"]], }; - await openView(openViewAction); - assert.containsOnce($, ".o-mail-Chatter"); - assert.containsOnce($, ".o-mail-Message"); - assert.containsOnce($, ".o-mail-read-more-less:contains(Read More)"); + openView(openViewAction); + await contains(".o-mail-Chatter"); + await contains(".o-mail-Message"); + await contains(".o-mail-read-more-less:contains(Read More)"); await click(".o-mail-read-more-less"); - assert.containsOnce($, ".o-mail-read-more-less:contains(Read Less)"); + await contains(".o-mail-read-more-less:contains(Read Less)"); }); QUnit.test( "[TECHNICAL] unfolded read more/less links should not fold on message click besides those button links", - async (assert) => { + async () => { // message click triggers a re-render. Before writing of this test, the // insertion of read more/less links were done during render. This meant // any re-render would re-insert the read more/less links. If some button @@ -277,22 +250,22 @@ QUnit.test( `, }; const { openView } = await start({ serverData: { views } }); - await openView({ + openView({ res_model: "res.partner", res_id: partnerId, views: [[false, "form"]], }); - assert.containsOnce($, ".o-mail-read-more-less:contains(Read More)"); + await contains(".o-mail-read-more-less:contains(Read More)"); await click(".o-mail-read-more-less"); - assert.containsOnce($, ".o-mail-read-more-less:contains(Read Less)"); + await contains(".o-mail-read-more-less:contains(Read Less)"); await click(".o-mail-Message"); - assert.containsOnce($, ".o-mail-read-more-less:contains(Read Less)"); + await contains(".o-mail-read-more-less:contains(Read Less)"); } ); -QUnit.test("read more/less links on message of type notification", async (assert) => { +QUnit.test("read more/less links on message of type notification", async () => { const pyEnv = await startServer(); const partnerId = pyEnv["res.partner"].create({}); pyEnv["mail.message"].create({ @@ -330,6 +303,6 @@ QUnit.test("read more/less links on message of type notification", async (assert res_id: partnerId, views: [[false, "form"]], }; - await openView(openViewAction); - assert.containsOnce($, ".o-mail-Message a:contains(Read More)"); + openView(openViewAction); + await contains(".o-mail-Message a:contains(Read More)"); }); diff --git a/addons/mrp/static/tests/mrp_document_kanban_tests.js b/addons/mrp/static/tests/mrp_document_kanban_tests.js index 80bae88b4c2..37ef87e568c 100644 --- a/addons/mrp/static/tests/mrp_document_kanban_tests.js +++ b/addons/mrp/static/tests/mrp_document_kanban_tests.js @@ -1,20 +1,16 @@ -/** @odoo-module **/ +/* @odoo-module */ -import testUtils from '@web/../tests/legacy/helpers/test_utils'; -import { registry } from "@web/core/registry"; -import { - getFixture, - nextTick, -} from '@web/../tests/helpers/utils'; -import { setupViewRegistries } from "@web/../tests/views/helpers"; -import { contains, start, startServer } from "@mail/../tests/helpers/test_utils"; +import { addModelNamesToFetch } from "@bus/../tests/helpers/model_definitions_helpers"; + +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; import { fileUploadService } from "@web/core/file_upload/file_upload_service"; +import { registry } from "@web/core/registry"; +import testUtils from "@web/../tests/legacy/helpers/test_utils"; +import { getFixture, nextTick } from "@web/../tests/helpers/utils"; +import { setupViewRegistries } from "@web/../tests/views/helpers"; -import { addModelNamesToFetch } from '@bus/../tests/helpers/model_definitions_helpers'; -addModelNamesToFetch([ - 'mrp.document', -]); +addModelNamesToFetch(["mrp.document"]); const serviceRegistry = registry.category("services"); @@ -223,9 +219,9 @@ QUnit.module('MrpDocumentsKanbanView', { res_model: "mrp.document", views: [[false, "kanban"]], }); - (await contains(".o_kanban_previewer")).click(); + await click(".o_kanban_previewer"); await contains(".o-FileViewer"); - (await contains(".o-FileViewer-headerButton .fa-times")).click(); + await click(".o-FileViewer-headerButton .fa-times"); await contains(".o-FileViewer", 0); }); }); diff --git a/addons/project_todo/static/tests/activity_menu_tests.js b/addons/project_todo/static/tests/activity_menu_tests.js index de481e6cf52..94a98fcbdb5 100644 --- a/addons/project_todo/static/tests/activity_menu_tests.js +++ b/addons/project_todo/static/tests/activity_menu_tests.js @@ -1,75 +1,76 @@ -/** @odoo-module **/ +/* @odoo-module */ -import { click, start } from "@mail/../tests/helpers/test_utils"; -import { getFixture, editInput, patchDate } from "@web/../tests/helpers/utils"; +import { click, contains, insertText, start } from "@mail/../tests/helpers/test_utils"; -let target; +import { editInput, patchDate } from "@web/../tests/helpers/utils"; -QUnit.module("todo activity menu", { - async beforeEach() { - target = getFixture(); - }, -}); - -QUnit.test("create todo from activity menu without date", async function (assert) { +QUnit.test("create todo from activity menu without date", async function () { await start(); - assert.containsOnce(target, ".o_menu_systray i[aria-label='Activities']"); - assert.containsNone(target, ".o-mail-ActivityMenu-counter"); + await contains(".o_menu_systray i[aria-label='Activities']"); + await contains(".o-mail-ActivityMenu-counter", 0); await click(".o_menu_systray i[aria-label='Activities']"); - assert.containsOnce( - target, + await contains( ".o-mail-ActivityMenu:contains(Congratulations, you're done with your activities.)" ); - assert.containsOnce(target, ".btn:contains(Add a To-do)"); await click(".btn:contains(Add a To-do)"); - assert.containsNone(target, ".btn:contains(Add a To-do)"); - assert.containsOnce(target, ".o-mail-ActivityMenu-show"); - await editInput(target, "input.o-mail-ActivityMenu-input", "New To-do"); + await contains(".btn:contains(Add a To-do)", 0); + await contains(".o-mail-ActivityMenu-show"); + await insertText("input.o-mail-ActivityMenu-input", "New To-do"); + await click(".btn:contains(SAVE)"); + await contains( + ".o_notification:contains(Your to-do has been successfully added to your tasks and scheduled for completion.)" + ); + // Need to reopen systray as it automatically closes when a todo is created + await click(".o_menu_systray i[aria-label='Activities']"); + await contains(".o-mail-ActivityMenu-counter:contains(1)"); + await contains(".o-mail-ActivityGroup"); + await contains(".o-mail-ActivityGroup:contains(project.task)"); + await contains(".btn:contains(1 Today)"); + await contains(".btn:contains(Add a To-do)"); + await contains(".o-mail-ActivityMenu-show", 0); + await contains(".o-mail-ActivityMenu-input", 0); + await click(".btn:contains(Add a To-do)"); + await contains(".btn:contains(Add a To-do)", 0); + await insertText("input.o-mail-ActivityMenu-input", "New To-do"); await click(".btn:contains(SAVE)"); // Need to reopen systray as it automatically closes when a todo is created - assert.containsOnce(target, ".o_menu_systray i[aria-label='Activities']"); + await contains( + ".o_notification:contains(Your to-do has been successfully added to your tasks and scheduled for completion.)", + 2 + ); await click(".o_menu_systray i[aria-label='Activities']"); - assert.containsOnce(target, ".o-mail-ActivityMenu-counter:contains(1)"); - assert.containsOnce(target, ".o-mail-ActivityGroup"); - assert.containsOnce(target, ".o-mail-ActivityGroup:contains(project.task)"); - assert.containsOnce(target, ".btn:contains(1 Today)"); - assert.containsOnce(target, ".btn:contains(Add a To-do)"); - assert.containsNone(target, ".o-mail-ActivityMenu-show"); - assert.containsNone(target, ".o-mail-ActivityMenu-input"); - await click(".btn:contains(Add a To-do)"); - assert.containsNone(target, ".btn:contains(Add a To-do)"); - await editInput(target, "input.o-mail-ActivityMenu-input", "New To-do"); - await click(".btn:contains(SAVE)"); - // Need to reopen systray as it automatically closes when a todo is created - assert.containsOnce(target, ".o_menu_systray i[aria-label='Activities']"); - await click(".o_menu_systray i[aria-label='Activities']"); - assert.containsOnce(target, ".o-mail-ActivityMenu-counter:contains(2)"); - assert.containsOnce(target, ".btn:contains(2 Today)"); + await contains(".o-mail-ActivityMenu-counter:contains(2)"); + await contains(".btn:contains(2 Today)"); }); -QUnit.test("create to-do from activity menu with date", async function (assert) { +QUnit.test("create to-do from activity menu with date", async function () { patchDate(2023, 1, 1, 6, 0, 0); const { DateTime } = luxon; const today = DateTime.utc(); const futureDay = today.plus({ days: 2 }); await start(); - assert.containsOnce(target, ".o_menu_systray i[aria-label='Activities']"); - assert.containsNone(target, ".o-mail-ActivityMenu-counter"); + await contains(".o_menu_systray i[aria-label='Activities']"); + await contains(".o-mail-ActivityMenu-counter", 0); await click(".o_menu_systray i[aria-label='Activities']"); await click(".btn:contains(Add a To-do)"); - await editInput(target, "input.o-mail-ActivityMenu-input", "New To-do"); + await insertText("input.o-mail-ActivityMenu-input", "New To-do"); await editInput( - target, + document.body, "input.o_datetime_input", - futureDay.toString(luxon.DateTime.DATE_SHORT) + futureDay.toString(luxon.DateTime.DATE_SHORT), + { + replace: true, + } ); await click(".btn:contains(SAVE)"); + await contains( + ".o_notification:contains(Your to-do has been successfully added to your tasks and scheduled for completion.)" + ); // Need to reopen systray as it automatically closes when a todo is created - assert.containsOnce(target, ".o_menu_systray i[aria-label='Activities']"); await click(".o_menu_systray i[aria-label='Activities']"); - assert.containsOnce(target, ".o-mail-ActivityMenu-counter:contains(1)"); - assert.containsOnce(target, ".o-mail-ActivityGroup"); - assert.containsOnce(target, ".o-mail-ActivityGroup:contains(project.task)"); - assert.containsOnce(target, ".btn:contains(1 Future)"); + await contains(".o-mail-ActivityMenu-counter:contains(1)"); + await contains(".o-mail-ActivityGroup"); + await contains(".o-mail-ActivityGroup:contains(project.task)"); + await contains(".btn:contains(1 Future)"); }); diff --git a/addons/sms/static/tests/messaging_menu/messaging_menu_patch_tests.js b/addons/sms/static/tests/messaging_menu/messaging_menu_patch_tests.js index 829d906c7db..d98f2f0426c 100644 --- a/addons/sms/static/tests/messaging_menu/messaging_menu_patch_tests.js +++ b/addons/sms/static/tests/messaging_menu/messaging_menu_patch_tests.js @@ -1,11 +1,12 @@ -/** @odoo-module **/ +/* @odoo-module */ + +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; -import { start, startServer, click } from "@mail/../tests/helpers/test_utils"; import { patchWithCleanup, triggerEvent } from "@web/../tests/helpers/utils"; QUnit.module("messaging menu (patch)"); -QUnit.test("mark as read", async (assert) => { +QUnit.test("mark as read", async () => { const pyEnv = await startServer(); const messageId = pyEnv["mail.message"].create({ message_type: "sms", @@ -20,15 +21,12 @@ QUnit.test("mark as read", async (assert) => { }); await start(); await click(".o_menu_systray i[aria-label='Messages']"); - assert.containsOnce($, ".o-mail-NotificationItem"); + await contains(".o-mail-NotificationItem"); await triggerEvent($(".o-mail-NotificationItem")[0], null, "mouseenter"); - assert.containsOnce($, ".o-mail-NotificationItem [title='Mark As Read']"); - assert.containsOnce( - $, - ".o-mail-NotificationItem:contains(An error occurred when sending an SMS)" - ); + await contains(".o-mail-NotificationItem [title='Mark As Read']"); + await contains(".o-mail-NotificationItem:contains(An error occurred when sending an SMS)"); await click(".o-mail-NotificationItem [title='Mark As Read']"); - assert.containsNone($, ".o-mail-NotificationItem"); + await contains(".o-mail-NotificationItem", 0); }); QUnit.test("notifications grouped by notification_type", async (assert) => { @@ -72,7 +70,7 @@ QUnit.test("notifications grouped by notification_type", async (assert) => { ]); await start(); await click(".o_menu_systray i[aria-label='Messages']"); - assert.containsN($, ".o-mail-NotificationItem", 2); + await contains(".o-mail-NotificationItem", 2); const items = $(".o-mail-NotificationItem"); assert.ok(items[0].textContent.includes("Partner")); assert.ok(items[0].textContent.includes("2")); // counter @@ -135,8 +133,8 @@ QUnit.test("grouped notifications by document model", async (assert) => { }); await click(".o_menu_systray i[aria-label='Messages']"); - assert.containsOnce($, ".o-mail-NotificationItem"); - assert.containsOnce($, ".o-mail-NotificationItem:contains(Partner) .badge:contains(2)"); + await contains(".o-mail-NotificationItem"); + await contains(".o-mail-NotificationItem:contains(Partner) .badge:contains(2)"); await click(".o-mail-NotificationItem"); assert.verifySteps(["do_action"]); }); diff --git a/addons/sms/static/tests/thread/message_patch_test.js b/addons/sms/static/tests/thread/message_patch_test.js index 20980cd95dd..8eb98670c17 100644 --- a/addons/sms/static/tests/thread/message_patch_test.js +++ b/addons/sms/static/tests/thread/message_patch_test.js @@ -1,6 +1,7 @@ -/** @odoo-module **/ +/* @odoo-module */ + +import { click, contains, startServer, start } from "@mail/../tests/helpers/test_utils"; -import { startServer, start, click } from "@mail/../tests/helpers/test_utils"; import { makeDeferred, patchWithCleanup } from "@web/../tests/helpers/utils"; QUnit.module("message (patch)"); @@ -21,17 +22,17 @@ QUnit.test("Notification Sent", async (assert) => { res_partner_id: partnerId, }); const { openFormView } = await start(); - await openFormView("res.partner", partnerId); - assert.containsOnce($, ".o-mail-Message"); - assert.containsOnce($, ".o-mail-Message-notification"); - assert.containsOnce($, ".o-mail-Message-notification i"); + openFormView("res.partner", partnerId); + await contains(".o-mail-Message"); + await contains(".o-mail-Message-notification"); + await contains(".o-mail-Message-notification i"); assert.hasClass($(".o-mail-Message-notification i"), "fa-mobile"); await click(".o-mail-Message-notification"); - assert.containsOnce($, ".o-mail-MessageNotificationPopover"); - assert.containsOnce($, ".o-mail-MessageNotificationPopover i"); + await contains(".o-mail-MessageNotificationPopover"); + await contains(".o-mail-MessageNotificationPopover i"); assert.hasClass($(".o-mail-MessageNotificationPopover i"), "fa-check"); - assert.containsOnce($, ".o-mail-MessageNotificationPopover:contains(Someone)"); + await contains(".o-mail-MessageNotificationPopover:contains(Someone)"); }); QUnit.test("Notification Error", async (assert) => { @@ -51,7 +52,7 @@ QUnit.test("Notification Error", async (assert) => { res_partner_id: partnerId, }); const { env, openFormView } = await start(); - await openFormView("res.partner", partnerId); + openFormView("res.partner", partnerId); patchWithCleanup(env.services.action, { doAction(action, options) { assert.step("do_action"); @@ -61,11 +62,11 @@ QUnit.test("Notification Error", async (assert) => { }, }); - assert.containsOnce($, ".o-mail-Message"); - assert.containsOnce($, ".o-mail-Message-notification"); - assert.containsOnce($, ".o-mail-Message-notification i"); + await contains(".o-mail-Message"); + await contains(".o-mail-Message-notification"); + await contains(".o-mail-Message-notification i"); assert.hasClass($(".o-mail-Message-notification i"), "fa-mobile"); - click(".o-mail-Message-notification").catch(() => {}); + await click(".o-mail-Message-notification"); await openResendActionDef; assert.verifySteps(["do_action"]); }); diff --git a/addons/snailmail/static/tests/message/message_patch_tests.js b/addons/snailmail/static/tests/message/message_patch_tests.js index 79b9c23a052..ff9a3b4d8fc 100644 --- a/addons/snailmail/static/tests/message/message_patch_tests.js +++ b/addons/snailmail/static/tests/message/message_patch_tests.js @@ -1,6 +1,7 @@ -/** @odoo-module **/ +/* @odoo-module */ + +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; -import { start, startServer, click } from "@mail/../tests/helpers/test_utils"; import { makeDeferred, patchWithCleanup } from "@web/../tests/helpers/utils"; QUnit.module("message (patch)"); @@ -24,15 +25,15 @@ QUnit.test("Sent", async (assert) => { res_partner_id: partnerId, }); const { openFormView } = await start(); - await openFormView("res.partner", partnerId); - assert.containsOnce($, ".o-mail-Message"); - assert.containsOnce($, ".o-mail-Message-notification"); - assert.containsOnce($, ".o-mail-Message-notification i"); + openFormView("res.partner", partnerId); + await contains(".o-mail-Message"); + await contains(".o-mail-Message-notification"); + await contains(".o-mail-Message-notification i"); assert.hasClass($(".o-mail-Message-notification i"), "fa-paper-plane"); await click(".o-mail-Message-notification"); - assert.containsOnce($, ".o-snailmail-SnailmailNotificationPopover"); - assert.containsOnce($, ".o-snailmail-SnailmailNotificationPopover i"); + await contains(".o-snailmail-SnailmailNotificationPopover"); + await contains(".o-snailmail-SnailmailNotificationPopover i"); assert.hasClass($(".o-snailmail-SnailmailNotificationPopover i"), "fa-check"); assert.strictEqual($(".o-snailmail-SnailmailNotificationPopover").text(), "Sent"); }); @@ -56,15 +57,15 @@ QUnit.test("Canceled", async (assert) => { res_partner_id: partnerId, }); const { openFormView } = await start(); - await openFormView("res.partner", partnerId); - assert.containsOnce($, ".o-mail-Message"); - assert.containsOnce($, ".o-mail-Message-notification"); - assert.containsOnce($, ".o-mail-Message-notification i"); + openFormView("res.partner", partnerId); + await contains(".o-mail-Message"); + await contains(".o-mail-Message-notification"); + await contains(".o-mail-Message-notification i"); assert.hasClass($(".o-mail-Message-notification i"), "fa-paper-plane"); await click(".o-mail-Message-notification"); - assert.containsOnce($, ".o-snailmail-SnailmailNotificationPopover"); - assert.containsOnce($, ".o-snailmail-SnailmailNotificationPopover i"); + await contains(".o-snailmail-SnailmailNotificationPopover"); + await contains(".o-snailmail-SnailmailNotificationPopover i"); assert.hasClass($(".o-snailmail-SnailmailNotificationPopover i"), "fa-trash-o"); assert.strictEqual($(".o-snailmail-SnailmailNotificationPopover").text(), "Canceled"); }); @@ -88,15 +89,15 @@ QUnit.test("Pending", async (assert) => { res_partner_id: partnerId, }); const { openFormView } = await start(); - await openFormView("res.partner", partnerId); - assert.containsOnce($, ".o-mail-Message"); - assert.containsOnce($, ".o-mail-Message-notification"); - assert.containsOnce($, ".o-mail-Message-notification i"); + openFormView("res.partner", partnerId); + await contains(".o-mail-Message"); + await contains(".o-mail-Message-notification"); + await contains(".o-mail-Message-notification i"); assert.hasClass($(".o-mail-Message-notification i"), "fa-paper-plane"); await click(".o-mail-Message-notification"); - assert.containsOnce($, ".o-snailmail-SnailmailNotificationPopover"); - assert.containsOnce($, ".o-snailmail-SnailmailNotificationPopover i"); + await contains(".o-snailmail-SnailmailNotificationPopover"); + await contains(".o-snailmail-SnailmailNotificationPopover i"); assert.hasClass($(".o-snailmail-SnailmailNotificationPopover i"), "fa-clock-o"); assert.strictEqual($(".o-snailmail-SnailmailNotificationPopover").text(), "Awaiting Dispatch"); }); @@ -131,21 +132,21 @@ QUnit.test("No Price Available", async (assert) => { } }, }); - await openFormView("res.partner", partnerId); - assert.containsOnce($, ".o-mail-Message"); - assert.containsOnce($, ".o-mail-Message-notification"); - assert.containsOnce($, ".o-mail-Message-notification i"); + openFormView("res.partner", partnerId); + await contains(".o-mail-Message"); + await contains(".o-mail-Message-notification"); + await contains(".o-mail-Message-notification i"); assert.hasClass($(".o-mail-Message-notification i"), "fa-paper-plane"); await click(".o-mail-Message-notification"); - assert.containsOnce($, ".o-snailmail-SnailmailError"); + await contains(".o-snailmail-SnailmailError"); assert.strictEqual( $(".o-snailmail-SnailmailError .modal-body").text().trim(), "The country to which you want to send the letter is not supported by our service." ); - assert.containsOnce($, "button:contains(Cancel letter)"); + await contains("button:contains(Cancel letter)"); await click("button:contains(Cancel letter)"); - assert.containsNone($, ".o-snailmail-SnailmailError"); + await contains(".o-snailmail-SnailmailError", 0); assert.verifySteps(["cancel_letter"]); }); @@ -179,22 +180,22 @@ QUnit.test("Credit Error", async (assert) => { } }, }); - await openFormView("res.partner", partnerId); - assert.containsOnce($, ".o-mail-Message"); - assert.containsOnce($, ".o-mail-Message-notification"); - assert.containsOnce($, ".o-mail-Message-notification i"); + openFormView("res.partner", partnerId); + await contains(".o-mail-Message"); + await contains(".o-mail-Message-notification"); + await contains(".o-mail-Message-notification i"); assert.hasClass($(".o-mail-Message-notification i"), "fa-paper-plane"); await click(".o-mail-Message-notification"); - assert.containsOnce($, ".o-snailmail-SnailmailError"); + await contains(".o-snailmail-SnailmailError"); assert.strictEqual( $(".o-snailmail-SnailmailError p").text().trim(), "The letter could not be sent due to insufficient credits on your IAP account." ); - assert.containsOnce($, "button:contains(Re-send letter)"); - assert.containsOnce($, "button:contains(Cancel letter)"); + await contains("button:contains(Re-send letter)"); + await contains("button:contains(Cancel letter)"); await click("button:contains(Re-send letter)"); - assert.containsNone($, ".o-snailmail-SnailmailError"); + await contains(".o-snailmail-SnailmailError", 0); assert.verifySteps(["send_letter"]); }); @@ -228,22 +229,22 @@ QUnit.test("Trial Error", async (assert) => { } }, }); - await openFormView("res.partner", partnerId); - assert.containsOnce($, ".o-mail-Message"); - assert.containsOnce($, ".o-mail-Message-notification"); - assert.containsOnce($, ".o-mail-Message-notification i"); + openFormView("res.partner", partnerId); + await contains(".o-mail-Message"); + await contains(".o-mail-Message-notification"); + await contains(".o-mail-Message-notification i"); assert.hasClass($(".o-mail-Message-notification i"), "fa-paper-plane"); await click(".o-mail-Message-notification"); - assert.containsOnce($, ".o-snailmail-SnailmailError"); + await contains(".o-snailmail-SnailmailError"); assert.strictEqual( $(".o-snailmail-SnailmailError p").text().trim(), "You need credits on your IAP account to send a letter." ); - assert.containsOnce($, "button:contains(Re-send letter)"); - assert.containsOnce($, "button:contains(Cancel letter)"); + await contains("button:contains(Re-send letter)"); + await contains("button:contains(Cancel letter)"); await click("button:contains(Re-send letter)"); - assert.containsNone($, ".o-snailmail-SnailmailError"); + await contains(".o-snailmail-SnailmailError", 0); assert.verifySteps(["send_letter"]); }); @@ -268,7 +269,7 @@ QUnit.test("Format Error", async (assert) => { res_partner_id: partnerId, }); const { env, openFormView } = await start(); - await openFormView("res.partner", partnerId); + openFormView("res.partner", partnerId); patchWithCleanup(env.services.action, { doAction(action, options) { assert.step("do_action"); @@ -277,9 +278,9 @@ QUnit.test("Format Error", async (assert) => { openFormatErrorActionDef.resolve(); }, }); - assert.containsOnce($, ".o-mail-Message"); - assert.containsOnce($, ".o-mail-Message-notification"); - assert.containsOnce($, ".o-mail-Message-notification i"); + await contains(".o-mail-Message"); + await contains(".o-mail-Message-notification"); + await contains(".o-mail-Message-notification i"); assert.hasClass($(".o-mail-Message-notification i"), "fa-paper-plane"); click(".o-mail-Message-notification").then(() => {}); @@ -307,7 +308,7 @@ QUnit.test("Missing Required Fields", async (assert) => { message_id: messageId, }); const { env, openFormView } = await start(); - await openFormView("res.partner", partnerId); + openFormView("res.partner", partnerId); patchWithCleanup(env.services.action, { doAction(action, options) { assert.step("do_action"); @@ -316,9 +317,9 @@ QUnit.test("Missing Required Fields", async (assert) => { openRequiredFieldsActionDef.resolve(); }, }); - assert.containsOnce($, ".o-mail-Message"); - assert.containsOnce($, ".o-mail-Message-notification"); - assert.containsOnce($, ".o-mail-Message-notification i"); + await contains(".o-mail-Message"); + await contains(".o-mail-Message-notification"); + await contains(".o-mail-Message-notification i"); assert.hasClass($(".o-mail-Message-notification i"), "fa-paper-plane"); click(".o-mail-Message-notification").then(() => {}); diff --git a/addons/snailmail/static/tests/messaging_menu/messaging_menu_patch_tests.js b/addons/snailmail/static/tests/messaging_menu/messaging_menu_patch_tests.js index 18e267bbadc..b8cb8a89511 100644 --- a/addons/snailmail/static/tests/messaging_menu/messaging_menu_patch_tests.js +++ b/addons/snailmail/static/tests/messaging_menu/messaging_menu_patch_tests.js @@ -1,11 +1,12 @@ -/** @odoo-module **/ +/* @odoo-module */ + +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; -import { start, startServer, click } from "@mail/../tests/helpers/test_utils"; import { patchWithCleanup, triggerEvent } from "@web/../tests/helpers/utils"; QUnit.module("messaging menu (patch)"); -QUnit.test("mark as read", async (assert) => { +QUnit.test("mark as read", async () => { const pyEnv = await startServer(); const messageId = pyEnv["mail.message"].create([ { @@ -22,15 +23,14 @@ QUnit.test("mark as read", async (assert) => { }); await start(); await click(".o_menu_systray i[aria-label='Messages']"); - assert.containsOnce($, ".o-mail-NotificationItem"); + await contains(".o-mail-NotificationItem"); await triggerEvent($(".o-mail-NotificationItem")[0], null, "mouseenter"); - assert.containsOnce($, ".o-mail-NotificationItem [title='Mark As Read']"); - assert.containsOnce( - $, + await contains(".o-mail-NotificationItem [title='Mark As Read']"); + await contains( ".o-mail-NotificationItem:contains(An error occurred when sending a letter with Snailmail.)" ); await click(".o-mail-NotificationItem [title='Mark As Read']"); - assert.containsNone($, ".o-mail-NotificationItem"); + await contains(".o-mail-NotificationItem", 0); }); QUnit.test("notifications grouped by notification_type", async (assert) => { @@ -74,7 +74,7 @@ QUnit.test("notifications grouped by notification_type", async (assert) => { ]); await start(); await click(".o_menu_systray i[aria-label='Messages']"); - assert.containsN($, ".o-mail-NotificationItem", 2); + await contains(".o-mail-NotificationItem", 2); assert.ok($(".o-mail-NotificationItem:eq(0)").text().includes("Partner")); assert.ok($(".o-mail-NotificationItem:eq(0)").text().includes("2")); // counter assert.ok( @@ -144,9 +144,9 @@ QUnit.test("grouped notifications by document model", async (assert) => { }, }); await click(".o_menu_systray i[aria-label='Messages']"); - assert.containsOnce($, ".o-mail-NotificationItem"); - assert.containsOnce($, ".o-mail-NotificationItem:contains(Partner)"); - assert.containsOnce($, ".o-mail-NotificationItem:contains(2)"); // counter + await contains(".o-mail-NotificationItem"); + await contains(".o-mail-NotificationItem:contains(Partner)"); + await contains(".o-mail-NotificationItem:contains(2)"); // counter await click(".o-mail-NotificationItem"); assert.verifySteps(["do_action"]); }); diff --git a/addons/test_mail/static/tests/properties_field_tests.js b/addons/test_mail/static/tests/properties_field_tests.js index 7a28e3d7f67..0851707cd5d 100644 --- a/addons/test_mail/static/tests/properties_field_tests.js +++ b/addons/test_mail/static/tests/properties_field_tests.js @@ -1,6 +1,6 @@ -/** @odoo-module **/ +/* @odoo-module */ -import { start, startServer, click } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; QUnit.module("properties field"); @@ -63,7 +63,7 @@ async function testPropertyFieldAvatarOpenChat(assert, propertyType) { ); assert.verifySteps(["read res.users"]); - const chatter = document.querySelectorAll(".o-mail-ChatWindow-name"); + const chatter = await contains(".o-mail-ChatWindow-name"); assert.strictEqual(chatter.length, 1); assert.strictEqual(chatter[0].innerText, "Partner Test"); } 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 f5c75931a56..fa9c6dd630b 100644 --- a/addons/test_mail/static/tests/systray_activity_menu_tests.js +++ b/addons/test_mail/static/tests/systray_activity_menu_tests.js @@ -1,14 +1,14 @@ -/** @odoo-module **/ +/* @odoo-module */ -import { start, startServer, click } from "@mail/../tests/helpers/test_utils"; +import { click, contains, start, startServer } from "@mail/../tests/helpers/test_utils"; -import { session } from "@web/session"; import { date_to_str } from "@web/legacy/js/core/time"; +import { session } from "@web/session"; import { patchWithCleanup } from "@web/../tests/helpers/utils"; QUnit.module("activity menu"); -QUnit.test("menu with no records", async (assert) => { +QUnit.test("menu with no records", async () => { await start({ async mockRPC(route, args) { if (args.method === "systray_get_activities") { @@ -17,13 +17,12 @@ QUnit.test("menu with no records", async (assert) => { }, }); await click(".o_menu_systray .dropdown-toggle:has(i[aria-label='Activities'])"); - assert.containsOnce( - $, + await contains( ".o-mail-ActivityMenu:contains(Congratulations, you're done with your activities.)" ); }); -QUnit.test("do not show empty text when at least some future activities", async (assert) => { +QUnit.test("do not show empty text when at least some future activities", async () => { const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); const pyEnv = await startServer(); @@ -37,9 +36,9 @@ QUnit.test("do not show empty text when at least some future activities", async ]); await start(); await click(".o_menu_systray .dropdown-toggle:has(i[aria-label='Activities'])"); - assert.containsNone( - $, - ".o-mail-ActivityMenu:contains(Congratulations, you're done with your activities.)" + await contains( + ".o-mail-ActivityMenu:contains(Congratulations, you're done with your activities.)", + 0 ); }); @@ -71,9 +70,9 @@ QUnit.test("activity menu widget: activity menu with 2 models", async (assert) = }, ]); const { env } = await start(); - assert.containsOnce($, ".o_menu_systray i[aria-label='Activities']"); - assert.containsOnce($, ".o-mail-ActivityMenu-counter"); - assert.containsOnce($, ".o-mail-ActivityMenu-counter:contains(5)"); + await contains(".o_menu_systray i[aria-label='Activities']"); + await contains(".o-mail-ActivityMenu-counter"); + await contains(".o-mail-ActivityMenu-counter:contains(5)"); let context = {}; patchWithCleanup(env.services.action, { doAction(action) { @@ -85,22 +84,24 @@ QUnit.test("activity menu widget: activity menu with 2 models", async (assert) = search_default_activities_overdue: 1, }; await click(".o_menu_systray i[aria-label='Activities']"); - assert.containsOnce($, ".o-mail-ActivityMenu"); - assert.containsN($, ".o-mail-ActivityMenu .o-mail-ActivityGroup", 2); + await contains(".o-mail-ActivityMenu"); + await contains(".o-mail-ActivityMenu .o-mail-ActivityGroup", 2); await click(".o-mail-ActivityMenu .o-mail-ActivityGroup button:contains('Late')"); - assert.containsNone($, ".o-mail-ActivityMenu"); + await contains(".o-mail-ActivityMenu", 0); context = { force_search_count: 1, search_default_activities_today: 1, }; await click(".o_menu_systray .dropdown-toggle:has(i[aria-label='Activities'])"); - await click(".o-mail-ActivityMenu .o-mail-ActivityGroup button:contains('Today')"); + await click(".o-mail-ActivityMenu .o-mail-ActivityGroup button:contains('Today'):eq(0)"); + await contains(".o-mail-ActivityMenu", 0); context = { force_search_count: 1, search_default_activities_upcoming_all: 1, }; await click(".o_menu_systray i[aria-label='Activities']"); await click(".o-mail-ActivityMenu .o-mail-ActivityGroup button:contains('Future')"); + await contains(".o-mail-ActivityMenu", 0); context = { force_search_count: 1, search_default_activities_overdue: 1, @@ -108,6 +109,7 @@ QUnit.test("activity menu widget: activity menu with 2 models", async (assert) = }; await click(".o_menu_systray i[aria-label='Activities']"); await click(".o-mail-ActivityMenu .o-mail-ActivityGroup:contains('mail.test.activity')"); + await contains(".o-mail-ActivityMenu", 0); }); QUnit.test("activity menu widget: activity view icon", async (assert) => { @@ -139,7 +141,7 @@ QUnit.test("activity menu widget: activity view icon", async (assert) => { ]); const { env } = await start(); await click(".o_menu_systray i[aria-label='Activities']"); - assert.containsN($, "button[title='Summary']", 2); + await contains("button[title='Summary']", 2); const first = $(".o-mail-ActivityGroup:contains('res.partner') button[title='Summary']"); const second = $( ".o-mail-ActivityGroup:contains('mail.test.activity') button[title='Summary']" @@ -161,7 +163,7 @@ QUnit.test("activity menu widget: activity view icon", async (assert) => { }, }); await click(".o-mail-ActivityGroup:contains('mail.test.activity') button[title='Summary']"); - assert.containsNone($, ".o-dropdown-menu"); + await contains(".o-dropdown-menu", 0); await click(".o_menu_systray i[aria-label='Activities']"); await click(".o-mail-ActivityGroup:contains('res.partner') button[title='Summary']"); assert.verifySteps(["do_action:mail.test.activity", "do_action:res.partner"]); @@ -170,7 +172,7 @@ QUnit.test("activity menu widget: activity view icon", async (assert) => { QUnit.test("activity menu widget: close on messaging menu click", async (assert) => { await start(); await click(".o_menu_systray i[aria-label='Activities']"); - assert.containsOnce($, ".o-mail-ActivityMenu"); + await contains(".o-mail-ActivityMenu"); await click(".o_menu_systray i[aria-label='Messages']"); - assert.containsNone($, ".o-mail-ActivityMenu"); + await contains(".o-mail-ActivityMenu", 0); }); diff --git a/addons/test_mail/static/tests/tracking_value_tests.js b/addons/test_mail/static/tests/tracking_value_tests.js index fb91b25092c..1d45c9123df 100644 --- a/addons/test_mail/static/tests/tracking_value_tests.js +++ b/addons/test_mail/static/tests/tracking_value_tests.js @@ -1,16 +1,14 @@ -/** @odoo-module **/ +/* @odoo-module */ -import { click, start, startServer } from "@mail/../tests/helpers/test_utils"; +import { click, contains, insertText, start, startServer } from "@mail/../tests/helpers/test_utils"; import { - editInput, editSelect, selectDropdownItem, patchWithCleanup, patchTimeZone, getFixture, } from "@web/../tests/helpers/utils"; - import session from "web.session"; import testUtils from "@web/../tests/legacy/helpers/test_utils"; @@ -56,172 +54,139 @@ QUnit.module("tracking value", { }, }); -QUnit.test("basic rendering of tracking value (float type)", async function (assert) { +QUnit.test("basic rendering of tracking value (float type)", async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ float_field: 12.3 }); await this.start({ res_id: mailTestTrackAllId1 }); - await editInput(target, "div[name=float_field] input", 45.67); + await insertText("div[name=float_field] input", "45.67", { replace: true }); await click(".o_form_button_save"); - assert.containsOnce(target, ".o-mail-Message-tracking"); - assert.containsOnce(target, ".o-mail-Message-trackingField"); - assert.strictEqual( - target.querySelector(".o-mail-Message-trackingField").textContent, - "(Float)" - ); - assert.containsOnce(target, ".o-mail-Message-trackingOld"); - assert.strictEqual(target.querySelector(".o-mail-Message-trackingOld").textContent, "12.30"); - assert.containsOnce(target, ".o-mail-Message-trackingSeparator"); - assert.containsOnce(target, ".o-mail-Message-trackingNew"); - assert.strictEqual(target.querySelector(".o-mail-Message-trackingNew").textContent, "45.67"); + await contains(".o-mail-Message-tracking"); + await contains(".o-mail-Message-trackingField"); + await contains(".o-mail-Message-trackingField:contains('(Float)')"); + await contains(".o-mail-Message-trackingOld"); + await contains(".o-mail-Message-trackingOld:contains('12.30')"); + await contains(".o-mail-Message-trackingSeparator"); + await contains(".o-mail-Message-trackingNew"); + await contains(".o-mail-Message-trackingNew:contains('45.67')"); }); -QUnit.test("rendering of tracked field of type float: from non-0 to 0", async function (assert) { +QUnit.test("rendering of tracked field of type float: from non-0 to 0", async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ float_field: 1, }); await this.start({ res_id: mailTestTrackAllId1 }); - await editInput(target, "div[name=float_field] input", 0); + await insertText("div[name=float_field] input", "0", { replace: true }); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "1.000.00(Float)" - ); + await contains(".o-mail-Message-tracking:contains('1.000.00(Float)')"); }); -QUnit.test("rendering of tracked field of type float: from 0 to non-0", async function (assert) { +QUnit.test("rendering of tracked field of type float: from 0 to non-0", async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ float_field: 0, }); await this.start({ res_id: mailTestTrackAllId1 }); - await editInput(target, "div[name=float_field] input", 1); + await insertText("div[name=float_field] input", "1", { replace: true }); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "0.001.00(Float)" - ); + await contains(".o-mail-Message-tracking:contains('0.001.00(Float)')"); }); -QUnit.test("rendering of tracked field of type integer: from non-0 to 0", async function (assert) { +QUnit.test("rendering of tracked field of type integer: from non-0 to 0", async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ integer_field: 1, }); await this.start({ res_id: mailTestTrackAllId1 }); - await editInput(target, "div[name=integer_field] input", 0); + await insertText("div[name=integer_field] input", "0", { replace: true }); await click(".o_form_button_save"); - assert.strictEqual(target.querySelector(".o-mail-Message-tracking").textContent, "10(Integer)"); + await contains(".o-mail-Message-tracking:contains('10(Integer)')"); }); -QUnit.test("rendering of tracked field of type integer: from 0 to non-0", async function (assert) { +QUnit.test("rendering of tracked field of type integer: from 0 to non-0", async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ integer_field: 0, }); await this.start({ res_id: mailTestTrackAllId1 }); - await editInput(target, "div[name=integer_field] input", 1); + await insertText("div[name=integer_field] input", "1", { replace: true }); await click(".o_form_button_save"); - assert.strictEqual(target.querySelector(".o-mail-Message-tracking").textContent, "01(Integer)"); + await contains(".o-mail-Message-tracking:contains('01(Integer)')"); }); -QUnit.test("rendering of tracked field of type monetary: from non-0 to 0", async function (assert) { +QUnit.test("rendering of tracked field of type monetary: from non-0 to 0", async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ monetary_field: 1, }); await this.start({ res_id: mailTestTrackAllId1 }); - await editInput(target, "div[name=monetary_field] input", 0); + await insertText("div[name=monetary_field] input", "0", { replace: true }); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "1.000.00(Monetary)" - ); + await contains(".o-mail-Message-tracking:contains('1.000.00(Monetary)')"); }); -QUnit.test("rendering of tracked field of type monetary: from 0 to non-0", async function (assert) { +QUnit.test("rendering of tracked field of type monetary: from 0 to non-0", async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ monetary_field: 0, }); await this.start({ res_id: mailTestTrackAllId1 }); - await editInput(target, "div[name=monetary_field] input", 1); + await insertText("div[name=monetary_field] input", "1", { replace: true }); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "0.001.00(Monetary)" - ); + await contains(".o-mail-Message-tracking:contains('0.001.00(Monetary)')"); +}); + +QUnit.test("rendering of tracked field of type boolean: from true to false", async function () { + const pyEnv = await startServer(); + const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ + boolean_field: true, + }); + await this.start({ res_id: mailTestTrackAllId1 }); + click(".o_field_boolean input").catch(() => {}); + await click(".o_form_button_save"); + await contains(".o-mail-Message-tracking:contains('YesNo(Boolean)')"); +}); + +QUnit.test("rendering of tracked field of type boolean: from false to true", async function () { + const pyEnv = await startServer(); + const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({}); + await this.start({ res_id: mailTestTrackAllId1 }); + click(".o_field_boolean input").catch(() => {}); + await click(".o_form_button_save"); + await contains(".o-mail-Message-tracking:contains('NoYes(Boolean)')"); }); -QUnit.test( - "rendering of tracked field of type boolean: from true to false", - async function (assert) { - const pyEnv = await startServer(); - const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ - boolean_field: true, - }); - await this.start({ res_id: mailTestTrackAllId1 }); - click(".o_field_boolean input").catch(() => {}); - await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "YesNo(Boolean)" - ); - } -); - -QUnit.test( - "rendering of tracked field of type boolean: from false to true", - async function (assert) { - const pyEnv = await startServer(); - const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({}); - await this.start({ res_id: mailTestTrackAllId1 }); - click(".o_field_boolean input").catch(() => {}); - await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "NoYes(Boolean)" - ); - } -); - QUnit.test( "rendering of tracked field of type char: from a string to empty string", - async function (assert) { + async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ char_field: "Marc", }); await this.start({ res_id: mailTestTrackAllId1 }); - await editInput(target, "div[name=char_field] input", ""); + await insertText("div[name=char_field] input", "", { replace: true }); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "MarcNone(Char)" - ); + await contains(".o-mail-Message-tracking:contains('MarcNone(Char)')"); } ); QUnit.test( "rendering of tracked field of type char: from empty string to a string", - async function (assert) { + async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ char_field: "", }); await this.start({ res_id: mailTestTrackAllId1 }); - await editInput(target, "div[name=char_field] input", "Marc"); + await insertText("div[name=char_field] input", "Marc", { replace: true }); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "NoneMarc(Char)" - ); + await contains(".o-mail-Message-tracking:contains('NoneMarc(Char)')"); } ); QUnit.test( "rendering of tracked field of type date: from no date to a set date", - async function (assert) { + async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ date_field: false, @@ -233,16 +198,13 @@ QUnit.test( ["change"] ); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "None12/14/2018(Date)" - ); + await contains(".o-mail-Message-tracking:contains('None12/14/2018(Date)')"); } ); QUnit.test( "rendering of tracked field of type date: from a set date to no date", - async function (assert) { + async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ date_field: "2018-12-14", @@ -254,10 +216,7 @@ QUnit.test( ["change"] ); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "12/14/2018None(Date)" - ); + await contains(".o-mail-Message-tracking:contains('12/14/2018None(Date)')"); } ); @@ -276,20 +235,17 @@ QUnit.test( ["change"] ); await click(".o_form_button_save"); + await contains(".o-mail-Message-tracking:contains('None12/14/2018 13:42:28(Datetime)')"); const savedRecord = pyEnv .getData() ["mail.test.track.all"].records.find(({ id }) => id === mailTestTrackAllId1); assert.strictEqual(savedRecord.datetime_field, "2018-12-14 10:42:28"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "None12/14/2018 13:42:28(Datetime)" - ); } ); QUnit.test( "rendering of tracked field of type datetime: from a set date and time to no date and time", - async function (assert) { + async function () { patchTimeZone(180); const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ @@ -302,50 +258,35 @@ QUnit.test( ["change"] ); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "12/14/2018 16:42:28None(Datetime)" - ); + await contains(".o-mail-Message-tracking:contains('12/14/2018 16:42:28None(Datetime)')"); } ); -QUnit.test( - "rendering of tracked field of type text: from some text to empty", - async function (assert) { - const pyEnv = await startServer(); - const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ - text_field: "Marc", - }); - await this.start({ res_id: mailTestTrackAllId1 }); - await editInput(target, "div[name=text_field] textarea", ""); - await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "MarcNone(Text)" - ); - } -); +QUnit.test("rendering of tracked field of type text: from some text to empty", async function () { + const pyEnv = await startServer(); + const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ + text_field: "Marc", + }); + await this.start({ res_id: mailTestTrackAllId1 }); + await insertText("div[name=text_field] textarea", "", { replace: true }); + await click(".o_form_button_save"); + await contains(".o-mail-Message-tracking:contains('MarcNone(Text)')"); +}); -QUnit.test( - "rendering of tracked field of type text: from empty to some text", - async function (assert) { - const pyEnv = await startServer(); - const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ - text_field: "", - }); - await this.start({ res_id: mailTestTrackAllId1 }); - await editInput(target, "div[name=text_field] textarea", "Marc"); - await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "NoneMarc(Text)" - ); - } -); +QUnit.test("rendering of tracked field of type text: from empty to some text", async function () { + const pyEnv = await startServer(); + const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ + text_field: "", + }); + await this.start({ res_id: mailTestTrackAllId1 }); + await insertText("div[name=text_field] textarea", "Marc", { replace: true }); + await click(".o_form_button_save"); + await contains(".o-mail-Message-tracking:contains('NoneMarc(Text)')"); +}); QUnit.test( "rendering of tracked field of type selection: from a selection to no selection", - async function (assert) { + async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ selection_field: "first", @@ -353,58 +294,46 @@ QUnit.test( await this.start({ res_id: mailTestTrackAllId1 }); await editSelect(target, "div[name=selection_field] select", false); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "firstNone(Selection)" - ); + await contains(".o-mail-Message-tracking:contains('firstNone(Selection)')"); } ); QUnit.test( "rendering of tracked field of type selection: from no selection to a selection", - async function (assert) { + async function () { const pyEnv = await startServer(); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({}); await this.start({ res_id: mailTestTrackAllId1 }); await editSelect(target, "div[name=selection_field] select", '"first"'); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "Nonefirst(Selection)" - ); + await contains(".o-mail-Message-tracking:contains('Nonefirst(Selection)')"); } ); QUnit.test( "rendering of tracked field of type many2one: from having a related record to no related record", - async function (assert) { + async function () { const pyEnv = await startServer(); const resPartnerId1 = pyEnv["res.partner"].create({ display_name: "Marc" }); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({ many2one_field_id: resPartnerId1, }); await this.start({ res_id: mailTestTrackAllId1 }); - await editInput(target, ".o_field_many2one_selection input", ""); + await insertText(".o_field_many2one_selection input", "", { replace: true }); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "MarcNone(Many2one)" - ); + await contains(".o-mail-Message-tracking:contains('MarcNone(Many2one)')"); } ); QUnit.test( "rendering of tracked field of type many2one: from no related record to having a related record", - async function (assert) { + async function () { const pyEnv = await startServer(); pyEnv["res.partner"].create({ display_name: "Marc" }); const mailTestTrackAllId1 = pyEnv["mail.test.track.all"].create({}); await this.start({ res_id: mailTestTrackAllId1 }); await selectDropdownItem(target, "many2one_field_id", "Marc"); await click(".o_form_button_save"); - assert.strictEqual( - target.querySelector(".o-mail-Message-tracking").textContent, - "NoneMarc(Many2one)" - ); + await contains(".o-mail-Message-tracking:contains('NoneMarc(Many2one)')"); } ); diff --git a/addons/web/static/src/core/emoji_picker/emoji_picker.js b/addons/web/static/src/core/emoji_picker/emoji_picker.js index fd527ca8555..aaeddd1b0e1 100644 --- a/addons/web/static/src/core/emoji_picker/emoji_picker.js +++ b/addons/web/static/src/core/emoji_picker/emoji_picker.js @@ -6,6 +6,7 @@ import { Component, onMounted, onPatched, + onWillDestroy, onWillPatch, onWillStart, onWillUnmount, @@ -128,7 +129,6 @@ export class EmojiPicker extends Component { static props = ["onSelect", "className?", "close?", "onClose?", "storeScroll?"]; static template = "web.EmojiPicker"; - recent = []; categories = null; emojis = null; shouldScrollElem = null; @@ -140,8 +140,20 @@ export class EmojiPicker extends Component { this.state = useState({ activeEmojiIndex: 0, categoryId: null, + recent: JSON.parse(browser.localStorage.getItem("web.emoji.frequent") || "{}"), searchStr: "", }); + const onStorage = (ev) => { + if (ev.key === "web.emoji.frequent") { + this.state.recent = ev.newValue ? JSON.parse(ev.newValue) : {}; + } else if (ev.key === null) { + this.state.recent = {}; + } + }; + browser.addEventListener("storage", onStorage); + onWillDestroy(() => { + browser.removeEventListener("storage", onStorage); + }); onWillStart(async () => { const { categories, emojis } = await loadEmoji(); this.categories = categories; @@ -150,7 +162,6 @@ export class EmojiPicker extends Component { this.emojis.map((emoji) => [emoji.codepoints, emoji]) ); this.state.categoryId = this.categories[0]?.sortId; - this.recent = JSON.parse(browser.localStorage.getItem("web.emoji.frequent") || "{}"); this.recentCategory = { name: "Frequently used", displayName: _t("Frequently used"), @@ -211,7 +222,7 @@ export class EmojiPicker extends Component { } get recentEmojis() { - return Object.entries(this.recent) + return Object.entries(this.state.recent) .sort(([, usage_1], [, usage_2]) => usage_2 - usage_1) .slice(0, 42) .map(([codepoints]) => this.emojiByCodepoints[codepoints]); @@ -289,9 +300,9 @@ export class EmojiPicker extends Component { selectEmoji(ev) { const codepoints = ev.currentTarget.dataset.codepoints; this.props.onSelect(codepoints); - this.recent[codepoints] ??= 0; - this.recent[codepoints]++; - browser.localStorage.setItem("web.emoji.frequent", JSON.stringify(this.recent)); + this.state.recent[codepoints] ??= 0; + this.state.recent[codepoints]++; + browser.localStorage.setItem("web.emoji.frequent", JSON.stringify(this.state.recent)); this.gridRef.el.scrollTop = 0; if (!ev.shiftKey) { this.props.close?.(); diff --git a/addons/web/tooling/_eslintignore b/addons/web/tooling/_eslintignore index 265a1ff54f1..81b309be399 100644 --- a/addons/web/tooling/_eslintignore +++ b/addons/web/tooling/_eslintignore @@ -173,6 +173,8 @@ addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js # Whitelist mail !addons/mail/ !addons/mail/**/* +!addons/test_mail/ +!addons/test_mail/**/* # Whitelist im_livechat !addons/im_livechat/ diff --git a/addons/web/tooling/_jsconfig.json b/addons/web/tooling/_jsconfig.json index 98e7633ebce..5749dbfab2a 100644 --- a/addons/web/tooling/_jsconfig.json +++ b/addons/web/tooling/_jsconfig.json @@ -41,7 +41,8 @@ "@pos_sale/*": ["addons/pos_sale/static/src/*"], "@pos_sale_product_configurator/*": ["addons/pos_sale_product_configurator/static/src/*"], "@pos_six/*": ["addons/pos_six/static/src/*"], - "@pos_stripe/*": ["addons/pos_stripe/static/src/*"] + "@pos_stripe/*": ["addons/pos_stripe/static/src/*"], + "@test_mail/*": ["addons/test_mail/static/src/*"] } }, "include": ["**/*.js", "**/*.ts"], diff --git a/addons/website_livechat/static/tests/tours/website_livechat_common.js b/addons/website_livechat/static/tests/tours/website_livechat_common.js index a66cc0f3fcb..0a1bb9c846f 100644 --- a/addons/website_livechat/static/tests/tours/website_livechat_common.js +++ b/addons/website_livechat/static/tests/tours/website_livechat_common.js @@ -69,7 +69,7 @@ export const feedback = [ }, { content: "Send the feedback", - trigger: "button:contains(Send)", + trigger: "button:contains(Send):not(:disabled)", }, { content: "Check if feedback has been sent",