mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-20 11:52:04 +02:00
19.0 vanilla
This commit is contained in:
parent
d1963a3c3a
commit
2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions
|
|
@ -0,0 +1,20 @@
|
|||
import { defineMailModels, start } from "@mail/../tests/mail_test_helpers";
|
||||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { getService } from "@web/../tests/web_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineMailModels();
|
||||
|
||||
test("Attachment model properties", async () => {
|
||||
await start();
|
||||
const attachment = getService("mail.store")["ir.attachment"].insert({
|
||||
id: 750,
|
||||
mimetype: "text/plain",
|
||||
name: "test.txt",
|
||||
});
|
||||
expect(attachment.isText).toBe(true);
|
||||
expect(attachment.isViewable).toBe(true);
|
||||
expect(attachment.mimetype).toBe("text/plain");
|
||||
expect(attachment.name).toBe("test.txt");
|
||||
expect(attachment.extension).toBe("txt");
|
||||
});
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import { Action } from "@mail/core/common/action";
|
||||
|
||||
import { describe, expect, test } from "@odoo/hoot";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
|
||||
test("store is correctly set on actions", async () => {
|
||||
const storeSym = Symbol("STORE");
|
||||
const ownerSym = Symbol("COMPONENT");
|
||||
const action = new Action({
|
||||
owner: ownerSym,
|
||||
id: "test",
|
||||
definition: {},
|
||||
store: storeSym,
|
||||
});
|
||||
expect(action.store).toBe(storeSym);
|
||||
});
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
import {
|
||||
click,
|
||||
contains,
|
||||
defineMailModels,
|
||||
insertText,
|
||||
openFormView,
|
||||
start,
|
||||
startServer,
|
||||
} from "@mail/../tests/mail_test_helpers";
|
||||
|
||||
import { describe, test } from "@odoo/hoot";
|
||||
import { animationFrame } from "@odoo/hoot-dom";
|
||||
import { getOrigin } from "@web/core/utils/urls";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineMailModels();
|
||||
|
||||
test("following internal link from chatter does not open chat window", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "Jeanne" });
|
||||
pyEnv["mail.message"].create({
|
||||
body: `Created by <a href="#" data-oe-model="res.partner" data-oe-id="${pyEnv.user.partner_id}">Admin</a>`,
|
||||
model: "res.partner",
|
||||
res_id: partnerId,
|
||||
});
|
||||
await start();
|
||||
await openFormView("res.partner", partnerId);
|
||||
await contains(".o_last_breadcrumb_item", { text: "Jeanne" });
|
||||
await click("a", { text: "Admin" });
|
||||
await contains(".o_last_breadcrumb_item", { text: "Mitchell Admin" });
|
||||
// Assert 0 chat windows not sufficient because not enough time for potential chat window opening.
|
||||
// Let's open another chat window to give some time and assert only manually open chat window opens.
|
||||
await contains(".o-mail-ChatWindow", { count: 0 });
|
||||
await click(".o_menu_systray i[aria-label='Messages']");
|
||||
await click("button", { text: "New Message" });
|
||||
await insertText("input[placeholder='Search a conversation']", "abc");
|
||||
await click("a", { text: "Create Channel" });
|
||||
await contains(".o-mail-ChatWindow-header", { text: "abc" });
|
||||
await contains(".o-mail-ChatWindow", { count: 1 });
|
||||
});
|
||||
|
||||
test("message link shows error when the message is not known", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "Alice" });
|
||||
const url = `${getOrigin()}/mail/message/999999`;
|
||||
pyEnv["mail.message"].create({
|
||||
body: `Check this out <a class="o_message_redirect" href="${url}" data-oe-model="mail.message" data-oe-id="999999">${url}</a>`,
|
||||
model: "res.partner",
|
||||
res_id: partnerId,
|
||||
});
|
||||
await start();
|
||||
await openFormView("res.partner", partnerId);
|
||||
await click("a.o_message_redirect");
|
||||
await contains(".o_notification:contains(This conversation isn’t available.)");
|
||||
});
|
||||
|
||||
test("same-thread message link does not open the thread again but highlights the message", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const [aliceId, lenaId] = pyEnv["res.partner"].create([{ name: "Alice" }, { name: "Lena" }]);
|
||||
const helloMessageId = pyEnv["mail.message"].create({
|
||||
body: "Hello",
|
||||
model: "res.partner",
|
||||
res_id: aliceId,
|
||||
});
|
||||
const heyMessageId = pyEnv["mail.message"].create({
|
||||
body: "Hey",
|
||||
model: "res.partner",
|
||||
res_id: lenaId,
|
||||
});
|
||||
const helloUrl = `${getOrigin()}/mail/message/${helloMessageId}`;
|
||||
pyEnv["mail.message"].create({
|
||||
body: `Check this out <a class="o_message_redirect" href="${helloUrl}" data-oe-model="mail.message" data-oe-id="${helloMessageId}">${helloUrl}</a>`,
|
||||
model: "res.partner",
|
||||
res_id: aliceId,
|
||||
});
|
||||
const heyUrl = `${getOrigin()}/mail/message/${heyMessageId}`;
|
||||
pyEnv["mail.message"].create({
|
||||
body: `Another thread <a class="o_message_redirect" href="${heyUrl}" data-oe-model="mail.message" data-oe-id="${heyMessageId}">${heyUrl}</a>`,
|
||||
model: "res.partner",
|
||||
res_id: aliceId,
|
||||
});
|
||||
await start();
|
||||
await openFormView("res.partner", aliceId);
|
||||
await click("a.o_message_redirect:contains(Alice)");
|
||||
await contains(".o-mail-Message.o-highlighted:contains(Hello)");
|
||||
await animationFrame(); // give enough time for the potential breadcrumb item to render
|
||||
await contains(".breadcrumb-item", { count: 0 });
|
||||
await click("a.o_message_redirect:contains(Lena)");
|
||||
await contains(".o-mail-Message.o-highlighted:contains(Hey)");
|
||||
await contains(".breadcrumb-item:contains(Alice)");
|
||||
});
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import { Message } from "@mail/core/common/message_model";
|
||||
|
||||
import { defineMailModels, start } from "@mail/../tests/mail_test_helpers";
|
||||
|
||||
import { expect, test } from "@odoo/hoot";
|
||||
|
||||
import {
|
||||
asyncStep,
|
||||
getService,
|
||||
patchWithCleanup,
|
||||
waitForSteps,
|
||||
} from "@web/../tests/web_test_helpers";
|
||||
|
||||
defineMailModels();
|
||||
|
||||
test("store.insert can delete record", async () => {
|
||||
await start();
|
||||
const store = getService("mail.store");
|
||||
store.insert({ "mail.message": [{ id: 1 }] });
|
||||
expect(store["mail.message"].get({ id: 1 })?.id).toBe(1);
|
||||
store.insert({ "mail.message": [{ id: 1, _DELETE: true }] });
|
||||
expect(store["mail.message"].get({ id: 1 })?.id).toBe(undefined);
|
||||
});
|
||||
|
||||
test("store.insert deletes record without creating it", async () => {
|
||||
patchWithCleanup(Message, {
|
||||
new() {
|
||||
const message = super.new(...arguments);
|
||||
asyncStep(`new-${message.id}`);
|
||||
return message;
|
||||
},
|
||||
});
|
||||
await start();
|
||||
const store = getService("mail.store");
|
||||
store.insert({ "mail.message": [{ id: 1, _DELETE: true }] });
|
||||
await waitForSteps([]);
|
||||
expect(store["mail.message"].get({ id: 1 })?.id).toBe(undefined);
|
||||
store.insert({ "mail.message": [{ id: 2 }] });
|
||||
await waitForSteps(["new-2"]);
|
||||
});
|
||||
|
||||
test("store.insert deletes record after relation created it", async () => {
|
||||
patchWithCleanup(Message, {
|
||||
new() {
|
||||
const message = super.new(...arguments);
|
||||
asyncStep(`new-${message.id}`);
|
||||
return message;
|
||||
},
|
||||
});
|
||||
await start();
|
||||
const store = getService("mail.store");
|
||||
store.insert({
|
||||
"mail.message": [{ id: 1, _DELETE: true }],
|
||||
// they key coverage of the test is to have the relation listed after the delete
|
||||
"mail.link.preview": [{ id: 1 }],
|
||||
"mail.message.link.preview": [{ id: 1, link_preview_id: 1, message_id: 1 }],
|
||||
});
|
||||
await waitForSteps(["new-1"]);
|
||||
expect(store["mail.message"].get({ id: 1 })?.id).toBe(undefined);
|
||||
});
|
||||
|
||||
test("store.insert different PY model having same JS model", async () => {
|
||||
await start();
|
||||
const store = getService("mail.store");
|
||||
const data = {
|
||||
"discuss.channel": [
|
||||
{ id: 1, name: "General" },
|
||||
{ id: 2, name: "Sales" },
|
||||
],
|
||||
"mail.thread": [
|
||||
{ id: 1, model: "discuss.channel" },
|
||||
{ id: 3, name: "R&D", model: "discuss.channel" },
|
||||
],
|
||||
};
|
||||
|
||||
store.insert(data);
|
||||
expect(store.Thread.records).toHaveLength(6); // 3 mailboxes + 3 channels
|
||||
expect(Boolean(store.Thread.get({ id: 1, model: "discuss.channel" }))).toBe(true);
|
||||
expect(Boolean(store.Thread.get({ id: 2, model: "discuss.channel" }))).toBe(true);
|
||||
expect(Boolean(store.Thread.get({ id: 3, model: "discuss.channel" }))).toBe(true);
|
||||
});
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import { defineMailModels, start } from "@mail/../tests/mail_test_helpers";
|
||||
|
||||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { markup } from "@odoo/owl";
|
||||
|
||||
import { deserializeDateTime, serializeDateTime } from "@web/core/l10n/dates";
|
||||
import { getService, serverState } from "@web/../tests/web_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineMailModels();
|
||||
|
||||
test("Message model properties", async () => {
|
||||
await start();
|
||||
const store = getService("mail.store");
|
||||
store.Store.insert({
|
||||
self_partner: { id: serverState.partnerId },
|
||||
});
|
||||
store.Thread.insert({
|
||||
id: serverState.partnerId,
|
||||
model: "res.partner",
|
||||
name: "general",
|
||||
});
|
||||
store["ir.attachment"].insert({
|
||||
id: 750,
|
||||
mimetype: "text/plain",
|
||||
name: "test.txt",
|
||||
});
|
||||
const message = store["mail.message"].insert({
|
||||
attachment_ids: 750,
|
||||
author_id: { id: 5, name: "Demo" },
|
||||
body: markup`<p>Test</p>`,
|
||||
date: deserializeDateTime("2019-05-05 10:00:00"),
|
||||
id: 4000,
|
||||
starred: true,
|
||||
model: "res.partner",
|
||||
thread: { id: serverState.partnerId, model: "res.partner" },
|
||||
res_id: serverState.partnerId,
|
||||
});
|
||||
expect(message.body?.toString()).toBe("<p>Test</p>");
|
||||
expect(serializeDateTime(message.date)).toBe("2019-05-05 10:00:00");
|
||||
expect(message.id).toBe(4000);
|
||||
expect(message.attachment_ids[0].name).toBe("test.txt");
|
||||
expect(message.thread.id).toBe(serverState.partnerId);
|
||||
expect(message.thread.name).toBe("general");
|
||||
expect(message.author_id.id).toBe(5);
|
||||
expect(message.author_id.name).toBe("Demo");
|
||||
});
|
||||
|
|
@ -0,0 +1,381 @@
|
|||
import { waitNotifications } from "@bus/../tests/bus_test_helpers";
|
||||
import {
|
||||
click,
|
||||
contains,
|
||||
defineMailModels,
|
||||
insertText,
|
||||
listenStoreFetch,
|
||||
openDiscuss,
|
||||
openFormView,
|
||||
setupChatHub,
|
||||
start,
|
||||
startServer,
|
||||
triggerHotkey,
|
||||
waitStoreFetch,
|
||||
} from "@mail/../tests/mail_test_helpers";
|
||||
import { describe, test } from "@odoo/hoot";
|
||||
import { click as hootClick, press, queryFirst } from "@odoo/hoot-dom";
|
||||
import { mockDate } from "@odoo/hoot-mock";
|
||||
import { Command, serverState, withUser } from "@web/../tests/web_test_helpers";
|
||||
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineMailModels();
|
||||
|
||||
test("keep new message separator when message is deleted", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const generalId = pyEnv["discuss.channel"].create({ name: "General" });
|
||||
pyEnv["mail.message"].create([
|
||||
{
|
||||
body: "message 0",
|
||||
message_type: "comment",
|
||||
model: "discuss.channel",
|
||||
author_id: serverState.partnerId,
|
||||
res_id: generalId,
|
||||
},
|
||||
{
|
||||
body: "message 1",
|
||||
message_type: "comment",
|
||||
model: "discuss.channel",
|
||||
author_id: serverState.partnerId,
|
||||
res_id: generalId,
|
||||
},
|
||||
]);
|
||||
await start();
|
||||
await openDiscuss(generalId);
|
||||
await contains(".o-mail-Message", { count: 2 });
|
||||
queryFirst(".o-mail-Composer-input").blur();
|
||||
await click("[title='Expand']", {
|
||||
parent: [".o-mail-Message", { text: "message 0" }],
|
||||
});
|
||||
await click(".o-dropdown-item:contains('Mark as Unread')");
|
||||
await contains(".o-mail-Thread-newMessage ~ .o-mail-Message", { text: "message 0" });
|
||||
await click("[title='Expand']", {
|
||||
parent: [".o-mail-Message", { text: "message 0" }],
|
||||
});
|
||||
await click(".o-dropdown-item:contains('Delete')");
|
||||
await click(".modal button", { text: "Delete" });
|
||||
await contains(".o-mail-Message", { text: "message 0", count: 0 });
|
||||
await contains(".o-mail-Thread-newMessage ~ .o-mail-Message", { text: "message 1" });
|
||||
});
|
||||
|
||||
test("new message separator is not shown if all messages are new", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
|
||||
const bobPartnerId = pyEnv["res.partner"].create({ name: "Bob" });
|
||||
for (let i = 0; i < 5; i++) {
|
||||
pyEnv["mail.message"].create({
|
||||
author_id: bobPartnerId,
|
||||
body: `message ${i}`,
|
||||
message_type: "comment",
|
||||
model: "discuss.channel",
|
||||
res_id: channelId,
|
||||
});
|
||||
}
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(".o-mail-Message", { count: 5 });
|
||||
await contains(".o-mail-Thread-newMessage hr + span", { count: 0, text: "New" });
|
||||
});
|
||||
|
||||
test("new message separator is shown after first mark as read, on receiving new message", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const bobPartnerId = pyEnv["res.partner"].create({ name: "Bob" });
|
||||
const bobUserId = pyEnv["res.users"].create({ name: "Bob", partner_id: bobPartnerId });
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: serverState.partnerId }),
|
||||
Command.create({ partner_id: bobPartnerId }),
|
||||
],
|
||||
channel_type: "chat",
|
||||
});
|
||||
pyEnv["mail.message"].create({
|
||||
author_id: bobPartnerId,
|
||||
body: `Message 0`,
|
||||
model: "discuss.channel",
|
||||
res_id: channelId,
|
||||
});
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(".o-mail-Message", { text: "Message 0" });
|
||||
await contains(".o-mail-Thread-newMessage", { count: 0, text: "New" });
|
||||
await withUser(bobUserId, () =>
|
||||
rpc("/mail/message/post", {
|
||||
post_data: {
|
||||
body: "Message 1",
|
||||
message_type: "comment",
|
||||
subtype_xmlid: "mail.mt_comment",
|
||||
},
|
||||
thread_id: channelId,
|
||||
thread_model: "discuss.channel",
|
||||
})
|
||||
);
|
||||
await contains(".o-mail-Thread-newMessage ~ .o-mail-Message", { text: "Message 1" });
|
||||
await contains(".o-mail-Thread-newMessage", { text: "New" });
|
||||
});
|
||||
|
||||
test("keep new message separator until user goes back to the thread", async () => {
|
||||
const pyEnv = await startServer();
|
||||
pyEnv["res.users"].write(serverState.userId, { notification_type: "inbox" });
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "Foreigner partner" });
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
name: "test",
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: partnerId }),
|
||||
Command.create({ partner_id: serverState.partnerId }),
|
||||
],
|
||||
});
|
||||
const messageIds = pyEnv["mail.message"].create([
|
||||
{
|
||||
author_id: partnerId,
|
||||
body: "Message body 1",
|
||||
message_type: "comment",
|
||||
model: "discuss.channel",
|
||||
res_id: channelId,
|
||||
},
|
||||
{
|
||||
author_id: partnerId,
|
||||
body: "Message body 2",
|
||||
message_type: "comment",
|
||||
model: "discuss.channel",
|
||||
res_id: channelId,
|
||||
},
|
||||
]);
|
||||
// simulate that there is at least one read message in the channel
|
||||
const [memberId] = pyEnv["discuss.channel.member"].search([
|
||||
["channel_id", "=", channelId],
|
||||
["partner_id", "=", serverState.partnerId],
|
||||
]);
|
||||
pyEnv["discuss.channel.member"].write([memberId], { new_message_separator: messageIds[0] + 1 });
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(".o-mail-Thread");
|
||||
await contains(".o-mail-Thread-newMessage ~ .o-mail-Message", { text: "Message body 2" });
|
||||
await contains(".o-mail-Thread-newMessage:contains('New')");
|
||||
await hootClick(document.body); // Force "focusin" back on the textarea
|
||||
await hootClick(".o-mail-Composer-input");
|
||||
await waitNotifications([
|
||||
"mail.record/insert",
|
||||
(n) => n["discuss.channel.member"][0].new_message_separator,
|
||||
]);
|
||||
await hootClick(".o-mail-DiscussSidebar-item:contains(History)");
|
||||
await contains(".o-mail-DiscussContent-threadName", { value: "History" });
|
||||
await hootClick(".o-mail-DiscussSidebar-item:contains(test)");
|
||||
await contains(".o-mail-DiscussContent-threadName", { value: "test" });
|
||||
await contains(".o-mail-Message", { text: "Message body 2" });
|
||||
await contains(".o-mail-Thread-newMessage:contains('New')", { count: 0 });
|
||||
});
|
||||
|
||||
test("show new message separator on receiving new message when out of odoo focus", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "Foreigner partner" });
|
||||
const userId = pyEnv["res.users"].create({
|
||||
name: "Foreigner user",
|
||||
partner_id: partnerId,
|
||||
});
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [
|
||||
Command.create({ message_unread_counter: 0, partner_id: serverState.partnerId }),
|
||||
Command.create({ partner_id: partnerId }),
|
||||
],
|
||||
channel_type: "channel",
|
||||
name: "General",
|
||||
});
|
||||
const messageId = pyEnv["mail.message"].create({
|
||||
body: "not empty",
|
||||
model: "discuss.channel",
|
||||
res_id: channelId,
|
||||
});
|
||||
// simulate that there is at least one read message in the channel
|
||||
const [memberId] = pyEnv["discuss.channel.member"].search([
|
||||
["channel_id", "=", channelId],
|
||||
["partner_id", "=", serverState.partnerId],
|
||||
]);
|
||||
pyEnv["discuss.channel.member"].write([memberId], { new_message_separator: messageId + 1 });
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(".o-mail-Thread");
|
||||
await contains(".o-mail-Thread-newMessage:contains('New')", { count: 0 });
|
||||
// simulate receiving a message
|
||||
await withUser(userId, () =>
|
||||
rpc("/mail/message/post", {
|
||||
post_data: { body: "hu", message_type: "comment", subtype_xmlid: "mail.mt_comment" },
|
||||
thread_id: channelId,
|
||||
thread_model: "discuss.channel",
|
||||
})
|
||||
);
|
||||
await contains(".o-mail-Message", { text: "hu" });
|
||||
await contains(".o-mail-Thread-newMessage:contains('New')");
|
||||
await contains(".o-mail-Thread-newMessage ~ .o-mail-Message", { text: "hu" });
|
||||
});
|
||||
|
||||
test("keep new message separator until current user sends a message", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await insertText(".o-mail-Composer-input", "hello");
|
||||
await triggerHotkey("Enter");
|
||||
await contains(".o-mail-Message", { text: "hello" });
|
||||
await click(".o-mail-Message [title='Expand']");
|
||||
await click(".o-dropdown-item:contains('Mark as Unread')");
|
||||
await contains(".o-mail-Thread-newMessage:contains('New')");
|
||||
await insertText(".o-mail-Composer-input", "hey!");
|
||||
await press("Enter");
|
||||
await contains(".o-mail-Message", { count: 2 });
|
||||
await contains(".o-mail-Thread-newMessage:contains('New')", { count: 0 });
|
||||
});
|
||||
|
||||
test("keep new message separator when switching between chat window and discuss of same thread", async () => {
|
||||
const pyEnv = await startServer();
|
||||
pyEnv["discuss.channel"].create({ channel_type: "channel", name: "General" });
|
||||
await start();
|
||||
await click(".o_menu_systray i[aria-label='Messages']");
|
||||
await click("button", { text: "General" });
|
||||
await insertText(".o-mail-Composer-input", "Very important message!");
|
||||
await triggerHotkey("Enter");
|
||||
await click(".o-mail-Message [title='Expand']");
|
||||
await click(".o-dropdown-item:contains('Mark as Unread')");
|
||||
await contains(".o-mail-Thread-newMessage");
|
||||
// dropdown requires an extra delay before click (because handler is registered in useEffect)
|
||||
await contains("[title='Open Actions Menu']");
|
||||
await click("[title='Open Actions Menu']");
|
||||
await click(".o-dropdown-item", { text: "Open in Discuss" });
|
||||
await contains(".o-mail-DiscussContent-threadName", { value: "General" });
|
||||
await contains(".o-mail-Thread-newMessage");
|
||||
await openFormView("res.partner", serverState.partnerId);
|
||||
await contains(".o-mail-ChatWindow-header", { text: "General" });
|
||||
await contains(".o-mail-Thread-newMessage");
|
||||
});
|
||||
|
||||
test("show new message separator when message is received in chat window", async () => {
|
||||
mockDate("2023-01-03 12:00:00"); // so that it's after last interest (mock server is in 2019 by default!)
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "Demo" });
|
||||
const userId = pyEnv["res.users"].create({ name: "Foreigner user", partner_id: partnerId });
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [
|
||||
Command.create({
|
||||
unpin_dt: "2021-01-01 12:00:00",
|
||||
last_interest_dt: "2021-01-01 10:00:00",
|
||||
partner_id: serverState.partnerId,
|
||||
}),
|
||||
Command.create({ partner_id: partnerId }),
|
||||
],
|
||||
channel_type: "chat",
|
||||
});
|
||||
const messageId = pyEnv["mail.message"].create({
|
||||
body: "not empty",
|
||||
model: "discuss.channel",
|
||||
res_id: channelId,
|
||||
});
|
||||
const [memberId] = pyEnv["discuss.channel.member"].search([
|
||||
["channel_id", "=", channelId],
|
||||
["partner_id", "=", serverState.partnerId],
|
||||
]);
|
||||
pyEnv["discuss.channel.member"].write([memberId], { new_message_separator: messageId + 1 });
|
||||
setupChatHub({ opened: [channelId] });
|
||||
await start();
|
||||
// simulate receiving a message
|
||||
withUser(userId, () =>
|
||||
rpc("/mail/message/post", {
|
||||
post_data: { body: "hu", message_type: "comment" },
|
||||
thread_id: channelId,
|
||||
thread_model: "discuss.channel",
|
||||
})
|
||||
);
|
||||
await contains(".o-mail-ChatWindow");
|
||||
await contains(".o-mail-Message", { count: 2 });
|
||||
await contains(".o-mail-Thread-newMessage:contains('New'):contains('New')");
|
||||
await contains(".o-mail-Thread-newMessage + .o-mail-Message", { text: "hu" });
|
||||
});
|
||||
|
||||
test("show new message separator when message is received while chat window is closed", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "Demo" });
|
||||
const userId = pyEnv["res.users"].create({
|
||||
name: "Foreigner user",
|
||||
partner_id: partnerId,
|
||||
});
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: serverState.partnerId }),
|
||||
Command.create({ partner_id: partnerId }),
|
||||
],
|
||||
channel_type: "chat",
|
||||
});
|
||||
const messageId = pyEnv["mail.message"].create({
|
||||
body: "not empty",
|
||||
model: "discuss.channel",
|
||||
res_id: channelId,
|
||||
});
|
||||
// simulate that there is at least one read message in the channel
|
||||
const [memberId] = pyEnv["discuss.channel.member"].search([
|
||||
["channel_id", "=", channelId],
|
||||
["partner_id", "=", serverState.partnerId],
|
||||
]);
|
||||
pyEnv["discuss.channel.member"].write([memberId], { new_message_separator: messageId + 1 });
|
||||
setupChatHub({ opened: [channelId] });
|
||||
listenStoreFetch("init_messaging");
|
||||
await start();
|
||||
await waitStoreFetch("init_messaging");
|
||||
await click(".o-mail-ChatWindow-header [title*='Close Chat Window']");
|
||||
await contains(".o-mail-ChatWindow", { count: 0 });
|
||||
// send after init_messaging because bus subscription is done after init_messaging
|
||||
// simulate receiving a message
|
||||
await withUser(userId, () =>
|
||||
rpc("/mail/message/post", {
|
||||
post_data: { body: "hu", message_type: "comment" },
|
||||
thread_id: channelId,
|
||||
thread_model: "discuss.channel",
|
||||
})
|
||||
);
|
||||
await contains(".o-mail-ChatBubble");
|
||||
await contains(".o-mail-ChatBubble-counter", { text: "1" });
|
||||
await click(".o-mail-ChatBubble");
|
||||
await contains(".o-mail-Thread-newMessage:contains('New')");
|
||||
});
|
||||
|
||||
test("only show new message separator in its thread", async () => {
|
||||
// when a message acts as the reference for displaying new message separator,
|
||||
// this should applies only when vieweing the message in its thread.
|
||||
const pyEnv = await startServer();
|
||||
pyEnv["res.users"].write(serverState.userId, { notification_type: "inbox" });
|
||||
const demoPartnerId = pyEnv["res.partner"].create({ name: "Demo" });
|
||||
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
|
||||
const messageIds = pyEnv["mail.message"].create([
|
||||
{
|
||||
author_id: demoPartnerId,
|
||||
body: "Hello",
|
||||
message_type: "comment",
|
||||
model: "discuss.channel",
|
||||
res_id: channelId,
|
||||
},
|
||||
{
|
||||
author_id: demoPartnerId,
|
||||
body: "@Mitchell Admin",
|
||||
attachment_ids: [],
|
||||
message_type: "comment",
|
||||
model: "discuss.channel",
|
||||
res_id: channelId,
|
||||
needaction: true,
|
||||
},
|
||||
]);
|
||||
// simulate that there is at least one read message in the channel
|
||||
const [memberId] = pyEnv["discuss.channel.member"].search([
|
||||
["channel_id", "=", channelId],
|
||||
["partner_id", "=", serverState.partnerId],
|
||||
]);
|
||||
pyEnv["discuss.channel.member"].write([memberId], { new_message_separator: messageIds[0] + 1 });
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(".o-mail-Thread-newMessage ~ .o-mail-Message", { text: "@Mitchell Admin" });
|
||||
await click(".o-mail-DiscussSidebar-item", { text: "Inbox" });
|
||||
await contains(".o-mail-DiscussContent-threadName", { value: "Inbox" });
|
||||
await contains(".o-mail-Message", { text: "@Mitchell Admin" });
|
||||
await contains(".o-mail-Thread-newMessage ~ .o-mail-Message", {
|
||||
count: 0,
|
||||
text: "@Mitchell Admin",
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
import {
|
||||
contains,
|
||||
defineMailModels,
|
||||
setupChatHub,
|
||||
start,
|
||||
startServer,
|
||||
} from "@mail/../tests/mail_test_helpers";
|
||||
import { describe, test } from "@odoo/hoot";
|
||||
import { Command, getService, serverState } from "@web/../tests/web_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineMailModels();
|
||||
|
||||
test("openChat: display notification for partner without user", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({});
|
||||
await start();
|
||||
await getService("mail.store").openChat({ partnerId });
|
||||
await contains(".o_notification:has(.o_notification_bar.bg-info)", {
|
||||
text: "You can only chat with partners that have a dedicated user.",
|
||||
});
|
||||
});
|
||||
|
||||
test("openChat: display notification for wrong user", async () => {
|
||||
const pyEnv = await startServer();
|
||||
pyEnv["res.users"].create({});
|
||||
await start();
|
||||
// userId not in the server data
|
||||
await getService("mail.store").openChat({ userId: 4242 });
|
||||
await contains(".o_notification:has(.o_notification_bar.bg-warning)", {
|
||||
text: "You can only chat with existing users.",
|
||||
});
|
||||
});
|
||||
|
||||
test("openChat: open new chat for user", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({});
|
||||
pyEnv["res.users"].create({ partner_id: partnerId });
|
||||
await start();
|
||||
await contains(".o-mail-ChatHub");
|
||||
await contains(".o-mail-ChatWindow", { count: 0 });
|
||||
getService("mail.store").openChat({ partnerId });
|
||||
await contains(".o-mail-ChatWindow");
|
||||
});
|
||||
|
||||
test.tags("focus required");
|
||||
test("openChat: open existing chat for user", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({});
|
||||
pyEnv["res.users"].create({ partner_id: partnerId });
|
||||
const channelId = pyEnv["discuss.channel"].create({
|
||||
channel_member_ids: [
|
||||
Command.create({ partner_id: serverState.partnerId }),
|
||||
Command.create({ partner_id: partnerId }),
|
||||
],
|
||||
channel_type: "chat",
|
||||
});
|
||||
setupChatHub({ opened: [channelId] });
|
||||
await start();
|
||||
await contains(".o-mail-ChatWindow .o-mail-Composer-input:not(:focus)");
|
||||
getService("mail.store").openChat({ partnerId });
|
||||
await contains(".o-mail-ChatWindow .o-mail-Composer-input:focus");
|
||||
});
|
||||
1414
odoo-bringout-oca-ocb-mail/mail/static/tests/core/record.test.js
Normal file
1414
odoo-bringout-oca-ocb-mail/mail/static/tests/core/record.test.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,214 @@
|
|||
import { HIGHLIGHT_CLASS, searchHighlight } from "@mail/core/common/message_search_hook";
|
||||
import {
|
||||
SIZES,
|
||||
click,
|
||||
contains,
|
||||
defineMailModels,
|
||||
insertText,
|
||||
openDiscuss,
|
||||
openFormView,
|
||||
patchUiSize,
|
||||
start,
|
||||
startServer,
|
||||
triggerHotkey,
|
||||
} from "@mail/../tests/mail_test_helpers";
|
||||
|
||||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { markup } from "@odoo/owl";
|
||||
|
||||
import { serverState } from "@web/../tests/web_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
defineMailModels();
|
||||
|
||||
test("Search highlight", async () => {
|
||||
const testCases = [
|
||||
{
|
||||
input: markup`test odoo`,
|
||||
output: `test <span class="${HIGHLIGHT_CLASS}">odoo</span>`,
|
||||
searchTerm: "odoo",
|
||||
},
|
||||
{
|
||||
input: markup`<a href="https://www.odoo.com">https://www.odoo.com</a>`,
|
||||
output: `<a href="https://www.odoo.com">https://www.<span class="${HIGHLIGHT_CLASS}">odoo</span>.com</a>`,
|
||||
searchTerm: "odoo",
|
||||
},
|
||||
{
|
||||
input: '<a href="https://www.odoo.com">https://www.odoo.com</a>',
|
||||
output: `<a href="https://www.<span class="${HIGHLIGHT_CLASS}">odoo</span>.com">https://www.<span class="${HIGHLIGHT_CLASS}">odoo</span>.com</a>`,
|
||||
searchTerm: "odoo",
|
||||
},
|
||||
{
|
||||
input: markup`<a href="https://www.odoo.com">Odoo</a>`,
|
||||
output: `<a href="https://www.odoo.com"><span class="${HIGHLIGHT_CLASS}">Odoo</span></a>`,
|
||||
searchTerm: "odoo",
|
||||
},
|
||||
{
|
||||
input: markup`<a href="https://www.odoo.com">Odoo</a> Odoo is a free software`,
|
||||
output: `<a href="https://www.odoo.com"><span class="${HIGHLIGHT_CLASS}">Odoo</span></a> <span class="${HIGHLIGHT_CLASS}">Odoo</span> is a free software`,
|
||||
searchTerm: "odoo",
|
||||
},
|
||||
{
|
||||
input: markup`odoo is a free software`,
|
||||
output: `<span class="${HIGHLIGHT_CLASS}">odoo</span> is a free software`,
|
||||
searchTerm: "odoo",
|
||||
},
|
||||
{
|
||||
input: markup`software ODOO is a free`,
|
||||
output: `software <span class="${HIGHLIGHT_CLASS}">ODOO</span> is a free`,
|
||||
searchTerm: "odoo",
|
||||
},
|
||||
{
|
||||
input: markup`<ul>
|
||||
<li>Odoo</li>
|
||||
<li><a href="https://odoo.com">Odoo ERP</a> Best ERP</li>
|
||||
</ul>`,
|
||||
output: `<ul>
|
||||
<li><span class="${HIGHLIGHT_CLASS}">Odoo</span></li>
|
||||
<li><a href="https://odoo.com"><span class="${HIGHLIGHT_CLASS}">Odoo</span> ERP</a> Best ERP</li>
|
||||
</ul>`,
|
||||
searchTerm: "odoo",
|
||||
},
|
||||
{
|
||||
input: markup`test <strong>Odoo</strong> test`,
|
||||
output: `<span class="${HIGHLIGHT_CLASS}">test</span> <strong><span class="${HIGHLIGHT_CLASS}">Odoo</span></strong> <span class="${HIGHLIGHT_CLASS}">test</span>`,
|
||||
searchTerm: "odoo test",
|
||||
},
|
||||
{
|
||||
input: markup`test <br> test`,
|
||||
output: `<span class="${HIGHLIGHT_CLASS}">test</span> <br> <span class="${HIGHLIGHT_CLASS}">test</span>`,
|
||||
searchTerm: "odoo test",
|
||||
},
|
||||
{
|
||||
input: markup`<strong>test</strong> test`,
|
||||
output: `<strong><span class="${HIGHLIGHT_CLASS}">test</span></strong> <span class="${HIGHLIGHT_CLASS}">test</span>`,
|
||||
searchTerm: "test",
|
||||
},
|
||||
{
|
||||
input: markup`<strong>a</strong> test`,
|
||||
output: `<strong><span class="${HIGHLIGHT_CLASS}">a</span></strong> <span class="${HIGHLIGHT_CLASS}">test</span>`,
|
||||
searchTerm: "a test",
|
||||
},
|
||||
{
|
||||
input: markup`&amp;`,
|
||||
output: `<span class="${HIGHLIGHT_CLASS}">&amp;</span>`,
|
||||
searchTerm: "&",
|
||||
},
|
||||
{
|
||||
input: markup`&amp;`,
|
||||
output: `<span class="${HIGHLIGHT_CLASS}">&</span>amp;`,
|
||||
searchTerm: "&",
|
||||
},
|
||||
{
|
||||
input: markup`<strong>test</strong> hello`,
|
||||
output: `<strong><span class="${HIGHLIGHT_CLASS}">test</span></strong> <span class="${HIGHLIGHT_CLASS}">hello</span>`,
|
||||
searchTerm: "test hello",
|
||||
},
|
||||
{
|
||||
input: markup`<p><strong>test</strong> hello</p>`,
|
||||
output: `<p><strong><span class="${HIGHLIGHT_CLASS}">test</span></strong> <span class="${HIGHLIGHT_CLASS}">hello</span></p>`,
|
||||
searchTerm: "test hello",
|
||||
},
|
||||
];
|
||||
for (const { input, output, searchTerm } of testCases) {
|
||||
expect(searchHighlight(searchTerm, input).toString()).toBe(output);
|
||||
}
|
||||
});
|
||||
|
||||
test("Display highlighted search in chatter", async () => {
|
||||
patchUiSize({ size: SIZES.XXL });
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "John Doe" });
|
||||
pyEnv["mail.message"].create({
|
||||
body: "not empty",
|
||||
model: "res.partner",
|
||||
res_id: partnerId,
|
||||
});
|
||||
await start();
|
||||
await openFormView("res.partner", partnerId);
|
||||
await click("[title='Search Messages']");
|
||||
await insertText(".o_searchview_input", "empty");
|
||||
triggerHotkey("Enter");
|
||||
await contains(`.o-mail-SearchMessageResult .o-mail-Message span.${HIGHLIGHT_CLASS}`);
|
||||
});
|
||||
|
||||
test("Display multiple highlighted search in chatter", async () => {
|
||||
patchUiSize({ size: SIZES.XXL });
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "John Doe" });
|
||||
pyEnv["mail.message"].create({
|
||||
body: "not test empty",
|
||||
model: "res.partner",
|
||||
res_id: partnerId,
|
||||
});
|
||||
await start();
|
||||
await openFormView("res.partner", partnerId);
|
||||
await click("[title='Search Messages']");
|
||||
await insertText(".o_searchview_input", "not empty");
|
||||
triggerHotkey("Enter");
|
||||
await contains(`.o-mail-SearchMessageResult .o-mail-Message span.${HIGHLIGHT_CLASS}`, {
|
||||
count: 2,
|
||||
});
|
||||
});
|
||||
|
||||
test("Display highlighted search in Discuss", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
|
||||
pyEnv["mail.message"].create({
|
||||
author_id: serverState.partnerId,
|
||||
body: "not empty",
|
||||
attachment_ids: [],
|
||||
message_type: "comment",
|
||||
model: "discuss.channel",
|
||||
res_id: channelId,
|
||||
});
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(".o-mail-Message");
|
||||
await click("button[title='Search Messages']");
|
||||
await insertText(".o_searchview_input", "empty");
|
||||
triggerHotkey("Enter");
|
||||
await contains(`.o-mail-SearchMessagesPanel .o-mail-Message span.${HIGHLIGHT_CLASS}`);
|
||||
});
|
||||
|
||||
test("Display multiple highlighted search in Discuss", async () => {
|
||||
const pyEnv = await startServer();
|
||||
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
|
||||
pyEnv["mail.message"].create({
|
||||
author_id: serverState.partnerId,
|
||||
body: "not prout empty",
|
||||
attachment_ids: [],
|
||||
message_type: "comment",
|
||||
model: "discuss.channel",
|
||||
res_id: channelId,
|
||||
});
|
||||
await start();
|
||||
await openDiscuss(channelId);
|
||||
await contains(".o-mail-Message");
|
||||
await click("button[title='Search Messages']");
|
||||
await insertText(".o_searchview_input", "not empty");
|
||||
triggerHotkey("Enter");
|
||||
await contains(`.o-mail-SearchMessagesPanel .o-mail-Message span.${HIGHLIGHT_CLASS}`, {
|
||||
count: 2,
|
||||
});
|
||||
});
|
||||
|
||||
test("Display highlighted with escaped character must ignore them", async () => {
|
||||
patchUiSize({ size: SIZES.XXL });
|
||||
const pyEnv = await startServer();
|
||||
const partnerId = pyEnv["res.partner"].create({ name: "John Doe" });
|
||||
pyEnv["mail.message"].create({
|
||||
body: "<p><strong>test</strong> hello</p>",
|
||||
model: "res.partner",
|
||||
res_id: partnerId,
|
||||
});
|
||||
await start();
|
||||
await openFormView("res.partner", partnerId);
|
||||
await click("[title='Search Messages']");
|
||||
await insertText(".o_searchview_input", "test hello");
|
||||
triggerHotkey("Enter");
|
||||
await contains(`.o-mail-SearchMessageResult .o-mail-Message span.${HIGHLIGHT_CLASS}`, {
|
||||
count: 2,
|
||||
});
|
||||
await contains(`.o-mail-Message-body`, { text: "<strong>test</strong> hello" });
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue