Initial squashed commit

This commit is contained in:
hoangvv
2026-05-12 18:58:14 +07:00
commit 0b5c2ce91a
54896 changed files with 28050323 additions and 0 deletions
@@ -0,0 +1,147 @@
import {
assertSteps,
click,
contains,
start,
startServer,
step,
triggerEvents,
} from "@mail/../tests/mail_test_helpers";
import { describe, expect, test } from "@odoo/hoot";
import { defineSMSModels } from "@sms/../tests/sms_test_helpers";
import { mockService, serverState } from "@web/../tests/web_test_helpers";
describe.current.tags("desktop");
defineSMSModels();
test("mark as read", async () => {
const pyEnv = await startServer();
const messageId = pyEnv["mail.message"].create({
message_type: "sms",
model: "res.partner",
res_id: serverState.partnerId,
});
pyEnv["mail.notification"].create({
mail_message_id: messageId,
notification_status: "exception",
notification_type: "sms",
});
await start();
await click(".o_menu_systray i[aria-label='Messages']");
await contains(".o-mail-NotificationItem");
await triggerEvents(".o-mail-NotificationItem", ["mouseenter"], { text: "" });
await contains(".o-mail-NotificationItem [title='Mark As Read']");
await contains(".o-mail-NotificationItem-text", {
text: "An error occurred when sending an SMS on “Mitchell Admin”",
});
await click(".o-mail-NotificationItem [title='Mark As Read']");
await contains(".o-mail-NotificationItem", { count: 0 });
});
test("notifications grouped by notification_type", async () => {
const pyEnv = await startServer();
const partnerId = pyEnv["res.partner"].create({});
const [messageId_1, messageId_2] = pyEnv["mail.message"].create([
{
message_type: "sms",
model: "res.partner",
res_id: partnerId,
},
{
message_type: "email",
model: "res.partner",
res_id: partnerId,
},
]);
pyEnv["mail.notification"].create([
{
mail_message_id: messageId_1,
notification_status: "exception",
notification_type: "sms",
},
{
mail_message_id: messageId_1,
notification_status: "exception",
notification_type: "sms",
},
{
mail_message_id: messageId_2,
notification_status: "exception",
notification_type: "email",
},
{
mail_message_id: messageId_2,
notification_status: "exception",
notification_type: "email",
},
]);
await start();
await click(".o_menu_systray i[aria-label='Messages']");
await contains(".o-mail-NotificationItem", { count: 2 });
await contains(":nth-child(1 of .o-mail-NotificationItem)", {
contains: [
[".o-mail-NotificationItem-name", { text: "Email Failure: Contact" }],
[".o-mail-NotificationItem-counter", { text: "2" }],
[".o-mail-NotificationItem-text", { text: "An error occurred when sending an email" }],
],
});
await contains(":nth-child(2 of .o-mail-NotificationItem)", {
contains: [
[".o-mail-NotificationItem-name", { text: "SMS Failure: Contact" }],
[".o-mail-NotificationItem-counter", { text: "2" }],
[".o-mail-NotificationItem-text", { text: "An error occurred when sending an SMS" }],
],
});
});
test("grouped notifications by document model", async () => {
const pyEnv = await startServer();
const [partnerId_1, partnerId_2] = pyEnv["res.partner"].create([{}, {}]);
const [messageId_1, messageId_2] = pyEnv["mail.message"].create([
{
message_type: "sms",
model: "res.partner",
res_id: partnerId_1,
},
{
message_type: "sms",
model: "res.partner",
res_id: partnerId_2,
},
]);
pyEnv["mail.notification"].create([
{
mail_message_id: messageId_1,
notification_status: "exception",
notification_type: "sms",
},
{
mail_message_id: messageId_2,
notification_status: "exception",
notification_type: "sms",
},
]);
mockService("action", {
doAction(action) {
step("do_action");
expect(action.name).toBe("SMS Failures");
expect(action.type).toBe("ir.actions.act_window");
expect(action.view_mode).toBe("kanban,list,form");
expect(action.views).toEqual([
[false, "kanban"],
[false, "list"],
[false, "form"],
]);
expect(action.target).toBe("current");
expect(action.res_model).toBe("res.partner");
expect(action.domain).toEqual([["message_has_sms_error", "=", true]]);
},
});
await start();
await click(".o_menu_systray i[aria-label='Messages']");
await click(".o-mail-NotificationItem", {
text: "SMS Failure: Contact",
contains: [".badge", { text: "2" }],
});
await assertSteps(["do_action"]);
});
@@ -0,0 +1,10 @@
import { fields, models } from "@web/../tests/web_test_helpers";
export class Partner extends models.Model {
_name = "partner";
message = fields.Char();
foo = fields.Char();
mobile = fields.Char();
partner_ids = fields.One2many({ relation: "partner" });
}
@@ -0,0 +1,7 @@
import { fields, models } from "@web/../tests/web_test_helpers";
export class Visitor extends models.Model {
_name = "visitor";
mobile = fields.Char();
}
@@ -0,0 +1,10 @@
import { mailModels } from "@mail/../tests/mail_test_helpers";
import { Partner } from "@sms/../tests/mock_server/mock_models/partner";
import { Visitor } from "@sms/../tests/mock_server/mock_models/visitor";
import { defineModels } from "@web/../tests/web_test_helpers";
export function defineSMSModels() {
return defineModels(smsModels);
}
export const smsModels = { ...mailModels, Partner, Visitor };
@@ -0,0 +1,90 @@
import {
assertSteps,
click,
contains,
openFormView,
start,
startServer,
step,
} from "@mail/../tests/mail_test_helpers";
import { describe, expect, test } from "@odoo/hoot";
import { defineSMSModels } from "@sms/../tests/sms_test_helpers";
import { mockService } from "@web/../tests/web_test_helpers";
describe.current.tags("desktop");
defineSMSModels();
test("Notification Processing", async () => {
const { partnerId } = await _prepareSmsNotification("process");
await start();
await openFormView("res.partner", partnerId);
await _assertContainsSmsNotification();
await _assertContainsPopoverWithIcon("fa-hourglass-half");
});
test("Notification Pending", async () => {
const { partnerId } = await _prepareSmsNotification("pending");
await start();
await openFormView("res.partner", partnerId);
await _assertContainsSmsNotification();
await _assertContainsPopoverWithIcon("fa-paper-plane-o");
});
test("Notification Sent", async () => {
const { partnerId } = await _prepareSmsNotification("sent");
await start();
await openFormView("res.partner", partnerId);
await _assertContainsPopoverWithIcon("fa-check");
});
test("Notification Error", async () => {
const { partnerId, messageId } = await _prepareSmsNotification("exception");
mockService("action", {
doAction(action, options) {
if (action?.res_model === "res.partner") {
return super.doAction(...arguments);
}
expect(action).toBe("sms.sms_resend_action");
expect(options.additionalContext.default_mail_message_id).toBe(messageId);
step("do_action");
},
});
await start();
await openFormView("res.partner", partnerId);
await _assertContainsSmsNotification();
await click(".o-mail-Message-notification");
await assertSteps(["do_action"]);
});
const _prepareSmsNotification = async (notification_status) => {
const pyEnv = await startServer();
const partnerId = pyEnv["res.partner"].create({ name: "Someone", partner_share: true });
const messageId = pyEnv["mail.message"].create({
body: "not empty",
message_type: "sms",
model: "res.partner",
res_id: partnerId,
});
pyEnv["mail.notification"].create({
mail_message_id: messageId,
notification_status: notification_status,
notification_type: "sms",
res_partner_id: partnerId,
});
return { partnerId, messageId };
};
const _assertContainsSmsNotification = async () => {
await contains(".o-mail-Message");
await contains(".o-mail-Message-notification");
await contains(".o-mail-Message-notification i");
await contains(".o-mail-Message-notification i.fa-mobile");
};
const _assertContainsPopoverWithIcon = async (iconClassName) => {
await click(".o-mail-Message-notification");
await contains(".o-mail-MessageNotificationPopover");
await contains(".o-mail-MessageNotificationPopover i");
await contains(`.o-mail-MessageNotificationPopover i.${iconClassName}`);
await contains(".o-mail-MessageNotificationPopover", { text: "Someone" });
};
@@ -0,0 +1,145 @@
import {
assertSteps,
click,
contains,
editInput,
startServer,
step,
} from "@mail/../tests/mail_test_helpers";
import { beforeEach, describe, expect, test } from "@odoo/hoot";
import { queryFirst } from "@odoo/hoot-dom";
import { defineSMSModels } from "@sms/../tests/sms_test_helpers";
import { mockService, mountView, MockServer } from "@web/../tests/web_test_helpers";
describe.current.tags("desktop");
defineSMSModels();
beforeEach(async () => {
const pyEnv = await startServer();
pyEnv["partner"].create([
{ message: "", foo: "yop", mobile: "+32494444444"},
{ message: "", foo: "bayou"},
]);
pyEnv["visitor"].create([
{ mobile: "+32494444444" },
]);
})
test("Sms button in form view", async () => {
const visitorId = MockServer.env["visitor"].search([["mobile","=","+32494444444"]])[0];
await mountView({
type: "form",
resModel: "visitor",
resId: visitorId,
mode: "readonly",
arch:
`<form>
<sheet>
<field name="mobile" widget="phone"/>
</sheet>
</form>`
});
await contains(".o_field_phone");
await contains(".o_field_phone a.o_field_phone_sms", { count: 1 });
});
test("Sms button with option enable_sms set as False", async () => {
const visitorId = MockServer.env["visitor"].search([["mobile","=","+32494444444"]])[0];
await mountView({
type: "form",
resModel: "visitor",
resId: visitorId,
mode: "readonly",
arch:
`<form>
<sheet>
<field name="mobile" widget="phone" options="{'enable_sms': false}"/>
</sheet>
</form>`
});
await contains(".o_field_phone");
await contains(".o_field_phone a.o_field_phone_sms", { count: 0 });
});
test("click on the sms button while creating a new record in a FormView", async () => {
mockService("action", {
doAction(action, options) {
step("do_action");
expect(action.type).toBe("ir.actions.act_window");
expect(action.res_model).toBe("sms.composer");
options.onClose();
},
});
const partnerId = MockServer.env["partner"].search([["foo", "=", "yop"]])[0];
await mountView({
type: "form",
resModel: "partner",
resId: partnerId,
arch:
`<form>
<sheet>
<field name="foo"/>
<field name="mobile" widget="phone"/>
</sheet>
</form>`,
});
await editInput(document.body, "[name='foo'] input", "John");
await editInput(document.body, "[name='mobile'] input", "+32494444411");
await click(".o_field_phone_sms");
expect(queryFirst("[name='foo'] input")).toHaveValue("John");
expect(queryFirst("[name='mobile'] input")).toHaveValue("+32494444411");
await assertSteps(["do_action"]);
});
test(
"click on the sms button in a FormViewDialog has no effect on the main form view",
async () => {
mockService("action", {
doAction(action, options){
step("do_action");
expect(action.type).toBe("ir.actions.act_window");
expect(action.res_model).toBe("sms.composer");
options.onClose();
},
});
const partnerId = MockServer.env["partner"].search([["foo", "=", "yop"]])[0];
await mountView({
type: "form",
resModel: "partner",
resId: partnerId,
arch:
`<form>
<sheet>
<field name="foo"/>
<field name="mobile" widget="phone"/>
<field name="partner_ids">
<kanban>
<templates>
<t t-name="card">
<field name="display_name"/>
</t>
</templates>
</kanban>
</field>
</sheet>
</form>`,
});
await editInput(document.body, "[name='foo'] input", "John");
await editInput(document.body, "[name='mobile'] input", "+32494444411");
await click(".o-kanban-button-new");
await contains(".modal");
await editInput(document.body, ".modal .o_field_char[name='foo'] input", "Max");
await editInput(document.body, ".modal .o_field_phone[name='mobile'] input", "+324955555");
await click(":nth-child(1 of .modal) .o_field_phone_sms");
expect(queryFirst(".modal [name='foo'] input")).toHaveValue("Max");
expect(queryFirst(".modal [name='mobile'] input")).toHaveValue("+324955555");
await click(":nth-child(1 of .modal) .o_form_button_cancel");
expect(queryFirst("[name='foo'] input")).toHaveValue("John");
expect(queryFirst("[name='mobile'] input")).toHaveValue("+32494444411");
await assertSteps(["do_action"]);
}
);