mirror of
https://github.com/bringout/oca-ocb-mail.git
synced 2026-04-20 04:22:09 +02:00
Initial commit: Mail packages
This commit is contained in:
commit
4e53507711
1948 changed files with 751201 additions and 0 deletions
|
|
@ -0,0 +1,159 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { makeDeferred } from '@mail/utils/deferred';
|
||||
import {
|
||||
afterNextRender,
|
||||
start,
|
||||
startServer,
|
||||
} from '@mail/../tests/helpers/test_utils';
|
||||
|
||||
import { patchWithCleanup } from '@web/../tests/helpers/utils';
|
||||
|
||||
QUnit.module('sms', {}, function () {
|
||||
QUnit.module('components', {}, function () {
|
||||
QUnit.module('message_tests.js');
|
||||
|
||||
QUnit.test('Notification Sent', async function (assert) {
|
||||
assert.expect(9);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const resPartnerId1 = pyEnv['res.partner'].create({ name: "Someone", partner_share: true });
|
||||
const mailMessageId1 = pyEnv['mail.message'].create({
|
||||
body: 'not empty',
|
||||
message_type: 'sms',
|
||||
model: 'res.partner',
|
||||
res_id: resPartnerId1,
|
||||
});
|
||||
pyEnv['mail.notification'].create({
|
||||
mail_message_id: mailMessageId1,
|
||||
notification_status: 'sent',
|
||||
notification_type: 'sms',
|
||||
res_partner_id: resPartnerId1,
|
||||
});
|
||||
const { openFormView } = await start();
|
||||
await openFormView({
|
||||
res_id: resPartnerId1,
|
||||
res_model: 'res.partner',
|
||||
});
|
||||
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_Message',
|
||||
"should display a message component"
|
||||
);
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_Message_notificationIconClickable',
|
||||
"should display the notification icon container"
|
||||
);
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_Message_notificationIcon',
|
||||
"should display the notification icon"
|
||||
);
|
||||
assert.hasClass(
|
||||
document.querySelector('.o_Message_notificationIcon'),
|
||||
'fa-mobile',
|
||||
"icon should represent sms"
|
||||
);
|
||||
|
||||
await afterNextRender(() => {
|
||||
document.querySelector('.o_Message_notificationIconClickable').click();
|
||||
});
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_MessageNotificationPopoverContent',
|
||||
"notification popover should be open"
|
||||
);
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_MessageNotificationPopoverContent_notificationIcon',
|
||||
"popover should have one icon"
|
||||
);
|
||||
assert.hasClass(
|
||||
document.querySelector('.o_MessageNotificationPopoverContent_notificationIcon'),
|
||||
'fa-check',
|
||||
"popover should have the sent icon"
|
||||
);
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_MessageNotificationPopoverContent_notificationPartnerName',
|
||||
"popover should have the partner name"
|
||||
);
|
||||
assert.strictEqual(
|
||||
document.querySelector('.o_MessageNotificationPopoverContent_notificationPartnerName').textContent.trim(),
|
||||
"Someone",
|
||||
"partner name should be correct"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('Notification Error', async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
const openResendActionDef = makeDeferred();
|
||||
const pyEnv = await startServer();
|
||||
const resPartnerId1 = pyEnv['res.partner'].create({ name: "Someone", partner_share: true });
|
||||
const mailMessageId1 = pyEnv['mail.message'].create({
|
||||
body: 'not empty',
|
||||
message_type: 'sms',
|
||||
model: 'res.partner',
|
||||
res_id: resPartnerId1,
|
||||
});
|
||||
pyEnv['mail.notification'].create({
|
||||
mail_message_id: mailMessageId1,
|
||||
notification_status: 'exception',
|
||||
notification_type: 'sms',
|
||||
res_partner_id: resPartnerId1,
|
||||
});
|
||||
const { env, openFormView } = await start();
|
||||
await openFormView({
|
||||
res_id: resPartnerId1,
|
||||
res_model: 'res.partner',
|
||||
});
|
||||
patchWithCleanup(env.services.action, {
|
||||
doAction(action, options) {
|
||||
assert.step('do_action');
|
||||
assert.strictEqual(
|
||||
action,
|
||||
'sms.sms_resend_action',
|
||||
"action should be the one to resend sms"
|
||||
);
|
||||
assert.strictEqual(
|
||||
options.additionalContext.default_mail_message_id,
|
||||
mailMessageId1,
|
||||
"action should have correct message id"
|
||||
);
|
||||
openResendActionDef.resolve();
|
||||
},
|
||||
});
|
||||
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_Message',
|
||||
"should display a message component"
|
||||
);
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_Message_notificationIconClickable',
|
||||
"should display the notification icon container"
|
||||
);
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_Message_notificationIcon',
|
||||
"should display the notification icon"
|
||||
);
|
||||
assert.hasClass(
|
||||
document.querySelector('.o_Message_notificationIcon'),
|
||||
'fa-mobile',
|
||||
"icon should represent sms"
|
||||
);
|
||||
document.querySelector('.o_Message_notificationIconClickable').click();
|
||||
await openResendActionDef;
|
||||
assert.verifySteps(
|
||||
['do_action'],
|
||||
"should do an action to display the resend sms dialog"
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { start, startServer } from '@mail/../tests/helpers/test_utils';
|
||||
|
||||
import { patchWithCleanup } from '@web/../tests/helpers/utils';
|
||||
|
||||
QUnit.module('sms', {}, function () {
|
||||
QUnit.module('components', {}, function () {
|
||||
QUnit.module('notification_list', {}, function () {
|
||||
QUnit.module('notification_list_notification_group_tests.js');
|
||||
|
||||
QUnit.test('mark as read', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const mailChannelId1 = pyEnv['mail.channel'].create({});
|
||||
const mailMessageId1 = pyEnv['mail.message'].create(
|
||||
// message that is expected to have a failure
|
||||
{
|
||||
author_id: pyEnv.currentPartnerId,
|
||||
message_type: 'sms',
|
||||
model: 'mail.channel',
|
||||
res_id: mailChannelId1,
|
||||
}
|
||||
);
|
||||
pyEnv['mail.notification'].create(
|
||||
// failure that is expected to be used in the test
|
||||
{
|
||||
mail_message_id: mailMessageId1, // id of the related message
|
||||
notification_status: 'exception', // necessary value to have a failure
|
||||
notification_type: 'sms',
|
||||
}
|
||||
);
|
||||
const { afterNextRender, click } = await start();
|
||||
await click('.o_MessagingMenu_toggler');
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_NotificationGroup_markAsRead',
|
||||
"should have 1 mark as read button"
|
||||
);
|
||||
|
||||
await afterNextRender(() => {
|
||||
document.querySelector('.o_NotificationGroup_markAsRead').click();
|
||||
});
|
||||
assert.containsNone(
|
||||
document.body,
|
||||
'.o_NotificationGroup',
|
||||
"should have no notification group"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('notifications grouped by notification_type', async function (assert) {
|
||||
assert.expect(11);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const resPartnerId1 = pyEnv['res.partner'].create({});
|
||||
const [mailMessageId1, mailMessageId2] = pyEnv['mail.message'].create([
|
||||
{
|
||||
message_type: 'sms', // different type from second message
|
||||
model: 'res.partner', // same model as second message (and not `mail.channel`)
|
||||
res_id: resPartnerId1, // same res_id as second message
|
||||
res_model_name: "Partner", // random related model name
|
||||
},
|
||||
{
|
||||
message_type: 'email', // different type from first message
|
||||
model: 'res.partner', // same model as first message (and not `mail.channel`)
|
||||
res_id: resPartnerId1, // same res_id as first message
|
||||
res_model_name: "Partner", // same related model name for consistency
|
||||
},
|
||||
]);
|
||||
pyEnv['mail.notification'].create([
|
||||
{
|
||||
mail_message_id: mailMessageId1, // id of the related first message
|
||||
notification_status: 'exception', // necessary value to have a failure
|
||||
notification_type: 'sms', // different type from second failure
|
||||
},
|
||||
{
|
||||
mail_message_id: mailMessageId1,
|
||||
notification_status: 'exception',
|
||||
notification_type: 'sms',
|
||||
},
|
||||
{
|
||||
mail_message_id: mailMessageId2, // id of the related second message
|
||||
notification_status: 'exception', // necessary value to have a failure
|
||||
notification_type: 'email', // different type from first failure
|
||||
},
|
||||
{
|
||||
mail_message_id: mailMessageId2,
|
||||
notification_status: 'exception',
|
||||
notification_type: 'email',
|
||||
},
|
||||
]);
|
||||
const { click } = await start();
|
||||
await click('.o_MessagingMenu_toggler');
|
||||
|
||||
assert.containsN(
|
||||
document.body,
|
||||
'.o_NotificationGroup',
|
||||
2,
|
||||
"should have 2 notifications group"
|
||||
);
|
||||
const groups = document.querySelectorAll('.o_NotificationGroup');
|
||||
assert.containsOnce(
|
||||
groups[0],
|
||||
'.o_NotificationGroup_name',
|
||||
"should have 1 group name in first group"
|
||||
);
|
||||
assert.strictEqual(
|
||||
groups[0].querySelector('.o_NotificationGroup_name').textContent,
|
||||
"Partner",
|
||||
"should have model name as group name"
|
||||
);
|
||||
assert.containsOnce(
|
||||
groups[0],
|
||||
'.o_NotificationGroup_counter',
|
||||
"should have 1 group counter in first group"
|
||||
);
|
||||
assert.strictEqual(
|
||||
groups[0].querySelector('.o_NotificationGroup_counter').textContent.trim(),
|
||||
"(2)",
|
||||
"should have 2 notifications in first group"
|
||||
);
|
||||
assert.strictEqual(
|
||||
groups[0].querySelector('.o_NotificationGroup_inlineText').textContent.trim(),
|
||||
"An error occurred when sending an email.",
|
||||
"should have the group text corresponding to email"
|
||||
);
|
||||
assert.containsOnce(
|
||||
groups[1],
|
||||
'.o_NotificationGroup_name',
|
||||
"should have 1 group name in second group"
|
||||
);
|
||||
assert.strictEqual(
|
||||
groups[1].querySelector('.o_NotificationGroup_name').textContent,
|
||||
"Partner",
|
||||
"should have second model name as group name"
|
||||
);
|
||||
assert.containsOnce(
|
||||
groups[1],
|
||||
'.o_NotificationGroup_counter',
|
||||
"should have 1 group counter in second group"
|
||||
);
|
||||
assert.strictEqual(
|
||||
groups[1].querySelector('.o_NotificationGroup_counter').textContent.trim(),
|
||||
"(2)",
|
||||
"should have 2 notifications in second group"
|
||||
);
|
||||
assert.strictEqual(
|
||||
groups[1].querySelector('.o_NotificationGroup_inlineText').textContent.trim(),
|
||||
"An error occurred when sending an SMS.",
|
||||
"should have the group text corresponding to sms"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test('grouped notifications by document model', async function (assert) {
|
||||
// If all failures linked to a document model refers to different documents,
|
||||
// a single notification should group all failures that are linked to this
|
||||
// document model.
|
||||
assert.expect(12);
|
||||
|
||||
const pyEnv = await startServer();
|
||||
const [mailMessageId1, mailMessageId2] = pyEnv['mail.message'].create([
|
||||
// first message that is expected to have a failure
|
||||
{
|
||||
message_type: 'sms', // message must be sms (goal of the test)
|
||||
model: 'res.partner', // same model as second message (and not `mail.channel`)
|
||||
res_id: 31, // different res_id from second message
|
||||
res_model_name: "Partner", // random related model name
|
||||
},
|
||||
// second message that is expected to have a failure
|
||||
{
|
||||
message_type: 'sms', // message must be sms (goal of the test)
|
||||
model: 'res.partner', // same model as first message (and not `mail.channel`)
|
||||
res_id: 32, // different res_id from first message
|
||||
res_model_name: "Partner", // same related model name for consistency
|
||||
},
|
||||
]);
|
||||
pyEnv['mail.notification'].create([
|
||||
// first failure that is expected to be used in the test
|
||||
{
|
||||
mail_message_id: mailMessageId1, // id of the related first message
|
||||
notification_status: 'exception', // necessary value to have a failure
|
||||
notification_type: 'sms', // expected failure type for sms message
|
||||
},
|
||||
// second failure that is expected to be used in the test
|
||||
{
|
||||
mail_message_id: mailMessageId2, // id of the related second message
|
||||
notification_status: 'exception', // necessary value to have a failure
|
||||
notification_type: 'sms', // expected failure type for sms message
|
||||
},
|
||||
]);
|
||||
const { click, env } = await start();
|
||||
patchWithCleanup(env.services.action, {
|
||||
doAction(action) {
|
||||
assert.step('do_action');
|
||||
assert.strictEqual(
|
||||
action.name,
|
||||
"SMS Failures",
|
||||
"action should have 'SMS Failures' as name",
|
||||
);
|
||||
assert.strictEqual(
|
||||
action.type,
|
||||
'ir.actions.act_window',
|
||||
"action should have the type act_window"
|
||||
);
|
||||
assert.strictEqual(
|
||||
action.view_mode,
|
||||
'kanban,list,form',
|
||||
"action should have 'kanban,list,form' as view_mode"
|
||||
);
|
||||
assert.strictEqual(
|
||||
JSON.stringify(action.views),
|
||||
JSON.stringify([[false, 'kanban'], [false, 'list'], [false, 'form']]),
|
||||
"action should have correct views"
|
||||
);
|
||||
assert.strictEqual(
|
||||
action.target,
|
||||
'current',
|
||||
"action should have 'current' as target"
|
||||
);
|
||||
assert.strictEqual(
|
||||
action.res_model,
|
||||
'res.partner',
|
||||
"action should have the group model as res_model"
|
||||
);
|
||||
assert.strictEqual(
|
||||
JSON.stringify(action.domain),
|
||||
JSON.stringify([['message_has_sms_error', '=', true]]),
|
||||
"action should have 'message_has_sms_error' as domain"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
await click('.o_MessagingMenu_toggler');
|
||||
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_NotificationGroup',
|
||||
"should have 1 notification group"
|
||||
);
|
||||
assert.containsOnce(
|
||||
document.body,
|
||||
'.o_NotificationGroup_counter',
|
||||
"should have 1 group counter"
|
||||
);
|
||||
assert.strictEqual(
|
||||
document.querySelector('.o_NotificationGroup_counter').textContent.trim(),
|
||||
"(2)",
|
||||
"should have 2 notifications in the group"
|
||||
);
|
||||
|
||||
document.querySelector('.o_NotificationGroup').click();
|
||||
assert.verifySteps(
|
||||
['do_action'],
|
||||
"should do an action to display the related records"
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
import { click, editInput, getFixture, patchWithCleanup } from "@web/../tests/helpers/utils";
|
||||
|
||||
let serverData;
|
||||
let target;
|
||||
|
||||
QUnit.module(
|
||||
"fields",
|
||||
{
|
||||
beforeEach: function () {
|
||||
serverData = {
|
||||
models: {
|
||||
partner: {
|
||||
fields: {
|
||||
message: { string: "message", type: "text" },
|
||||
foo: { string: "Foo", type: "char", default: "My little Foo Value" },
|
||||
mobile: { string: "mobile", type: "text" },
|
||||
},
|
||||
records: [
|
||||
{
|
||||
id: 1,
|
||||
message: "",
|
||||
foo: "yop",
|
||||
mobile: "+32494444444",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
message: "",
|
||||
foo: "bayou",
|
||||
},
|
||||
],
|
||||
},
|
||||
visitor: {
|
||||
fields: {
|
||||
mobile: { string: "mobile", type: "text" },
|
||||
},
|
||||
records: [
|
||||
{
|
||||
id: 1,
|
||||
mobile: "+32494444444",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
setupViewRegistries();
|
||||
target = getFixture();
|
||||
},
|
||||
},
|
||||
function () {
|
||||
QUnit.module("SmsButton");
|
||||
|
||||
QUnit.test("Sms button in form view", async function (assert) {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "visitor",
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: /* xml */ `
|
||||
<form>
|
||||
<sheet>
|
||||
<field name="mobile" widget="phone"/>
|
||||
</sheet>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
assert.containsOnce(
|
||||
target.querySelector(".o_field_phone"),
|
||||
".o_field_phone_sms",
|
||||
"the button is present"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("Sms button with option enable_sms set as False", async function (assert) {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "visitor",
|
||||
resId: 1,
|
||||
serverData,
|
||||
mode: "readonly",
|
||||
arch: /* xml */ `
|
||||
<form>
|
||||
<sheet>
|
||||
<field name="mobile" widget="phone" options="{'enable_sms': false}"/>
|
||||
</sheet>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
assert.containsNone(
|
||||
target.querySelector(".o_field_phone"),
|
||||
".o_field_phone_sms",
|
||||
"the button is not present"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"click on the sms button while creating a new record in a FormView",
|
||||
async function (assert) {
|
||||
const form = await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: /* xml */ `
|
||||
<form>
|
||||
<sheet>
|
||||
<field name="foo"/>
|
||||
<field name="mobile" widget="phone"/>
|
||||
</sheet>
|
||||
</form>`,
|
||||
});
|
||||
patchWithCleanup(form.env.services.action, {
|
||||
doAction: (action, options) => {
|
||||
assert.strictEqual(action.type, "ir.actions.act_window");
|
||||
assert.strictEqual(action.res_model, "sms.composer");
|
||||
options.onClose();
|
||||
},
|
||||
});
|
||||
await editInput(target, "[name='foo'] input", "John");
|
||||
await editInput(target, "[name='mobile'] input", "+32494444411");
|
||||
|
||||
await click(target, ".o_field_phone_sms", true);
|
||||
assert.strictEqual(target.querySelector("[name='foo'] input").value, "John");
|
||||
assert.strictEqual(
|
||||
target.querySelector("[name='mobile'] input").value,
|
||||
"+32494444411"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
QUnit.test(
|
||||
"click on the sms button in a FormViewDialog has no effect on the main form view",
|
||||
async function (assert) {
|
||||
serverData.models.partner.fields.partner_ids = {
|
||||
string: "one2many partners field",
|
||||
type: "one2many",
|
||||
relation: "partner",
|
||||
};
|
||||
|
||||
const form = await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: /* xml */ `
|
||||
<form>
|
||||
<sheet>
|
||||
<field name="foo"/>
|
||||
<field name="mobile" widget="phone"/>
|
||||
<field name="partner_ids">
|
||||
<kanban>
|
||||
<field name="display_name"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div><t t-esc="record.display_name"/></div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</sheet>
|
||||
</form>`,
|
||||
});
|
||||
patchWithCleanup(form.env.services.action, {
|
||||
doAction: (action, options) => {
|
||||
assert.strictEqual(action.type, "ir.actions.act_window");
|
||||
assert.strictEqual(action.res_model, "sms.composer");
|
||||
options.onClose();
|
||||
},
|
||||
});
|
||||
await editInput(target, "[name='foo'] input", "John");
|
||||
await editInput(target, "[name='mobile'] input", "+32494444411");
|
||||
|
||||
await click(target, "[name='partner_ids'] .o-kanban-button-new");
|
||||
assert.containsOnce(target, ".modal");
|
||||
|
||||
const modal = target.querySelector(".modal");
|
||||
await editInput(modal, "[name='foo'] input", "Max");
|
||||
await editInput(modal, "[name='mobile'] input", "+324955555");
|
||||
|
||||
await click(modal, ".o_field_phone_sms", true);
|
||||
assert.strictEqual(modal.querySelector("[name='foo'] input").value, "Max");
|
||||
assert.strictEqual(
|
||||
modal.querySelector("[name='mobile'] input").value,
|
||||
"+324955555"
|
||||
);
|
||||
|
||||
await click(modal, ".o_form_button_cancel");
|
||||
assert.strictEqual(target.querySelector("[name='foo'] input").value, "John");
|
||||
assert.strictEqual(
|
||||
target.querySelector("[name='mobile'] input").value,
|
||||
"+32494444411"
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
225
odoo-bringout-oca-ocb-sms/sms/static/tests/sms_widget_test.js
Normal file
225
odoo-bringout-oca-ocb-sms/sms/static/tests/sms_widget_test.js
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import FormView from 'web.FormView';
|
||||
import ListView from 'web.ListView';
|
||||
import testUtils from 'web.test_utils';
|
||||
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
import { getFixture } from "@web/../tests/helpers/utils";
|
||||
|
||||
const createView = testUtils.createView;
|
||||
|
||||
QUnit.module('fields', {
|
||||
beforeEach: function () {
|
||||
this.data = {
|
||||
partner: {
|
||||
fields: {
|
||||
message: {string: "message", type: "text"},
|
||||
foo: {string: "Foo", type: "char", default: "My little Foo Value"},
|
||||
mobile: {string: "mobile", type: "text"},
|
||||
},
|
||||
records: [{
|
||||
id: 1,
|
||||
message: "",
|
||||
foo: 'yop',
|
||||
mobile: "+32494444444",
|
||||
}, {
|
||||
id: 2,
|
||||
message: "",
|
||||
foo: 'bayou',
|
||||
}]
|
||||
},
|
||||
visitor: {
|
||||
fields: {
|
||||
mobile: {string: "mobile", type: "text"},
|
||||
},
|
||||
records: [{
|
||||
id: 1,
|
||||
mobile: "+32494444444",
|
||||
}]
|
||||
},
|
||||
};
|
||||
setupViewRegistries();
|
||||
this.target = getFixture();
|
||||
}
|
||||
}, function () {
|
||||
|
||||
QUnit.module('SmsWidget');
|
||||
|
||||
QUnit.test('Sms widgets are correctly rendered', async function (assert) {
|
||||
assert.expect(9);
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData: { models: this.data },
|
||||
arch: /* xml */ `<form><sheet><field name="message" widget="sms_widget"/></sheet></form>`,
|
||||
});
|
||||
|
||||
assert.containsOnce(this.target, '.o_sms_count', "Should have a sms counter");
|
||||
assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '0 characters, fits in 0 SMS (GSM7) ',
|
||||
'Should be "0 characters, fits in 0 SMS (GSM7) " by default');
|
||||
// GSM-7
|
||||
await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), "Hello from Odoo", 'input');
|
||||
assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '15 characters, fits in 1 SMS (GSM7) ',
|
||||
'Should be "15 characters, fits in 1 SMS (GSM7) " for "Hello from Odoo"');
|
||||
// GSM-7 with \n => this one count as 2 characters
|
||||
await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), "Hello from Odoo\n", 'input');
|
||||
assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '17 characters, fits in 1 SMS (GSM7) ',
|
||||
'Should be "17 characters, fits in 1 SMS (GSM7) " for "Hello from Odoo\\n"');
|
||||
// Unicode => ê
|
||||
await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), "Hêllo from Odoo", 'input');
|
||||
assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '15 characters, fits in 1 SMS (UNICODE) ',
|
||||
'Should be "15 characters, fits in 1 SMS (UNICODE) " for "Hêllo from Odoo"');
|
||||
// GSM-7 with 160c
|
||||
var text = Array(161).join('a');
|
||||
await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), text, 'input');
|
||||
assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '160 characters, fits in 1 SMS (GSM7) ',
|
||||
'Should be "160 characters, fits in 1 SMS (GSM7) " for 160 x "a"');
|
||||
// GSM-7 with 161c
|
||||
text = Array(162).join('a');
|
||||
await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), text, 'input');
|
||||
assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '161 characters, fits in 2 SMS (GSM7) ',
|
||||
'Should be "161 characters, fits in 2 SMS (GSM7) " for 161 x "a"');
|
||||
// Unicode with 70c
|
||||
text = Array(71).join('ê');
|
||||
await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), text, 'input');
|
||||
assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '70 characters, fits in 1 SMS (UNICODE) ',
|
||||
'Should be "70 characters, fits in 1 SMS (UNICODE) " for 70 x "ê"');
|
||||
// Unicode with 71c
|
||||
text = Array(72).join('ê');
|
||||
await testUtils.fields.editAndTrigger(this.target.querySelector('.o_input'), text, 'input');
|
||||
assert.strictEqual(this.target.querySelector('.o_sms_count').textContent, '71 characters, fits in 2 SMS (UNICODE) ',
|
||||
'Should be "71 characters, fits in 2 SMS (UNICODE) " for 71 x "ê"');
|
||||
|
||||
});
|
||||
|
||||
QUnit.test('Sms widgets with non-empty initial value', async function (assert) {
|
||||
assert.expect(1);
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "visitor",
|
||||
resId: 1,
|
||||
serverData: { models: this.data },
|
||||
arch: /* xml */ `<form><sheet><field name="mobile" widget="sms_widget" readonly="true"/></sheet></form>`,
|
||||
});
|
||||
|
||||
assert.strictEqual(this.target.querySelector('.o_field_text span').textContent, '+32494444444',
|
||||
'Should have the initial value');
|
||||
|
||||
});
|
||||
|
||||
QUnit.test('Sms widgets with empty initial value', async function (assert) {
|
||||
assert.expect(1);
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
resId: 1,
|
||||
serverData: { models: this.data },
|
||||
arch: /* xml */ `<form><sheet><field name="message" widget="sms_widget" readonly="true"/></sheet></form>`,
|
||||
});
|
||||
|
||||
assert.strictEqual(this.target.querySelector('.o_field_text span').textContent, '',
|
||||
'Should have the empty initial value');
|
||||
|
||||
});
|
||||
|
||||
QUnit.module('PhoneWidget');
|
||||
|
||||
QUnit.test('phone field in editable list view on normal screens', async function (assert) {
|
||||
assert.expect(11);
|
||||
var doActionCount = 0;
|
||||
|
||||
var list = await createView({
|
||||
View: ListView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
debug:true,
|
||||
arch: '<tree editable="bottom"><field name="foo" widget="phone"/></tree>',
|
||||
intercepts: {
|
||||
do_action(ev) {
|
||||
assert.equal(ev.data.action.res_model, 'sms.composer',
|
||||
'The action to send an SMS should have been executed');
|
||||
doActionCount += 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
assert.containsN(list, 'tbody td:not(.o_list_record_selector)', 4);
|
||||
assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'yopSMS',
|
||||
"value should be displayed properly with a link to send SMS");
|
||||
|
||||
assert.containsN(list, 'div.o_field_widget.o_form_uri.o_field_phone > a', 2,
|
||||
"should have the correct classnames");
|
||||
|
||||
// Edit a line and check the result
|
||||
var $cell = list.$('tbody td:not(.o_list_record_selector)').first();
|
||||
await testUtils.dom.click($cell);
|
||||
assert.hasClass($cell.parent(),'o_selected_row', 'should be set as edit mode');
|
||||
assert.strictEqual($cell.find('input').val(), 'yop',
|
||||
'should have the corect value in internal input');
|
||||
await testUtils.fields.editInput($cell.find('input'), 'new');
|
||||
|
||||
// save
|
||||
await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
|
||||
$cell = list.$('tbody td:not(.o_list_record_selector)').first();
|
||||
assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode anymore');
|
||||
assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'newSMS',
|
||||
"value should be properly updated");
|
||||
assert.containsN(list, 'div.o_field_widget.o_form_uri.o_field_phone > a', 2,
|
||||
"should still have links with correct classes");
|
||||
|
||||
await testUtils.dom.click(list.$('tbody td:not(.o_list_record_selector) .o_field_phone_sms').first());
|
||||
assert.equal(doActionCount, 1, 'Only one action should have been executed');
|
||||
assert.containsNone(list, '.o_selected_row',
|
||||
'None of the list element should have been activated');
|
||||
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('readonly sms phone field is properly rerendered after been changed by onchange', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
const NEW_PHONE = '+32595555555';
|
||||
|
||||
const form = await createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<sheet>' +
|
||||
'<group>' +
|
||||
'<field name="foo" on_change="1"/>' + // onchange to update mobile in readonly mode directly
|
||||
'<field name="mobile" widget="phone" readonly="1"/>' + // readonly only, we don't want to go through write mode
|
||||
'</group>' +
|
||||
'</sheet>' +
|
||||
'</form>',
|
||||
res_id: 1,
|
||||
viewOptions: {mode: 'edit'},
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'onchange') {
|
||||
return Promise.resolve({
|
||||
value: {
|
||||
mobile: NEW_PHONE, // onchange to update mobile in readonly mode directly
|
||||
},
|
||||
});
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
// check initial rendering
|
||||
assert.strictEqual(form.$('.o_field_phone').text(), "+32494444444",
|
||||
'Initial Phone text should be set');
|
||||
assert.strictEqual(form.$('.o_field_phone_sms').text(), 'SMS',
|
||||
'SMS button label should be rendered');
|
||||
|
||||
// trigger the onchange to update phone field, but still in readonly mode
|
||||
await testUtils.fields.editInput($('input[name="foo"]'), 'someOtherFoo');
|
||||
|
||||
// check rendering after changes
|
||||
assert.strictEqual(form.$('.o_field_phone').text(), NEW_PHONE,
|
||||
'Phone text should be updated');
|
||||
assert.strictEqual(form.$('.o_field_phone_sms').text(), 'SMS',
|
||||
'SMS button label should not be changed');
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue