mirror of
https://github.com/bringout/oca-ocb-mail.git
synced 2026-04-20 19:42:00 +02:00
19.0 vanilla
This commit is contained in:
parent
5df8c07b59
commit
daa394e8b0
2114 changed files with 564841 additions and 299642 deletions
|
|
@ -1,71 +0,0 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
import { patchWithCleanup } from "@web/../tests/helpers/utils";
|
||||
import { createWebClient, doAction } from "@web/../tests/webclient/helpers";
|
||||
import { MassMailingFullWidthViewController } from "@mass_mailing/js/mailing_mailing_view_form_full_width";
|
||||
|
||||
let serverData;
|
||||
|
||||
QUnit.module("mass_mailing", {}, function () {
|
||||
QUnit.module("MassMailingFullWidthViewController", (hooks) => {
|
||||
hooks.beforeEach(() => {
|
||||
serverData = {
|
||||
models: {
|
||||
partner: {
|
||||
fields: {
|
||||
display_name: { string: "Displayed name", type: "char" },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
1: {
|
||||
id: 1,
|
||||
name: "test",
|
||||
res_model: "partner",
|
||||
type: "ir.actions.act_window",
|
||||
views: [[false, "form"]],
|
||||
},
|
||||
2: {
|
||||
id: 2,
|
||||
name: "test",
|
||||
res_model: "partner",
|
||||
type: "ir.actions.act_window",
|
||||
views: [[false, "list"]],
|
||||
},
|
||||
},
|
||||
|
||||
views: {
|
||||
"partner,false,form": `<form js_class="mailing_mailing_view_form_full_width">
|
||||
<field name="display_name"/>
|
||||
</form>`,
|
||||
"partner,false,list": `<tree><field name="display_name"/></tree>`,
|
||||
"partner,false,search": `<search/>`,
|
||||
},
|
||||
};
|
||||
|
||||
setupViewRegistries();
|
||||
});
|
||||
|
||||
QUnit.test("unregister ResizeObserver on unmount", async (assert) => {
|
||||
patchWithCleanup(MassMailingFullWidthViewController.prototype, {
|
||||
setup() {
|
||||
this._super();
|
||||
patchWithCleanup(this._resizeObserver, {
|
||||
disconnect() {
|
||||
assert.step("disconnect");
|
||||
return this._super(...arguments);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const webClient = await createWebClient({ serverData });
|
||||
await doAction(webClient, 1);
|
||||
assert.verifySteps([]);
|
||||
await doAction(webClient, 2);
|
||||
assert.verifySteps(["disconnect"]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,448 @@
|
|||
import { expect, test, describe } from "@odoo/hoot";
|
||||
import {
|
||||
defineModels,
|
||||
fields,
|
||||
models,
|
||||
mountView,
|
||||
onRpc,
|
||||
contains,
|
||||
clickSave,
|
||||
MockServer,
|
||||
} from "@web/../tests/web_test_helpers";
|
||||
import { queryFirst } from "@odoo/hoot-dom";
|
||||
import { animationFrame } from "@odoo/hoot-mock";
|
||||
import { defineMailModels } from "@mail/../tests/mail_test_helpers";
|
||||
|
||||
class Mailing extends models.Model {
|
||||
_name = "mailing.mailing";
|
||||
|
||||
display_name = fields.Char();
|
||||
subject = fields.Char();
|
||||
mailing_model_id = fields.Many2one({ relation: "ir.model", string: "Recipients" });
|
||||
mailing_model_name = fields.Char({ string: "Recipients Model Name" });
|
||||
mailing_filter_id = fields.Many2one({ relation: "mailing.filter", string: "Filters" });
|
||||
mailing_domain = fields.Char({ string: "Domain" });
|
||||
mailing_filter_domain = fields.Char({ related: "mailing_domain", string: "Domain" });
|
||||
mailing_filter_count = fields.Integer({ string: "Filter Count" });
|
||||
|
||||
_records = [
|
||||
{
|
||||
id: 1,
|
||||
display_name: "Belgian Event promotion",
|
||||
subject: "Early bird discount for Belgian Events! Register Now!",
|
||||
mailing_model_id: 1,
|
||||
mailing_model_name: "event",
|
||||
mailing_domain: '[["country","=","be"]]',
|
||||
mailing_filter_id: 1,
|
||||
mailing_filter_count: 1,
|
||||
mailing_filter_domain: '[["country","=","be"]]',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
display_name: "New Users Promotion",
|
||||
subject: "Early bird discount for new users! Register Now!",
|
||||
mailing_model_id: 1,
|
||||
mailing_filter_count: 1,
|
||||
mailing_model_name: "event",
|
||||
mailing_domain: '[["new_user","=",True]]',
|
||||
mailing_filter_domain: '[["new_user","=",True]]',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
class IrModel extends models.Model {
|
||||
_name = "ir.model";
|
||||
|
||||
name = fields.Char();
|
||||
model = fields.Char();
|
||||
|
||||
_records = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Event",
|
||||
model: "event",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Partner",
|
||||
model: "partner",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
class MailingFilter extends models.Model {
|
||||
_name = "mailing.filter";
|
||||
|
||||
name = fields.Char();
|
||||
mailing_domain = fields.Char();
|
||||
mailing_model_id = fields.Many2one({ relation: "ir.model", string: "Recipients Model" });
|
||||
|
||||
_records = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Belgian Events",
|
||||
mailing_domain: '[["country","=","be"]]',
|
||||
mailing_model_id: 1,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
class Partner extends models.Model {
|
||||
_name = "partner";
|
||||
|
||||
name = fields.Char();
|
||||
|
||||
_records = [
|
||||
{ id: 1, name: "Azure Interior" },
|
||||
{ id: 2, name: "Acme Corporation" },
|
||||
{ id: 3, name: "Marc Demo" },
|
||||
];
|
||||
}
|
||||
|
||||
class Event extends models.Model {
|
||||
_name = "event";
|
||||
|
||||
name = fields.Char();
|
||||
country = fields.Char();
|
||||
|
||||
_records = [{ id: 1, name: "BE Event", country: "be" }];
|
||||
}
|
||||
|
||||
defineMailModels();
|
||||
defineModels([IrModel, Mailing, MailingFilter, Partner, Event]);
|
||||
|
||||
describe.current.tags("desktop");
|
||||
|
||||
test("create favorite filter", async () => {
|
||||
expect.assertions(8);
|
||||
|
||||
onRpc("mailing.filter", "create", (params) => {
|
||||
expect(params.args[0]).toEqual([
|
||||
{
|
||||
mailing_domain: '[["new_user","=",True]]',
|
||||
mailing_model_id: 1,
|
||||
name: "event promo - new users",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 2,
|
||||
arch: `<form>
|
||||
<field name="display_name"/>
|
||||
<field name="subject"/>
|
||||
<field name="mailing_domain"/>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id"/>
|
||||
<field name="mailing_filter_count"/>
|
||||
<field name="mailing_filter_domain" invisible="1"/>
|
||||
<field name="mailing_filter_id"
|
||||
widget="mailing_filter"
|
||||
options="{'no_create': '1', 'no_open': '1', 'domain_field': 'mailing_domain', 'model': 'mailing_model_id'}"/>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
queryFirst(".o_field_mailing_filter input").autocomplete = "widget";
|
||||
expect(".o_mass_mailing_remove_filter").not.toBeVisible();
|
||||
expect(".o_mass_mailing_save_filter_container").toBeVisible();
|
||||
|
||||
await contains(".o_field_mailing_filter input").click();
|
||||
expect(".o_field_mailing_filter .dropdown li.ui-menu-item").toHaveCount(2);
|
||||
|
||||
await contains(".o_mass_mailing_add_filter").click();
|
||||
await contains(".o_mass_mailing_filter_name").edit("event promo - new users", {
|
||||
confirm: "Enter",
|
||||
});
|
||||
await contains(".o_content").click();
|
||||
|
||||
expect(".o_field_mailing_filter input").toHaveValue("event promo - new users");
|
||||
expect(".o_mass_mailing_remove_filter").toBeVisible();
|
||||
expect(".o_mass_mailing_save_filter_container").not.toBeVisible();
|
||||
await contains(".o_field_mailing_filter input").click();
|
||||
expect(".o_field_mailing_filter .dropdown li.ui-menu-item").toHaveCount(3);
|
||||
await clickSave();
|
||||
});
|
||||
|
||||
test("unlink favorite filter", async () => {
|
||||
expect.assertions(10);
|
||||
|
||||
onRpc("mailing.filter", "unlink", (params) => {
|
||||
expect(params.args[0]).toEqual([1]);
|
||||
});
|
||||
|
||||
onRpc("mailing.mailing", "web_save", (params) => {
|
||||
expect(params.args[1].mailing_filter_id).toBe(false);
|
||||
expect(params.args[1].mailing_domain).toBe('[["country","=","be"]]');
|
||||
});
|
||||
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 1,
|
||||
arch: `<form>
|
||||
<field name="display_name"/>
|
||||
<field name="subject"/>
|
||||
<field name="mailing_domain"/>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id"/>
|
||||
<field name="mailing_filter_count"/>
|
||||
<field name="mailing_filter_domain" invisible="1"/>
|
||||
<field name="mailing_filter_id"
|
||||
widget="mailing_filter"
|
||||
options="{'no_create': '1', 'no_open': '1', 'domain_field': 'mailing_domain', 'model': 'mailing_model_id'}"/>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
expect(".o_field_mailing_filter input").toHaveValue("Belgian Events");
|
||||
expect(".o_mass_mailing_remove_filter").toBeVisible();
|
||||
expect(".o_mass_mailing_save_filter_container").not.toBeVisible();
|
||||
|
||||
await contains(".o_mass_mailing_remove_filter").click();
|
||||
await animationFrame();
|
||||
expect(".o_field_mailing_filter input").toHaveValue("");
|
||||
expect(".o_mass_mailing_remove_filter").not.toBeVisible();
|
||||
expect(".o_mass_mailing_save_filter_container").toBeVisible();
|
||||
|
||||
queryFirst(".o_field_mailing_filter input").autocomplete = "widget";
|
||||
await contains(".o_field_mailing_filter input").click();
|
||||
expect(".o_field_mailing_filter .dropdown li.ui-menu-item.o_m2o_no_result").toHaveCount(1);
|
||||
await clickSave();
|
||||
});
|
||||
|
||||
test("changing filter correctly applies the domain", async () => {
|
||||
MailingFilter._records = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Azure Partner Only",
|
||||
mailing_domain: "[['name','=', 'Azure Interior']]",
|
||||
mailing_model_id: 2,
|
||||
},
|
||||
];
|
||||
|
||||
Mailing._records.push({
|
||||
id: 3,
|
||||
display_name: "Partner Event promotion",
|
||||
subject: "Early bird discount for Partners!",
|
||||
mailing_model_id: 2,
|
||||
mailing_model_name: "partner",
|
||||
mailing_filter_count: 1,
|
||||
mailing_domain: "[['name','!=', 'Azure Interior']]",
|
||||
});
|
||||
|
||||
Mailing._onChanges = {
|
||||
mailing_filter_id(record) {
|
||||
record.mailing_domain = MockServer.env["mailing.filter"].filter(
|
||||
(r) => r.id === record.mailing_filter_id
|
||||
)[0].mailing_domain;
|
||||
},
|
||||
};
|
||||
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 3,
|
||||
arch: `<form>
|
||||
<field name="display_name"/>
|
||||
<field name="subject"/>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id"/>
|
||||
<field name="mailing_filter_count" />
|
||||
<field name="mailing_filter_id" widget="mailing_filter" options="{'no_create': '1', 'no_open': '1', 'domain_field': 'mailing_domain', 'model': 'mailing_model_id'}"/>
|
||||
<group>
|
||||
<field name="mailing_domain" widget="domain" options="{'model': 'mailing_model_name'}"/>
|
||||
</group>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
expect(".o_domain_show_selection_button").toHaveText("2 record(s)");
|
||||
await contains(".o_field_mailing_filter input").click();
|
||||
queryFirst(".o_field_mailing_filter input").autocomplete = "widget";
|
||||
await contains(".o_field_mailing_filter .dropdown li:first-of-type").click();
|
||||
await animationFrame();
|
||||
expect(".o_domain_show_selection_button").toHaveText("1 record(s)");
|
||||
});
|
||||
|
||||
test("filter drop-down and filter icons visibility toggles properly based on filters available", async () => {
|
||||
MailingFilter._records = [
|
||||
{
|
||||
id: 2,
|
||||
name: "Azure partner",
|
||||
mailing_domain: '[["name","=","Azure Interior"]]',
|
||||
mailing_model_id: 2,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Ready Mat partner",
|
||||
mailing_domain: '[["name","=","Ready Mat"]]',
|
||||
mailing_model_id: 2,
|
||||
},
|
||||
];
|
||||
|
||||
Mailing._records = [
|
||||
{
|
||||
id: 1,
|
||||
display_name: "Belgian Event promotion",
|
||||
subject: "Early bird discount for Belgian Events! Register Now!",
|
||||
mailing_model_id: 1,
|
||||
mailing_model_name: "event",
|
||||
mailing_domain: '[["country","=","be"]]',
|
||||
mailing_filter_id: false,
|
||||
mailing_filter_count: 0,
|
||||
},
|
||||
];
|
||||
|
||||
Mailing._onChanges = {
|
||||
mailing_model_id(record) {
|
||||
record.mailing_filter_count = MockServer.env["mailing.filter"].filter(
|
||||
(r) => r.mailing_model_id === record.mailing_model_id
|
||||
).length;
|
||||
},
|
||||
mailing_filter_id(record) {
|
||||
const filterDomain = MockServer.env["mailing.filter"].filter(
|
||||
(r) => r.id === record.mailing_filter_id
|
||||
)[0].mailing_domain;
|
||||
record.mailing_domain = filterDomain;
|
||||
record.mailing_filter_domain = filterDomain;
|
||||
},
|
||||
};
|
||||
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 1,
|
||||
arch: `<form>
|
||||
<field name="display_name"/>
|
||||
<field name="subject"/>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id"/>
|
||||
<field name="mailing_filter_count" />
|
||||
<field name="mailing_filter_id" widget="mailing_filter"
|
||||
options="{'no_create': '1', 'no_open': '1', 'domain_field': 'mailing_domain', 'model': 'mailing_model_id'}"/>
|
||||
<field name="mailing_filter_domain" invisible="1"/>
|
||||
<group>
|
||||
<field name="mailing_domain" widget="domain" options="{'model': 'mailing_model_name'}"/>
|
||||
</group>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
expect(".o_field_mailing_filter .o_input_dropdown").not.toBeVisible();
|
||||
expect(".o_mass_mailing_no_filter").toBeVisible();
|
||||
expect(".o_mass_mailing_save_filter_container").toBeVisible();
|
||||
|
||||
await contains(".o_tree_editor_node_control_panel > button:nth-child(2)").click();
|
||||
expect(".o_field_mailing_filter .o_input_dropdown").not.toBeVisible();
|
||||
expect(".o_mass_mailing_filter_container").not.toBeVisible();
|
||||
|
||||
await contains(".o_field_widget[name='mailing_model_id'] input").click();
|
||||
await contains(".dropdown-item:contains('Partner')").click();
|
||||
expect(".o_field_mailing_filter .o_input_dropdown").toBeVisible();
|
||||
expect(".o_mass_mailing_filter_container").not.toBeVisible();
|
||||
|
||||
await contains(".o_field_mailing_filter input").click();
|
||||
await contains(".dropdown-item:contains('Azure partner')").click();
|
||||
await animationFrame();
|
||||
expect(".o_mass_mailing_remove_filter").toBeVisible();
|
||||
expect(".o_mass_mailing_save_filter_container").not.toBeVisible();
|
||||
|
||||
await contains(".o_tree_editor_node_control_panel > button:nth-child(1)").click();
|
||||
await animationFrame();
|
||||
expect(".o_mass_mailing_save_filter_container").toBeVisible();
|
||||
expect(".o_mass_mailing_remove_filter").not.toBeVisible();
|
||||
});
|
||||
|
||||
test("filter widget does not raise traceback when losing focus with unexpected domain format", async () => {
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 2,
|
||||
arch: `<form>
|
||||
<field name="display_name"/>
|
||||
<field name="subject"/>
|
||||
<field name="mailing_domain"/>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id"/>
|
||||
<field name="mailing_filter_count"/>
|
||||
<field name="mailing_filter_domain" invisible="1"/>
|
||||
<field name="mailing_filter_id"
|
||||
widget="mailing_filter"
|
||||
options="{'no_create': '1', 'no_open': '1', 'domain_field': 'mailing_domain', 'model': 'mailing_model_id'}"/>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
expect(".o_mass_mailing_save_filter_container").toBeVisible();
|
||||
expect(".o_mass_mailing_remove_filter").not.toBeVisible();
|
||||
|
||||
await contains("div[name='mailing_domain'] input").edit("[");
|
||||
await animationFrame();
|
||||
|
||||
expect(".o_mass_mailing_save_filter_container").not.toBeVisible();
|
||||
expect(".o_mass_mailing_remove_filter").not.toBeVisible();
|
||||
});
|
||||
|
||||
test("filter widget works in edit and readonly", async () => {
|
||||
Partner._fields.name.searchable = true;
|
||||
|
||||
MailingFilter._records = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Azure Partner Only",
|
||||
mailing_domain: "[['name','=', 'Azure Interior']]",
|
||||
mailing_model_id: 2,
|
||||
},
|
||||
];
|
||||
|
||||
Mailing._fields.state = fields.Selection({
|
||||
selection: [
|
||||
["draft", "Draft"],
|
||||
["running", "Running"],
|
||||
],
|
||||
});
|
||||
|
||||
Mailing._records.push({
|
||||
id: 3,
|
||||
display_name: "Partner Event promotion",
|
||||
subject: "Early bird discount for Partners!",
|
||||
mailing_model_id: 2,
|
||||
mailing_model_name: "partner",
|
||||
mailing_filter_count: 1,
|
||||
mailing_filter_domain: "[['name','=', 'Azure Interior']]",
|
||||
mailing_filter_id: 1,
|
||||
mailing_domain: "[['name','=', 'Azure Interior']]",
|
||||
state: "draft",
|
||||
});
|
||||
|
||||
Mailing._onChanges = {
|
||||
mailing_filter_id(record) {
|
||||
record.mailing_domain = MockServer.env["mailing.filter"].filter(
|
||||
(r) => r.id === record.mailing_filter_id
|
||||
)[0].mailing_domain;
|
||||
},
|
||||
};
|
||||
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 3,
|
||||
arch: `<form>
|
||||
<field name="display_name"/>
|
||||
<field name="subject"/>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id" readonly="state != 'draft'"/>
|
||||
<field name="mailing_filter_count" />
|
||||
<field name="mailing_filter_id" widget="mailing_filter" options="{'no_create': '1', 'no_open': '1', 'domain_field': 'mailing_domain', 'model': 'mailing_model_id'}"/>
|
||||
<field name="state" widget="statusbar" options="{'clickable' : '1'}"/>
|
||||
<group>
|
||||
<field name="mailing_domain" widget="domain" options="{'model': 'mailing_model_name'}"/>
|
||||
</group>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
expect("div[name='mailing_model_id']").not.toHaveClass("o_readonly_modifier");
|
||||
expect(".o_mass_mailing_save_filter_container").not.toHaveClass("d-none");
|
||||
await contains("button[data-value='running']").click();
|
||||
await animationFrame();
|
||||
expect("div[name='mailing_model_id']").toHaveClass("o_readonly_modifier");
|
||||
expect(".o_mass_mailing_save_filter_container").not.toHaveClass("d-none");
|
||||
});
|
||||
|
|
@ -1,521 +0,0 @@
|
|||
/** @odoo-module alias=mass_mailing.FieldMassMailingFavoriteFilter.test */
|
||||
|
||||
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
import * as testUtils from "@web/../tests/helpers/utils";
|
||||
import weTestUtils from "web_editor.test_utils";
|
||||
|
||||
let fixture;
|
||||
let serverData;
|
||||
|
||||
QUnit.module('mass_mailing_favourite_filter', {}, function () {
|
||||
QUnit.module('favorite filter widget', (hooks) => {
|
||||
hooks.beforeEach(() => {
|
||||
fixture = testUtils.getFixture();
|
||||
const models = weTestUtils.wysiwygData({
|
||||
'mailing.mailing': {
|
||||
fields: {
|
||||
display_name: {
|
||||
string: 'Display name',
|
||||
type: 'char',
|
||||
},
|
||||
subject: {
|
||||
string: 'subject',
|
||||
type: 'char',
|
||||
},
|
||||
mailing_model_id: {
|
||||
string: 'Recipients',
|
||||
type: 'many2one',
|
||||
relation: 'ir.model',
|
||||
},
|
||||
mailing_model_name: {
|
||||
string: 'Recipients Model Name',
|
||||
type: 'char',
|
||||
},
|
||||
mailing_filter_id: {
|
||||
string: 'Filters',
|
||||
type: 'many2one',
|
||||
relation: 'mailing.filter',
|
||||
},
|
||||
mailing_domain: {
|
||||
string: 'Domain',
|
||||
type: 'char',
|
||||
},
|
||||
mailing_filter_domain: {
|
||||
string: 'Domain',
|
||||
type: 'char',
|
||||
related: 'mailing_filter_id.mailing_domain',
|
||||
},
|
||||
mailing_filter_count: {
|
||||
string: 'filter Count',
|
||||
type: 'integer',
|
||||
},
|
||||
},
|
||||
records: [{
|
||||
id: 1,
|
||||
display_name: 'Belgian Event promotion',
|
||||
subject: 'Early bird discount for Belgian Events! Register Now!',
|
||||
mailing_model_id: 1,
|
||||
mailing_model_name: 'event',
|
||||
mailing_domain: '[["country","=","be"]]',
|
||||
mailing_filter_id: 1,
|
||||
mailing_filter_count: 1,
|
||||
mailing_filter_domain: '[["country","=","be"]]',
|
||||
}, {
|
||||
id: 2,
|
||||
display_name: 'New Users Promotion',
|
||||
subject: 'Early bird discount for new users! Register Now!',
|
||||
mailing_model_id: 1,
|
||||
mailing_filter_count: 1,
|
||||
mailing_model_name: 'event',
|
||||
mailing_domain: '[["new_user","=",True]]',
|
||||
mailing_filter_domain: '[["new_user","=",True]]',
|
||||
}],
|
||||
},
|
||||
'ir.model': {
|
||||
fields: {
|
||||
model: {string: 'Model', type: 'char'},
|
||||
},
|
||||
records: [{
|
||||
id: 1, name: 'Event', model: 'event',
|
||||
}, {
|
||||
id: 2, name: 'Partner', model: 'partner',
|
||||
}],
|
||||
},
|
||||
'mailing.filter': {
|
||||
fields: {
|
||||
name: {
|
||||
string: 'Name',
|
||||
type: 'char',
|
||||
},
|
||||
mailing_domain: {
|
||||
string: 'Mailing Domain',
|
||||
type: 'char',
|
||||
},
|
||||
mailing_model_id: {
|
||||
string: 'Recipients Model',
|
||||
type: 'many2one',
|
||||
relation: 'ir.model'
|
||||
},
|
||||
},
|
||||
records: [{
|
||||
id: 1,
|
||||
name: 'Belgian Events',
|
||||
mailing_domain: '[["country","=","be"]]',
|
||||
mailing_model_id: 1,
|
||||
}],
|
||||
},
|
||||
});
|
||||
serverData = { models };
|
||||
setupViewRegistries();
|
||||
});
|
||||
|
||||
QUnit.test('create favorite filter', async (assert) => {
|
||||
assert.expect(8);
|
||||
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 2,
|
||||
serverData,
|
||||
arch: `<form>
|
||||
<field name="display_name"/>
|
||||
<field name="subject"/>
|
||||
<field name="mailing_domain"/>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id"/>
|
||||
<field name="mailing_filter_count"/>
|
||||
<field name="mailing_filter_domain" invisible="1"/>
|
||||
<field name="mailing_filter_id"
|
||||
widget="mailing_filter"
|
||||
options="{'no_create': '1', 'no_open': '1', 'domain_field': 'mailing_domain', 'model': 'mailing_model_id'}"/>
|
||||
</form>`,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'create' && args.model === 'mailing.filter') {
|
||||
assert.deepEqual(args.args,
|
||||
[{mailing_domain: '[["new_user","=",True]]', mailing_model_id: 1, name: 'event promo - new users'}],
|
||||
"should pass correct data in create");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
fixture.querySelector('.o_field_mailing_filter input').autocomplete = 'widget';
|
||||
const $dropdown = fixture.querySelector('.o_field_mailing_filter .dropdown');
|
||||
assert.isNotVisible(fixture.querySelector('.o_mass_mailing_remove_filter'),
|
||||
"should hide the option to remove filter if no filter is set");
|
||||
assert.isVisible(fixture.querySelector('.o_mass_mailing_save_filter_container'),
|
||||
"should have option to save filter if no filter is set");
|
||||
await testUtils.click(fixture.querySelector('.o_field_mailing_filter input'));
|
||||
assert.containsOnce($dropdown, 'li.ui-menu-item',
|
||||
"there should be only one existing filter");
|
||||
// create a new filter
|
||||
await testUtils.click(fixture, '.o_mass_mailing_add_filter');
|
||||
fixture.querySelector('.o_mass_mailing_filter_name').value = 'event promo - new users';
|
||||
// Simulate 'Enter' key, which actually 'clicks' the 'o_mass_mailing_btn_save_filter' btn
|
||||
await testUtils.triggerEvent(fixture, '.o_mass_mailing_filter_name', 'keydown', { key: 'Enter'});
|
||||
|
||||
// check if filter is set correctly
|
||||
assert.strictEqual(
|
||||
fixture.querySelector('.o_field_mailing_filter input').value,
|
||||
'event promo - new users', "saved filter should be set automatically");
|
||||
|
||||
await testUtils.nextTick();
|
||||
assert.isVisible(fixture.querySelector('.o_mass_mailing_remove_filter'),
|
||||
"should have option to remove filter if filter is already set");
|
||||
assert.isNotVisible(fixture.querySelector('.o_mass_mailing_save_filter_container'),
|
||||
"should not have option to save filter if filter is already set");
|
||||
// Ensures input is not focussed otherwise clicking on it will just close the dropdown instead of opening it
|
||||
fixture.querySelector('.o_field_mailing_filter .o_input_dropdown input').blur();
|
||||
await testUtils.click(fixture.querySelector('.o_field_mailing_filter input'));
|
||||
assert.containsN($dropdown, 'li.ui-menu-item', 2,
|
||||
"there should be two existing filters");
|
||||
await testUtils.clickSave(fixture);
|
||||
});
|
||||
|
||||
QUnit.test('unlink favorite filter', async (assert) => {
|
||||
assert.expect(10);
|
||||
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: `<form>
|
||||
<field name="display_name"/>
|
||||
<field name="subject"/>
|
||||
<field name="mailing_domain"/>
|
||||
<field name="mailing_model_id"/>
|
||||
<field name="mailing_filter_domain" invisible="1"/>
|
||||
<field name="mailing_filter_count"/>
|
||||
<field name="mailing_filter_id"
|
||||
widget="mailing_filter"
|
||||
options="{'no_create': '1', 'no_open': '1', 'domain_field': 'mailing_domain', 'model': 'mailing_model_id'}"/>
|
||||
</form>`,
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'unlink' && args.model === 'mailing.filter') {
|
||||
assert.deepEqual(args.args[0], [1], "should pass correct filter ID for deletion");
|
||||
} else if (args.method === 'write' && args.model === 'mailing.mailing') {
|
||||
assert.strictEqual(args.args[1].mailing_filter_id,
|
||||
false, "filter id should be");
|
||||
assert.strictEqual(args.args[1].mailing_domain,
|
||||
'[["country","=","be"]]', "mailing domain should be retained while unlinking filter");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(
|
||||
fixture.querySelector('.o_field_mailing_filter input').value,
|
||||
'Belgian Events', "there should be filter set");
|
||||
assert.isVisible(fixture.querySelector('.o_mass_mailing_remove_filter'),
|
||||
"should have option to remove filter if filter is already set");
|
||||
assert.isNotVisible(fixture.querySelector('.o_mass_mailing_save_filter_container'),
|
||||
"should hide the option to save filter if filter is already set");
|
||||
// unlink filter
|
||||
await testUtils.click(fixture.querySelector('.o_mass_mailing_remove_filter'));
|
||||
assert.strictEqual(
|
||||
fixture.querySelector('.o_field_mailing_filter input').value,
|
||||
'', "filter should be empty");
|
||||
await testUtils.nextTick();
|
||||
assert.isNotVisible(fixture.querySelector('.o_mass_mailing_remove_filter'),
|
||||
"should hide the option to remove filter if no filter is set");
|
||||
assert.isVisible(fixture.querySelector('.o_mass_mailing_save_filter_container'),
|
||||
"should not hide the option to save filter if no filter is set");
|
||||
// check drop-down after filter deletion
|
||||
fixture.querySelector('.o_field_mailing_filter input').autocomplete = 'widget';
|
||||
const $dropdown = fixture.querySelector('.o_field_mailing_filter .dropdown');
|
||||
await testUtils.click(fixture.querySelector('.o_field_mailing_filter input'));
|
||||
assert.containsOnce($dropdown, 'li.ui-menu-item.o_m2o_no_result',
|
||||
"there should be no available filters");
|
||||
await testUtils.clickSave(fixture);
|
||||
});
|
||||
|
||||
QUnit.test('changing filter correctly applies the domain', async (assert) => {
|
||||
assert.expect(2);
|
||||
|
||||
serverData.models.partner = {
|
||||
fields: {
|
||||
name: {string: 'Name', type: 'char', searchable: true},
|
||||
},
|
||||
records: [
|
||||
{id: 1, name: 'Azure Interior'},
|
||||
{id: 2, name: 'Deco Addict'},
|
||||
{id: 3, name: 'Marc Demo'},
|
||||
]
|
||||
};
|
||||
|
||||
serverData.models['mailing.filter'].records = [{
|
||||
id: 1,
|
||||
name: 'Azure Partner Only',
|
||||
mailing_domain: "[['name','=', 'Azure Interior']]",
|
||||
mailing_model_id: 2,
|
||||
}];
|
||||
|
||||
serverData.models['mailing.mailing'].records.push({
|
||||
id: 3,
|
||||
display_name: 'Partner Event promotion',
|
||||
subject: 'Early bird discount for Partners!',
|
||||
mailing_model_id: 2,
|
||||
mailing_model_name: 'partner',
|
||||
mailing_filter_count: 1,
|
||||
mailing_domain: "[['name','!=', 'Azure Interior']]",
|
||||
});
|
||||
|
||||
serverData.models['mailing.mailing'].onchanges = {
|
||||
mailing_filter_id: obj => {
|
||||
obj.mailing_domain = serverData.models['mailing.filter'].records.filter(r => r.id === obj.mailing_filter_id)[0].mailing_domain;
|
||||
},
|
||||
};
|
||||
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 3,
|
||||
serverData,
|
||||
arch: `<form>
|
||||
<field name="display_name"/>
|
||||
<field name="subject"/>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id"/>
|
||||
<field name="mailing_filter_count" />
|
||||
<field name="mailing_filter_id" widget="mailing_filter" options="{'no_create': '1', 'no_open': '1', 'domain_field': 'mailing_domain', 'model': 'mailing_model_id'}"/>
|
||||
<group>
|
||||
<field name="mailing_domain" widget="domain" options="{'model': 'mailing_model_name'}"/>
|
||||
</group>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
assert.equal(fixture.querySelector('.o_domain_show_selection_button').textContent.trim(), '2 record(s)',
|
||||
"default domain should filter 2 records (all but Azure)");
|
||||
|
||||
await testUtils.click(fixture.querySelector('.o_field_mailing_filter input'));
|
||||
fixture.querySelector('.o_field_mailing_filter input').autocomplete = 'widget';
|
||||
const $dropdown = fixture.querySelector('.o_field_mailing_filter .dropdown');
|
||||
await testUtils.click($dropdown.lastElementChild, 'li');
|
||||
assert.equal(fixture.querySelector('.o_domain_show_selection_button').textContent.trim(), '1 record(s)',
|
||||
"applied filter should only display single record (only Azure)");
|
||||
await testUtils.clickSave(fixture);
|
||||
});
|
||||
|
||||
QUnit.test('filter drop-down and filter icons visibility toggles properly based on filters available', async (assert) => {
|
||||
assert.expect(11);
|
||||
|
||||
serverData.models.partner = {
|
||||
fields: {
|
||||
name: {string: 'Name', type: 'char', searchable: true},
|
||||
},
|
||||
records: [
|
||||
{id: 1, name: 'Azure Interior'},
|
||||
]
|
||||
};
|
||||
serverData.models.event = {
|
||||
fields: {
|
||||
name: {string: 'Name', type: 'char', searchable: true},
|
||||
country: {string: 'Country', type: 'char', searchable: true},
|
||||
},
|
||||
records: [
|
||||
{id: 1, name: 'BE Event', country: 'be'},
|
||||
]
|
||||
};
|
||||
|
||||
serverData.models['mailing.filter'].records = [{
|
||||
id: 2,
|
||||
name: 'Azure partner',
|
||||
mailing_domain: '[["name","=","Azure Interior"]]',
|
||||
mailing_model_id: 2,
|
||||
}, {
|
||||
id: 3,
|
||||
name: 'Ready Mat partner',
|
||||
mailing_domain: '[["name","=","Ready Mat"]]',
|
||||
mailing_model_id: 2,
|
||||
}];
|
||||
|
||||
serverData.models['mailing.mailing'].records = [{
|
||||
id: 1,
|
||||
display_name: 'Belgian Event promotion',
|
||||
subject: 'Early bird discount for Belgian Events! Register Now!',
|
||||
mailing_model_id: 1,
|
||||
mailing_model_name: 'event',
|
||||
mailing_domain: '[["country","=","be"]]',
|
||||
mailing_filter_id: false,
|
||||
mailing_filter_count: 0,
|
||||
}];
|
||||
|
||||
serverData.models['mailing.mailing'].onchanges = {
|
||||
mailing_model_id: obj => {
|
||||
obj.mailing_filter_count = serverData.models['mailing.filter'].records.filter(r => r.mailing_model_id === obj.mailing_model_id).length;
|
||||
},
|
||||
mailing_filter_id: obj => {
|
||||
const filterDomain = serverData.models['mailing.filter'].records.filter(r => r.id === obj.mailing_filter_id)[0].mailing_domain;
|
||||
obj.mailing_domain = filterDomain, obj.mailing_filter_domain = filterDomain;
|
||||
},
|
||||
};
|
||||
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: `<form>
|
||||
<field name="display_name"/>
|
||||
<field name="subject"/>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id"/>
|
||||
<field name="mailing_filter_count" />
|
||||
<field name="mailing_filter_id" widget="mailing_filter"
|
||||
options="{'no_create': '1', 'no_open': '1', 'domain_field': 'mailing_domain', 'model': 'mailing_model_id'}"/>
|
||||
<field name="mailing_filter_domain" invisible="1"/>
|
||||
<group>
|
||||
<field name="mailing_domain" widget="domain" options="{'model': 'mailing_model_name'}"/>
|
||||
</group>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
assert.isNotVisible(fixture.querySelector('.o_field_mailing_filter .o_input_dropdown'),
|
||||
"should hide the drop-down to select a filter because there is no filter available for 'Event'");
|
||||
assert.isVisible(fixture.querySelector('.o_mass_mailing_no_filter'),
|
||||
"should show custom message because there is no filter available for 'Event'");
|
||||
assert.isVisible(fixture.querySelector('.o_mass_mailing_save_filter_container'),
|
||||
"should show icon to save the filter because domain is set in the mailing");
|
||||
|
||||
// If domain is not set on mailing and no filter available, both drop-down and icon container are hidden
|
||||
await testUtils.click(fixture.querySelector('.o_domain_delete_node_button'));
|
||||
assert.isNotVisible(fixture.querySelector('.o_field_mailing_filter .o_input_dropdown'),
|
||||
"should not display drop-down because there is still no filter available to select from");
|
||||
assert.isNotVisible(fixture.querySelector('.o_mass_mailing_filter_container'),
|
||||
"should not show filter container because there is no filter available and no domain set in mailing");
|
||||
|
||||
// If domain is not set on mailing but filters available, display drop-down but hide the icon container
|
||||
await testUtils.clickDropdown(fixture, 'mailing_model_id');
|
||||
await testUtils.clickOpenedDropdownItem(fixture, 'mailing_model_id', 'Partner');
|
||||
assert.isVisible(fixture.querySelector('.o_field_mailing_filter .o_input_dropdown'),
|
||||
"should show the drop-down to select a filter because there are filters available for 'Partner'");
|
||||
assert.isNotVisible(fixture.querySelector('.o_mass_mailing_filter_container'),
|
||||
"should not show filter container because there is no filter selected and no domain set in mailing");
|
||||
|
||||
// Save / Remove icons visibility
|
||||
await testUtils.click(fixture.querySelector('.o_field_mailing_filter input'));
|
||||
await testUtils.clickOpenedDropdownItem(fixture, 'mailing_filter_id', 'Azure partner');
|
||||
await testUtils.nextTick();
|
||||
assert.isVisible(fixture.querySelector('.o_mass_mailing_remove_filter'),
|
||||
"should have option to remove filter if filter is selected");
|
||||
assert.isNotVisible(fixture.querySelector('.o_mass_mailing_save_filter_container'),
|
||||
"should not have option to save filter if filter is selected");
|
||||
|
||||
await testUtils.click(fixture.querySelector('.o_domain_add_node_button'));
|
||||
await testUtils.nextTick();
|
||||
assert.isVisible(fixture.querySelector('.o_mass_mailing_save_filter_container'),
|
||||
"should have option to save filter because mailing domain is changed");
|
||||
assert.isNotVisible(fixture.querySelector('.o_mass_mailing_remove_filter'),
|
||||
"should not have option to remove filter because mailing domain is changed");
|
||||
});
|
||||
|
||||
QUnit.test('filter widget does not raise traceback when losing focus with unexpected domain format', async (assert) => {
|
||||
assert.expect(4);
|
||||
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 2,
|
||||
serverData,
|
||||
arch: `<form>
|
||||
<field name="display_name"/>
|
||||
<field name="subject"/>
|
||||
<field name="mailing_domain"/>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id"/>
|
||||
<field name="mailing_filter_count"/>
|
||||
<field name="mailing_filter_domain" invisible="1"/>
|
||||
<field name="mailing_filter_id"
|
||||
widget="mailing_filter"
|
||||
options="{'no_create': '1', 'no_open': '1', 'domain_field': 'mailing_domain', 'model': 'mailing_model_id'}"/>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
// Initial state of icons with no filter
|
||||
assert.isVisible(fixture.querySelector('.o_mass_mailing_save_filter_container'),
|
||||
"should have option to save filter if no filter is set");
|
||||
assert.isNotVisible(fixture.querySelector('.o_mass_mailing_remove_filter'));
|
||||
|
||||
// Set incorrect domain format
|
||||
await testUtils.editInput(fixture, "#mailing_domain", "[");
|
||||
// Wait to lose the focus
|
||||
await testUtils.nextTick();
|
||||
|
||||
assert.isNotVisible(fixture.querySelector('.o_mass_mailing_save_filter_container'),
|
||||
"should not have option to save filter if domain format is incorrect");
|
||||
assert.isNotVisible(fixture.querySelector('.o_mass_mailing_remove_filter'),
|
||||
"should still not be visible");
|
||||
});
|
||||
|
||||
QUnit.test('filter widget works in edit and readonly', async (assert) => {
|
||||
assert.expect(4);
|
||||
|
||||
serverData.models.partner = {
|
||||
fields: {
|
||||
name: { string: 'Name', type: 'char', searchable: true },
|
||||
},
|
||||
};
|
||||
|
||||
serverData.models['mailing.filter'].records = [{
|
||||
id: 1,
|
||||
name: 'Azure Partner Only',
|
||||
mailing_domain: "[['name','=', 'Azure Interior']]",
|
||||
mailing_model_id: 2,
|
||||
}];
|
||||
|
||||
serverData.models['mailing.mailing'].records.push({
|
||||
id: 3,
|
||||
display_name: 'Partner Event promotion',
|
||||
subject: 'Early bird discount for Partners!',
|
||||
mailing_model_id: 2,
|
||||
mailing_model_name: 'partner',
|
||||
mailing_filter_count: 1,
|
||||
mailing_filter_domain: "[['name','=', 'Azure Interior']]",
|
||||
mailing_filter_id: 1,
|
||||
mailing_domain: "[['name','=', 'Azure Interior']]",
|
||||
state: 'draft',
|
||||
});
|
||||
|
||||
serverData.models['mailing.mailing'].fields.state = {
|
||||
string: 'Stage',
|
||||
type: 'selection',
|
||||
selection: [['draft', 'Draft'], ['running', 'Running']]
|
||||
};
|
||||
|
||||
serverData.models['mailing.mailing'].onchanges = {
|
||||
mailing_filter_id: obj => {
|
||||
obj.mailing_domain = serverData.models['mailing.filter'].records.filter(r => r.id === obj.mailing_filter_id)[0].mailing_domain;
|
||||
},
|
||||
};
|
||||
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 3,
|
||||
serverData,
|
||||
arch: `<form>
|
||||
<field name="display_name"/>
|
||||
<field name="subject"/>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="mailing_filter_count" />
|
||||
<field name="mailing_filter_id" widget="mailing_filter" options="{'no_create': '1', 'no_open': '1', 'domain_field': 'mailing_domain', 'model': 'mailing_model_id'}"/>
|
||||
<field name="state" widget="statusbar" options="{'clickable' : '1'}"/>
|
||||
<group>
|
||||
<field name="mailing_domain" widget="domain" options="{'model': 'mailing_model_name'}"/>
|
||||
</group>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
await testUtils.nextTick();
|
||||
const selectField = fixture.querySelector("button[data-value='running']");
|
||||
assert.containsOnce(fixture, "div[name='mailing_model_id']:not(.o_readonly_modifier)");
|
||||
assert.ok(fixture.querySelector(".o_mass_mailing_save_filter_container").checkVisibility());
|
||||
// set to 'running'
|
||||
selectField.dispatchEvent(new Event('click'));
|
||||
selectField.dispatchEvent(new Event('change'));
|
||||
await testUtils.nextTick();
|
||||
assert.containsOnce(fixture, "div[name='mailing_model_id'].o_readonly_modifier");
|
||||
assert.ok(fixture.querySelector(".o_mass_mailing_save_filter_container").checkVisibility());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,521 @@
|
|||
import { expect, test, describe, beforeEach, getFixture } from "@odoo/hoot";
|
||||
import {
|
||||
defineModels,
|
||||
fields,
|
||||
models,
|
||||
mountView,
|
||||
onRpc,
|
||||
clickSave,
|
||||
patchWithCleanup,
|
||||
contains,
|
||||
getPagerValue,
|
||||
getPagerLimit,
|
||||
} from "@web/../tests/web_test_helpers";
|
||||
import { click, queryAny, queryOne, waitFor } from "@odoo/hoot-dom";
|
||||
import { animationFrame, runAllTimers } from "@odoo/hoot-mock";
|
||||
import { defineMailModels } from "@mail/../tests/mail_test_helpers";
|
||||
import { unmockedOrm } from "@web/../tests/_framework/module_set.hoot";
|
||||
import { MassMailingIframe } from "../src/iframe/mass_mailing_iframe";
|
||||
import { MassMailingHtmlField } from "../src/fields/html_field/mass_mailing_html_field";
|
||||
import { FormController } from "@web/views/form/form_controller";
|
||||
|
||||
class Mailing extends models.Model {
|
||||
_name = "mailing.mailing";
|
||||
|
||||
display_name = fields.Char();
|
||||
subject = fields.Char();
|
||||
body_arch = fields.Html();
|
||||
body_html = fields.Html();
|
||||
mailing_model_id = fields.Many2one({ relation: "ir.model", string: "Recipients" });
|
||||
mailing_model_real = fields.Char({
|
||||
string: "Recipients Model Name (real)",
|
||||
compute: "compute_model_real",
|
||||
});
|
||||
mailing_model_name = fields.Char({ string: "Recipients Model Name" });
|
||||
state = fields.Selection({
|
||||
string: "Status",
|
||||
default: "draft",
|
||||
selection: [
|
||||
["draft", "Draft"],
|
||||
["in_queue", "In Queue"],
|
||||
["sending", "Sending"],
|
||||
["done", "Sent"],
|
||||
],
|
||||
});
|
||||
|
||||
compute_model_real() {
|
||||
for (const record of this) {
|
||||
record.mailing_model_real = this.env["ir.model"].browse([
|
||||
record.mailing_model_id,
|
||||
])[0].model;
|
||||
}
|
||||
}
|
||||
|
||||
action_fetch_favorites() {
|
||||
return [];
|
||||
}
|
||||
|
||||
_records = [
|
||||
{
|
||||
id: 1,
|
||||
display_name: "Belgian Event promotion",
|
||||
mailing_model_id: 1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
display_name: "Sent Belgian Event promotion",
|
||||
mailing_model_id: 1,
|
||||
body_arch: `
|
||||
<div data_name="Mailing" class="o_layout oe_unremovable oe_unmovable o_empty_theme">
|
||||
<div class="container o_mail_wrapper o_mail_regular oe_unremovable">
|
||||
<div class="row">
|
||||
<div class="col o_mail_no_options o_mail_wrapper_td bg-white oe_structure o_editable oe_empty" data-editor-message-default="true" data-editor-message="DRAG BUILDING BLOCKS HERE" contenteditable="true">
|
||||
This element <t t-out="'should be inline'"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
state: "done",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
display_name: "Readonly",
|
||||
mailing_model_id: 1,
|
||||
body_arch: `
|
||||
<div data_name="Mailing" class="o_layout oe_unremovable oe_unmovable o_default_theme">
|
||||
<div class="container o_mail_wrapper o_mail_regular oe_unremovable">
|
||||
<div class="row mw-100 mx-0">
|
||||
<div class="col o_mail_no_options o_mail_wrapper_td bg-white oe_structure">
|
||||
<section class="s_text_block o_mail_snippet_general" data-snippet="s_text_block">
|
||||
<div class="container">
|
||||
<p>Readonly</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
state: "done",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
display_name: "Basic",
|
||||
mailing_model_id: 1,
|
||||
body_arch: `
|
||||
<div data_name="Mailing" class="o_layout oe_unremovable oe_unmovable o_basic_theme">
|
||||
<div class="oe_structure">
|
||||
<div class="o_mail_no_options">
|
||||
<p>Basic</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
display_name: "Builder",
|
||||
mailing_model_id: 1,
|
||||
body_arch: `
|
||||
<div data_name="Mailing" class="o_layout oe_unremovable oe_unmovable o_empty_theme">
|
||||
<div class="container o_mail_wrapper o_mail_regular oe_unremovable">
|
||||
<div class="row mw-100 mx-0">
|
||||
<div class="col o_mail_no_options o_mail_wrapper_td bg-white oe_structure">
|
||||
<section class="s_text_block o_mail_snippet_general" data-snippet="s_text_block">
|
||||
<div class="container">
|
||||
<p>Builder</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
class IrUiView extends models.Model {
|
||||
async render_public_asset(template, values) {
|
||||
return unmockedOrm("ir.ui.view", "render_public_asset", [template, values], {});
|
||||
}
|
||||
}
|
||||
|
||||
class IrModel extends models.Model {
|
||||
_name = "ir.model";
|
||||
|
||||
name = fields.Char();
|
||||
display_name = fields.Char();
|
||||
model = fields.Char();
|
||||
|
||||
_records = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Event",
|
||||
display_name: "Event",
|
||||
model: "event",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
class Event extends models.Model {
|
||||
_name = "event";
|
||||
|
||||
name = fields.Char();
|
||||
country = fields.Char();
|
||||
|
||||
_records = [{ id: 1, name: "BE Event", country: "be" }];
|
||||
}
|
||||
|
||||
defineMailModels();
|
||||
defineModels([IrModel, IrUiView, Mailing, Event]);
|
||||
|
||||
const mailViewArch = `
|
||||
<form>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id" invisible="1"/>
|
||||
<field name="mailing_model_real" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="body_html" class="o_mail_body_inline"/>
|
||||
<field name="body_arch" class="o_mail_body_mailing" widget="mass_mailing_html"
|
||||
options="{
|
||||
'inline_field': 'body_html',
|
||||
'dynamic_placeholder': true,
|
||||
'dynamic_placeholder_model_reference_field': 'mailing_model_real'
|
||||
}" readonly="state in ('sending', 'done')"/>
|
||||
</form>
|
||||
`;
|
||||
|
||||
/**
|
||||
* @type {MassMailingHtmlField}
|
||||
*/
|
||||
let htmlField;
|
||||
describe.current.tags("desktop");
|
||||
beforeEach(() => {
|
||||
patchWithCleanup(MassMailingHtmlField.prototype, {
|
||||
setup() {
|
||||
super.setup();
|
||||
htmlField = this;
|
||||
},
|
||||
});
|
||||
});
|
||||
describe("field HTML", () => {
|
||||
beforeEach(() => {
|
||||
patchWithCleanup(MassMailingIframe.prototype, {
|
||||
// Css assets are not needed for these tests.
|
||||
loadIframeAssets() {
|
||||
return {
|
||||
"mass_mailing.assets_iframe_style": {
|
||||
toggle: () => {},
|
||||
},
|
||||
"mass_mailing.assets_inside_basic_editor_iframe": {
|
||||
toggle: () => {},
|
||||
},
|
||||
"mass_mailing.assets_inside_builder_iframe": {
|
||||
toggle: () => {},
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
test("save arch and html", async () => {
|
||||
onRpc("web_save", ({ args }) => {
|
||||
expect(args[1].body_arch).toMatch(/^<div/);
|
||||
expect(args[1].body_html).toMatch(/^<table/);
|
||||
expect.step("web_save mail body");
|
||||
});
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 1,
|
||||
arch: mailViewArch,
|
||||
});
|
||||
expect(queryOne(".o_mass_mailing_iframe_wrapper iframe")).toHaveClass("d-none");
|
||||
await click(
|
||||
waitFor(
|
||||
".o_mailing_template_preview_wrapper div[role='menuitem']:contains(Start From Scratch)"
|
||||
)
|
||||
);
|
||||
await waitFor(".o_mass_mailing_iframe_wrapper iframe:not(.d-none)");
|
||||
expect(await waitFor(":iframe .o_layout", { timeout: 3000 })).toHaveClass("o_empty_theme");
|
||||
await clickSave();
|
||||
await expect.waitForSteps(["web_save mail body"]);
|
||||
});
|
||||
test("t-out field in uneditable mode inline", async () => {
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 2,
|
||||
arch: mailViewArch,
|
||||
});
|
||||
await waitFor(".o_mass_mailing_iframe_wrapper iframe:not(.d-none)");
|
||||
const tElement = await waitFor(":iframe t", { timeout: 3000 });
|
||||
|
||||
// assert that we are in readonly mode (sanity check)
|
||||
expect(":iframe .o_mass_mailing_value.o_readonly").toHaveCount(1);
|
||||
|
||||
// assert that tElement style has inline attibute
|
||||
expect(tElement).toHaveAttribute("data-oe-t-inline", "true");
|
||||
});
|
||||
test("switch out from a notebook tab with html field should update the record", async () => {
|
||||
const arch = `
|
||||
<form>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id" invisible="1"/>
|
||||
<field name="mailing_model_real" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<notebook>
|
||||
<page string="body_arch" name="body_arch">
|
||||
<field name="body_arch" class="o_mail_body_mailing" widget="mass_mailing_html"
|
||||
options="{
|
||||
'inline_field': 'body_html',
|
||||
'dynamic_placeholder': true,
|
||||
'dynamic_placeholder_model_reference_field': 'mailing_model_real'
|
||||
}" readonly="state in ('sending', 'done')"/>
|
||||
</page>
|
||||
<page string="body_html" name="body_html">
|
||||
<field name="body_html" class="o_mail_body_inline" readonly="true"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
`;
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 5,
|
||||
arch,
|
||||
});
|
||||
await waitFor(":iframe .o_layout .container:contains(Builder)", { timeout: 3000 });
|
||||
// ensure conversion of the existing html content
|
||||
await htmlField.commitChanges();
|
||||
const oldConvert = htmlField.converter.convertToEmailHtml;
|
||||
const { promise: conversionDelay, resolve: resumeConversion } = Promise.withResolvers();
|
||||
htmlField.converter.convertToEmailHtml = (fragment, config) =>
|
||||
conversionDelay.then(() => oldConvert(fragment, config));
|
||||
const p = htmlField.editor.editable.querySelector("p");
|
||||
p.append(htmlField.editor.document.createTextNode("Updated"));
|
||||
htmlField.editor.shared.history.addStep();
|
||||
await contains(".o_notebook a[name='body_html']").click();
|
||||
await animationFrame();
|
||||
await waitFor(".o_notebook a[name='body_html']");
|
||||
resumeConversion();
|
||||
expect(
|
||||
(
|
||||
await waitFor(".o_field_widget[name='body_html']:contains(BuilderUpdated)", {
|
||||
timeout: 3000,
|
||||
})
|
||||
).innerText.trim()
|
||||
).toBe("BuilderUpdated");
|
||||
});
|
||||
test("beforeLeave a FormController with html field should save the record", async () => {
|
||||
let formController;
|
||||
patchWithCleanup(FormController.prototype, {
|
||||
setup() {
|
||||
formController = this;
|
||||
super.setup();
|
||||
},
|
||||
});
|
||||
const arch = `
|
||||
<form>
|
||||
<field name="mailing_model_name" invisible="1"/>
|
||||
<field name="mailing_model_id" invisible="1"/>
|
||||
<field name="mailing_model_real" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<notebook>
|
||||
<page string="body_arch" name="body_arch">
|
||||
<field name="body_arch" class="o_mail_body_mailing" widget="mass_mailing_html"
|
||||
options="{
|
||||
'inline_field': 'body_html',
|
||||
'dynamic_placeholder': true,
|
||||
'dynamic_placeholder_model_reference_field': 'mailing_model_real'
|
||||
}" readonly="state in ('sending', 'done')"/>
|
||||
<field name="body_html" class="o_mail_body_inline" readonly="true"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
`;
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 5,
|
||||
arch,
|
||||
});
|
||||
await waitFor(":iframe .o_layout .container:contains(Builder)", { timeout: 3000 });
|
||||
// ensure conversion of the existing html content
|
||||
await htmlField.commitChanges();
|
||||
expect(
|
||||
(
|
||||
await waitFor(".o_field_widget[name='body_html']:contains(Builder)", {
|
||||
timeout: 3000,
|
||||
})
|
||||
).innerText.trim()
|
||||
).toBe("Builder");
|
||||
const p = htmlField.editor.editable.querySelector("p");
|
||||
p.append(htmlField.editor.document.createTextNode("Updated"));
|
||||
htmlField.editor.shared.history.addStep();
|
||||
await formController.beforeLeave();
|
||||
expect(
|
||||
(
|
||||
await waitFor(".o_field_widget[name='body_html']:contains(BuilderUpdated)", {
|
||||
timeout: 3000,
|
||||
})
|
||||
).innerText.trim()
|
||||
).toBe("BuilderUpdated");
|
||||
});
|
||||
test("builder in modal -- owl reconciliation iframe unload", async () => {
|
||||
// Related to ad-hoc fix where in modal, some editor's popovers
|
||||
// get to be spawned before the modal in the DOM and in OWL
|
||||
// When those popovers are killed, OWL tries to reconcile its element List
|
||||
// in OverlayContainer, displaces the node that contains the iframe
|
||||
// and the editor subsequently crashes
|
||||
const base64Img =
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=";
|
||||
onRpc("/html_editor/get_image_info", () => ({
|
||||
original: { image_src: base64Img },
|
||||
}));
|
||||
class SomeModel extends models.Model {
|
||||
_name = "some.model";
|
||||
mailing_ids = fields.One2many({ relation: "mailing.mailing" });
|
||||
|
||||
_records = [
|
||||
{
|
||||
id: 1,
|
||||
mailing_ids: [1],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
Mailing._views["form"] = mailViewArch;
|
||||
defineModels([SomeModel]);
|
||||
const arch = `<form><field name="mailing_ids"> <list><field name="display_name" /></list> </field></form>`;
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "some.model",
|
||||
arch,
|
||||
resId: 1,
|
||||
});
|
||||
await contains(".o_data_cell").click();
|
||||
await waitFor(".o_dialog");
|
||||
await contains(".o_dialog [data-name='event']").click();
|
||||
await waitFor(".o_dialog .o_mass_mailing-builder_sidebar", { timeout: 1000 });
|
||||
await contains(".o_dialog :iframe p", { timeout: 1000 }).click();
|
||||
await waitFor(
|
||||
".o_dialog .o_mass_mailing-builder_sidebar .options-container-header:contains(Text)"
|
||||
);
|
||||
const overlayOptionsSelect =
|
||||
".o-main-components-container .o-overlay-container .o_overlay_options";
|
||||
await waitFor(overlayOptionsSelect + ":has(button[title='Move up'])");
|
||||
await contains(".o_dialog :iframe img").click();
|
||||
await waitFor(overlayOptionsSelect + ":not(:has(button[title='Move up']))");
|
||||
});
|
||||
test("preprocess some domain", async () => {
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 1,
|
||||
arch: mailViewArch,
|
||||
});
|
||||
await click(waitFor(".o_mailing_template_preview_wrapper [data-name='default']"));
|
||||
await waitFor(".o_mass_mailing_iframe_wrapper iframe:not(.d-none)");
|
||||
expect(await waitFor(":iframe .o_layout", { timeout: 3000 })).toHaveClass(
|
||||
"o_default_theme"
|
||||
);
|
||||
await runAllTimers();
|
||||
const section = queryAny(":iframe section");
|
||||
section.dataset.filterDomain = JSON.stringify([["id", "=", 1]]);
|
||||
htmlField.editor.config.onChange({ isPreviewing: false });
|
||||
await click(section);
|
||||
await waitFor(".hb-row .hb-row-label span:contains(Domain)");
|
||||
expect(queryOne(".hb-row span.fa-filter + span").textContent.toLowerCase()).toBe("id = 1");
|
||||
await clickSave();
|
||||
await waitFor("table[t-if]");
|
||||
expect(queryOne("table[t-if]")).toHaveAttribute(
|
||||
"t-if",
|
||||
'object.filtered_domain([("id", "=", 1)])'
|
||||
);
|
||||
});
|
||||
test(`Switching mailing records in the Form view properly switches between basic Editor, HtmlBuilder and readonly`, async () => {
|
||||
const fixture = getFixture();
|
||||
let htmlField;
|
||||
patchWithCleanup(MassMailingHtmlField.prototype, {
|
||||
setup() {
|
||||
super.setup();
|
||||
htmlField = this;
|
||||
},
|
||||
});
|
||||
await mountView({
|
||||
resModel: "mailing.mailing",
|
||||
type: "form",
|
||||
arch: mailViewArch,
|
||||
resIds: [3, 4, 5],
|
||||
resId: 3,
|
||||
});
|
||||
// readonly default
|
||||
expect(await waitFor(":iframe .o_layout", { timeout: 3000 })).toHaveClass(
|
||||
"o_default_theme"
|
||||
);
|
||||
expect(getPagerValue()).toEqual([1]);
|
||||
expect(getPagerLimit()).toBe(3);
|
||||
expect(htmlField.state.activeTheme).toBe("default");
|
||||
expect(fixture.querySelectorAll(".o_mass_mailing-builder_sidebar")).toHaveCount(0);
|
||||
// editable basic
|
||||
await contains(`.o_pager_next`).click();
|
||||
await waitFor(".o_mass_mailing_iframe_wrapper :iframe .o_layout.o_basic_theme:only-child", {
|
||||
timeout: 3000,
|
||||
});
|
||||
expect(getPagerValue()).toEqual([2]);
|
||||
expect(htmlField.state.activeTheme).toBe("basic");
|
||||
expect(fixture.querySelectorAll(".o_mass_mailing-builder_sidebar")).toHaveCount(0);
|
||||
// editable builder
|
||||
await contains(`.o_pager_next`).click();
|
||||
await waitFor(".o_mass_mailing_iframe_wrapper :iframe .o_layout.o_empty_theme:only-child", {
|
||||
timeout: 3000,
|
||||
});
|
||||
expect(getPagerValue()).toEqual([3]);
|
||||
expect(htmlField.state.activeTheme).toBe("empty");
|
||||
expect(fixture.querySelectorAll(".o_mass_mailing-builder_sidebar")).toHaveCount(1);
|
||||
// readonly default
|
||||
await contains(`.o_pager_next`).click();
|
||||
await waitFor(
|
||||
".o_mass_mailing_iframe_wrapper :iframe .o_layout.o_default_theme:only-child",
|
||||
{ timeout: 3000 }
|
||||
);
|
||||
expect(getPagerValue()).toEqual([1]);
|
||||
expect(htmlField.state.activeTheme).toBe("default");
|
||||
expect(fixture.querySelectorAll(".o_mass_mailing-builder_sidebar")).toHaveCount(0);
|
||||
});
|
||||
});
|
||||
describe("field HTML: with loaded assets", () => {
|
||||
test("Ensure style bundles loaded in the `MassMailingIframe` can be toggled On or Off", async () => {
|
||||
await mountView({
|
||||
type: "form",
|
||||
resModel: "mailing.mailing",
|
||||
resId: 1,
|
||||
arch: mailViewArch,
|
||||
});
|
||||
await click(waitFor(".o_mailing_template_preview_wrapper [data-name='default']"));
|
||||
await waitFor(".o_mass_mailing_iframe_wrapper iframe:not(.d-none)");
|
||||
const { bundleControls } = await htmlField.ensureIframeLoaded();
|
||||
|
||||
expect(
|
||||
htmlField.iframeRef.el.contentDocument.head.querySelectorAll(
|
||||
'[href*="mass_mailing.assets_inside_builder_iframe"]'
|
||||
)
|
||||
).toHaveLength(1);
|
||||
|
||||
bundleControls["mass_mailing.assets_inside_builder_iframe"].toggle(false);
|
||||
expect(
|
||||
htmlField.iframeRef.el.contentDocument.head.querySelectorAll(
|
||||
'[href*="mass_mailing.assets_inside_builder_iframe"]'
|
||||
)
|
||||
).toHaveLength(0);
|
||||
|
||||
bundleControls["mass_mailing.assets_inside_builder_iframe"].toggle(true);
|
||||
expect(
|
||||
htmlField.iframeRef.el.contentDocument.head.querySelectorAll(
|
||||
'[href*="mass_mailing.assets_inside_builder_iframe"]'
|
||||
)
|
||||
).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
/** @odoo-module alias=mass_mailing.field_html_tests **/
|
||||
|
||||
import * as ajax from "web.ajax";
|
||||
import weTestUtils from "web_editor.test_utils";
|
||||
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
import {
|
||||
editInput,
|
||||
getFixture,
|
||||
makeDeferred,
|
||||
nextTick,
|
||||
patchWithCleanup,
|
||||
} from "@web/../tests/helpers/utils";
|
||||
import * as legacyTestUtils from "web.test_utils";
|
||||
import { assets } from "@web/core/assets";
|
||||
|
||||
let serverData;
|
||||
let fixture;
|
||||
|
||||
QUnit.module('mass_mailing', {}, function () {
|
||||
QUnit.module('field html', (hooks) => {
|
||||
hooks.beforeEach(() => {
|
||||
fixture = getFixture();
|
||||
const models = weTestUtils.wysiwygData({
|
||||
'mailing.mailing': {
|
||||
fields: {
|
||||
display_name: {
|
||||
string: "Displayed name",
|
||||
type: "char"
|
||||
},
|
||||
body_html: {
|
||||
string: "Message Body inline (to send)",
|
||||
type: "html"
|
||||
},
|
||||
body_arch: {
|
||||
string: "Message Body for edition",
|
||||
type: "html"
|
||||
},
|
||||
},
|
||||
records: [{
|
||||
id: 1,
|
||||
display_name: "first record",
|
||||
body_html: "<div class='field_body' style='background-color: red;'><p>code to edit</p></div>",
|
||||
body_arch: "<div class='field_body'><p>code to edit</p></div>",
|
||||
}],
|
||||
},
|
||||
});
|
||||
serverData = { models };
|
||||
setupViewRegistries();
|
||||
|
||||
legacyTestUtils.mock.patch(ajax, {
|
||||
loadAsset: function (xmlId) {
|
||||
if (xmlId === 'template.assets') {
|
||||
return Promise.resolve({
|
||||
cssLibs: [],
|
||||
cssContents: ['.field_body {background-color: red;}'],
|
||||
jsContents: ['window.odoo = {define: function(){}}; // inline asset'],
|
||||
});
|
||||
}
|
||||
if (xmlId === 'template.assets_all_style') {
|
||||
return Promise.resolve({
|
||||
cssLibs: $('link[href]:not([type="image/x-icon"])').map(function () {
|
||||
return $(this).attr('href');
|
||||
}).get(),
|
||||
cssContents: ['.field_body {background-color: red;}']
|
||||
});
|
||||
}
|
||||
if (xmlId === 'web_editor.wysiwyg_iframe_editor_assets') {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
throw 'Wrong template';
|
||||
},
|
||||
});
|
||||
});
|
||||
hooks.afterEach(() => {
|
||||
legacyTestUtils.mock.unpatch(ajax);
|
||||
});
|
||||
|
||||
QUnit.test('save arch and html', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: 'mailing.mailing',
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: '<form>' +
|
||||
' <field name="body_html" class="oe_read_only"'+
|
||||
' options="{'+
|
||||
' \'cssReadonly\': \'template.assets\','+
|
||||
' }"'+
|
||||
' />'+
|
||||
' <field name="body_arch" class="oe_edit_only" widget="mass_mailing_html"'+
|
||||
' options="{'+
|
||||
' \'snippets\': \'web_editor.snippets\','+
|
||||
' \'cssEdit\': \'template.assets\','+
|
||||
' \'inline-field\': \'body_html\''+
|
||||
' }"'+
|
||||
' />'+
|
||||
'</form>',
|
||||
});
|
||||
await nextTick();
|
||||
let fieldReadonly = fixture.querySelector('.o_field_widget[name="body_html"]');
|
||||
let fieldEdit = fixture.querySelector('.o_field_widget[name="body_arch"]');
|
||||
|
||||
assert.strictEqual($(fieldReadonly).css('display'), 'none', "should hide the readonly mode");
|
||||
assert.strictEqual($(fieldEdit).css('display'), 'block', "should display the edit mode");
|
||||
});
|
||||
|
||||
QUnit.test('component destroyed while loading', async function (assert) {
|
||||
const def = makeDeferred();
|
||||
patchWithCleanup(assets, {
|
||||
loadBundle() {
|
||||
assert.step("loadBundle");
|
||||
return def;
|
||||
}
|
||||
})
|
||||
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: 'mailing.mailing',
|
||||
resId: 1,
|
||||
serverData,
|
||||
arch: `
|
||||
<form>
|
||||
<field name="display_name"/>
|
||||
<field name="body_arch" widget="mass_mailing_html" attrs="{'invisible': [['display_name', '=', 'hide']]}"/>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
assert.containsOnce(fixture, ".o_field_widget[name=body_arch]");
|
||||
await editInput(fixture, ".o_field_widget[name=display_name] input", "hide");
|
||||
assert.containsNone(fixture, ".o_field_widget[name=body_arch]");
|
||||
|
||||
def.resolve();
|
||||
await nextTick();
|
||||
assert.containsNone(fixture, ".o_field_widget[name=body_arch]");
|
||||
assert.verifySteps(["loadBundle"]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
registry.category('web_tour.tours').add('mailing_campaign', {
|
||||
url: '/odoo',
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
content: 'Select the "Email Marketing" app',
|
||||
trigger: '.o_app[data-menu-xmlid="mass_mailing.mass_mailing_menu_root"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: 'Select "Campaings" Navbar item',
|
||||
trigger: '.o_nav_entry[data-menu-xmlid="mass_mailing.menu_email_campaigns"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: 'Select "Newsletter" campaign',
|
||||
trigger: '.o_kanban_record:contains("Newsletter")',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: 'Add a line (create new mailing)',
|
||||
trigger: '.o_field_x2many_list_row_add a',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: 'Pick the basic theme',
|
||||
trigger: ".o_mailing_template_preview_wrapper [data-name='basic']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: ":iframe .o_mass_mailing_value .o_layout",
|
||||
},
|
||||
{
|
||||
content: 'Fill in Subject',
|
||||
trigger: '#subject_0',
|
||||
run: "edit TestFromTour",
|
||||
},
|
||||
{
|
||||
content: 'Fill in Mailing list',
|
||||
trigger: '#contact_list_ids_0',
|
||||
run: "edit Newsletter",
|
||||
},
|
||||
{
|
||||
content: 'Pick "Newsletter" option',
|
||||
trigger: '.o_input_dropdown a:contains(Newsletter)',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: 'Save form',
|
||||
trigger: ".modal .o_form_button_save:contains(Save & Close)",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: "body:not(:has(.modal))",
|
||||
},
|
||||
{
|
||||
content: 'Check that newly created record is on the list',
|
||||
trigger: '[name="mailing_mail_ids"] td[name="subject"]:contains("TestFromTour")',
|
||||
},
|
||||
...stepUtils.saveForm(),
|
||||
],
|
||||
});
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
registry.category("web_tour.tours").add('mailing_editor', {
|
||||
url: '/odoo',
|
||||
steps: () => [stepUtils.showAppsMenuItem(), {
|
||||
trigger: '.o_app[data-menu-xmlid="mass_mailing.mass_mailing_menu_root"]',
|
||||
run: "click",
|
||||
}, {
|
||||
trigger: 'button.o_list_button_add',
|
||||
run: "click",
|
||||
}, {
|
||||
trigger: 'div[name="contact_list_ids"] .o_input_dropdown input[type="text"]',
|
||||
run: "edit Test",
|
||||
}, {
|
||||
trigger: 'div[name="contact_list_ids"] .ui-state-active',
|
||||
run: "click",
|
||||
}, {
|
||||
content: 'choose the theme "empty" to edit the mailing with snippets',
|
||||
trigger: '[name="body_arch"] .o_mailing_template_preview_wrapper [data-name="empty"]',
|
||||
run: "click",
|
||||
}, {
|
||||
content: 'wait for the editor to be rendered',
|
||||
trigger: '[name="body_arch"] :iframe .o_editable[data-editor-message="DRAG BUILDING BLOCKS HERE"]',
|
||||
}, {
|
||||
trigger: '.o_snippet[name="Text"] button',
|
||||
content: 'Click the "Text" snippet category to drop a snippet in the editor',
|
||||
run: "click",
|
||||
}, {
|
||||
trigger: ":iframe .o_snippet_preview_wrap:has(.s_title)",
|
||||
content: "Select the Title Snippet",
|
||||
run: "click",
|
||||
}, {
|
||||
content: 'wait for the snippet menu to finish the drop process',
|
||||
trigger: 'body:not(:has(.o_we_ongoing_insertion))',
|
||||
}, {
|
||||
content: 'verify that the title was inserted properly in the editor',
|
||||
trigger: '[name="body_arch"] :iframe .o_editable h1',
|
||||
}, {
|
||||
trigger: 'button.o_form_button_save',
|
||||
run: "click",
|
||||
}, {
|
||||
content: 'verify that the save failed (since the field "subject" was not set and it is required)',
|
||||
trigger: 'label.o_field_invalid',
|
||||
}, {
|
||||
content: 'verify that the edited mailing body was not lost during the failed save',
|
||||
trigger: '[name="body_arch"] :iframe .o_editable h1',
|
||||
}, {
|
||||
trigger: 'input#subject_0',
|
||||
run: "edit TestFromTour",
|
||||
}, {
|
||||
trigger: '.o_form_view', // blur previous input
|
||||
run: "click",
|
||||
},
|
||||
...stepUtils.saveForm(),
|
||||
{
|
||||
trigger: ':iframe .o_editable',
|
||||
}]});
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
import { boundariesIn } from "@html_editor/utils/position";
|
||||
import { setSelection } from "@html_editor/../tests/tours/helpers/editor";
|
||||
|
||||
registry.category("web_tour.tours").add('mailing_editor_theme', {
|
||||
url: '/odoo',
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
content: "Select the 'Email Marketing' app.",
|
||||
trigger: '.o_app[data-menu-xmlid="mass_mailing.mass_mailing_menu_root"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the create button to create a new mailing.",
|
||||
trigger: 'button.o_list_button_add',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Fill in Subject",
|
||||
trigger: '#subject_0',
|
||||
run: "edit Test Basic Theme",
|
||||
},
|
||||
{
|
||||
content: "Fill in Mailing list",
|
||||
trigger: '#contact_list_ids_0',
|
||||
run: "edit Newsletter",
|
||||
},
|
||||
{
|
||||
content: "Pick 'Newsletter' option",
|
||||
trigger: '.o_input_dropdown a:contains(Newsletter)',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: ".o_mailing_template_preview_wrapper",
|
||||
},
|
||||
{
|
||||
content: "Pick the basic theme",
|
||||
trigger: '.o_mailing_template_preview_wrapper [data-name="basic"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: "html:not(:has(.o_mailing_template_preview_wrapper))",
|
||||
},
|
||||
{
|
||||
content: "Make sure the snippets menu is hidden",
|
||||
trigger: "html:not(:has(.o-snippets-menu))",
|
||||
},
|
||||
...stepUtils.saveForm(),
|
||||
{
|
||||
content: "Click on the New button to create another mailing",
|
||||
trigger: 'button.o_form_button_create',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: ".o_mailing_template_preview_wrapper",
|
||||
},
|
||||
{
|
||||
content: "Fill in Subject",
|
||||
trigger: '#subject_0',
|
||||
run: "edit Test Newsletter Theme",
|
||||
},
|
||||
{
|
||||
content: "Fill in Mailing list",
|
||||
trigger: '#contact_list_ids_0',
|
||||
run: "edit Newsletter",
|
||||
},
|
||||
{
|
||||
content: "Pick 'Newsletter' option",
|
||||
trigger: '.o_input_dropdown a:contains(Newsletter)',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Pick the newsletter theme",
|
||||
trigger: '.o_mailing_template_preview_wrapper [data-name="newsletter"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Make sure the snippets menu is displayed",
|
||||
trigger: ".o-snippets-menu",
|
||||
},
|
||||
...stepUtils.discardForm(),
|
||||
{
|
||||
content: 'Go back to previous mailing',
|
||||
trigger: 'td[name="subject"]:contains(Test Basic Theme)',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Make sure the snippets menu is hidden",
|
||||
trigger: "html:not(:has(.o-snippets-menu))",
|
||||
},
|
||||
{
|
||||
content: "Add some content to be selected afterwards",
|
||||
trigger: ':iframe p',
|
||||
run: "editor content",
|
||||
},
|
||||
{
|
||||
content: "Select text",
|
||||
trigger: ':iframe p:contains(content)',
|
||||
run() {
|
||||
const [anchorNode, anchorOffset, focusNode, focusOffset] = boundariesIn(
|
||||
this.anchor
|
||||
);
|
||||
setSelection({ anchorNode, anchorOffset, focusNode, focusOffset });
|
||||
}
|
||||
},
|
||||
{
|
||||
content: "Make sure the floating toolbar is visible",
|
||||
trigger: '.overlay:has(.o-we-toolbar)[style*="visible"]',
|
||||
},
|
||||
{
|
||||
content: "Expand Toolbar",
|
||||
trigger: ".o-we-toolbar button[name='expand_toolbar']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open the color picker",
|
||||
trigger: ".o-select-color-foreground",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open Solid tab",
|
||||
trigger: ".btn-tab.solid-tab",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Pick a color",
|
||||
trigger: '.o_font_color_selector button[data-color="o-color-1"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Check that color was applied",
|
||||
trigger: ':iframe p font.text-o-color-1',
|
||||
},
|
||||
...stepUtils.saveForm(),
|
||||
{
|
||||
content: "Go to 'Mailings' list view",
|
||||
trigger: '.breadcrumb a:contains(Mailings)',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Open newly created mailing",
|
||||
trigger: 'td:contains("Test Basic Theme")',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Make sure the snippets menu is hidden",
|
||||
trigger: "html:not(:has(.o-snippets-menu))",
|
||||
},
|
||||
{
|
||||
content: "Select content",
|
||||
trigger: ':iframe p:contains(content)',
|
||||
run() {
|
||||
const [anchorNode, anchorOffset, focusNode, focusOffset] = boundariesIn(
|
||||
this.anchor
|
||||
);
|
||||
setSelection({ anchorNode, anchorOffset, focusNode, focusOffset });
|
||||
}
|
||||
},
|
||||
{
|
||||
content: "Make sure the floating toolbar is visible",
|
||||
trigger: '.overlay:has(.o-we-toolbar)[style*="visible"]',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
|
||||
/*
|
||||
* Tour: unsubscribe from a mailing done on documents (aka not on contacts or
|
||||
* mailing lists). We assume email is not member of any mailing list in this test.
|
||||
*/
|
||||
registry.category("web_tour.tours").add('mailing_portal_unsubscribe_from_document', {
|
||||
steps: () => [
|
||||
{
|
||||
content: "Confirmation unsubscribe is done",
|
||||
trigger: "div#o_mailing_subscription_info span:contains('You are no longer part of our services and will not be contacted again.')",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "No warning should be displayed",
|
||||
trigger: "div#o_mailing_subscription_form_blocklisted:not(:has(p:contains('You will not receive any news from those mailing lists you are a member of')))",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Warning will not receive anything anymore",
|
||||
trigger: "div#o_mailing_subscription_form_blocklisted p:contains('You will not hear from us anymore.')",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Feedback textarea not displayed (see data)",
|
||||
trigger: "div#o_mailing_portal_subscription:not(textarea)",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Choose 'Other' reason",
|
||||
trigger: "fieldset label:contains('Other')",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "This should display the Feedback area",
|
||||
trigger: "div#o_mailing_portal_subscription textarea",
|
||||
}, {
|
||||
content: "Write feedback reason",
|
||||
trigger: "textarea[name='feedback']",
|
||||
run: "edit My feedback",
|
||||
}, {
|
||||
content: "Hit Send",
|
||||
trigger: "button#button_feedback",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Confirmation feedback is sent",
|
||||
trigger: "div#o_mailing_subscription_feedback_info span:contains('Sent. Thanks you for your feedback!')",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Revert exclusion list",
|
||||
trigger: "div#button_blocklist_remove",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Confirmation exclusion list is removed",
|
||||
trigger: "div#o_mailing_subscription_update_info span:contains('Email removed from our blocklist')",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Now exclude me (again)",
|
||||
trigger: "div#button_blocklist_add",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Confirmation exclusion is done",
|
||||
trigger: "div#o_mailing_subscription_update_info span:contains('Email added to our blocklist')",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* Tour: unsubscribe from a mailing done on documents (aka not on contacts or
|
||||
* mailing lists). We assume email is member of mailing lists in this test.
|
||||
*/
|
||||
registry.category("web_tour.tours").add('mailing_portal_unsubscribe_from_document_with_lists', {
|
||||
steps: () => [
|
||||
{
|
||||
content: "Confirmation unsubscribe is done",
|
||||
trigger: "div#o_mailing_subscription_info span:contains('You are no longer part of our services and will not be contacted again.')",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Display warning about mailing lists",
|
||||
trigger: "div#o_mailing_subscription_form_blocklisted p:contains('You will not receive any news from those mailing lists you are a member of')",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Warning should contain reference to memberships",
|
||||
trigger: "div#o_mailing_subscription_form_blocklisted li strong:contains('List1')",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Feedback textarea not displayed (see data)",
|
||||
trigger: "div#o_mailing_portal_subscription:not(textarea)",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Choose 'Other' reason",
|
||||
trigger: "fieldset label:contains('Other')",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "This should display the Feedback area",
|
||||
trigger: "div#o_mailing_portal_subscription textarea",
|
||||
}, {
|
||||
content: "Write feedback reason",
|
||||
trigger: "textarea[name='feedback']",
|
||||
run: "edit My feedback",
|
||||
}, {
|
||||
content: "Hit Send",
|
||||
trigger: "button#button_feedback",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Confirmation feedback is sent",
|
||||
trigger: "div#o_mailing_subscription_feedback_info span:contains('Sent. Thanks you for your feedback!')",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Revert exclusion list",
|
||||
trigger: "div#button_blocklist_remove",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Confirmation exclusion list is removed",
|
||||
trigger: "div#o_mailing_subscription_update_info span:contains('Email removed from our blocklist')",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Now exclude me (again)",
|
||||
trigger: "div#button_blocklist_add",
|
||||
run: "click",
|
||||
}, {
|
||||
content: "Confirmation exclusion is done",
|
||||
trigger: "div#o_mailing_subscription_update_info span:contains('Email added to our blocklist')",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
|
||||
/*
|
||||
* Tour: unsubscribe from a mailing done on lists (aka playing with opt-out flag
|
||||
* instead of directly blocking emails).
|
||||
*/
|
||||
registry.category("web_tour.tours").add("mailing_portal_unsubscribe_from_list", {
|
||||
steps: () => [
|
||||
{
|
||||
content: "Confirmation unsubscribe is done",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_info span:contains('You are no longer part of the List1, List2 mailing list')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Feedback textarea not displayed (see data)",
|
||||
trigger: "div#o_mailing_portal_subscription:not(textarea)",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Choose 'Other' reason",
|
||||
trigger: "fieldset label:contains('Other')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Write feedback reason",
|
||||
trigger: "textarea[name='feedback']",
|
||||
run: "edit My feedback",
|
||||
},
|
||||
{
|
||||
content: "Hit Send",
|
||||
trigger: "button#button_feedback",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Confirmation feedback is sent",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_feedback_info span:contains('Sent. Thanks you for your feedback!')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Now exclude me",
|
||||
trigger: "div#button_blocklist_add",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Confirmation exclusion is done",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_update_info span:contains('Email added to our blocklist')",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
/*
|
||||
* Tour: unsubscribe from a mailing done on lists (aka playing with opt-out flag
|
||||
* instead of directly blocking emails), then play with list subscriptions and
|
||||
* blocklist addition / removal. This is mainly an extended version of the tour
|
||||
* hereabove, easing debug and splitting checks.
|
||||
*/
|
||||
registry.category("web_tour.tours").add("mailing_portal_unsubscribe_from_list_with_update", {
|
||||
steps: () => [
|
||||
{
|
||||
content: "Confirmation unsubscribe is done",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_info span:contains('You are no longer part of the List1, List2 mailing list')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List1 is present, just opt-outed",
|
||||
trigger:
|
||||
"ul#o_mailing_subscription_form_lists li.list-group-item:contains('List1') span:contains('Not subscribed')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List3 is present, opt-outed (test starting data)",
|
||||
trigger:
|
||||
"ul#o_mailing_subscription_form_lists li.list-group-item:contains('List3') span:contains('Not subscribed')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List2 is proposed (not member -> proposal to join)",
|
||||
trigger:
|
||||
"ul#o_mailing_subscription_form_lists_additional li.list-group-item:contains('List2')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List4 is not proposed (not member but not private)",
|
||||
trigger:
|
||||
"ul#o_mailing_subscription_form_lists_additional:not(:has(li.list-group-item:contains('List4')))",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Feedback textarea not displayed (see data)",
|
||||
trigger: "div#o_mailing_portal_subscription:not(textarea)",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Choose 'Other' reason",
|
||||
trigger: "fieldset label:contains('Other')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Write feedback reason",
|
||||
trigger: "textarea[name='feedback']",
|
||||
run: "edit My feedback",
|
||||
},
|
||||
{
|
||||
content: "Hit Send",
|
||||
trigger: "button#button_feedback",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Confirmation feedback is sent",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_feedback_info span:contains('Sent. Thanks you for your feedback!')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Now exclude me",
|
||||
trigger: "div#button_blocklist_add",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Confirmation exclusion is done",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_update_info span:contains('Email added to our blocklist')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "This should disable the 'Update my subscriptions' (Apply changes) button",
|
||||
trigger: "div#o_mailing_subscription_blocklist:not(button#button_form_send)",
|
||||
},
|
||||
{
|
||||
content: "Revert exclusion list",
|
||||
trigger: "div#button_blocklist_remove",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Confirmation exclusion list is removed",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_update_info span:contains('Email removed from our blocklist')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "'Update my subscriptions' button usable again",
|
||||
trigger: "button#button_form_send:not([disabled])",
|
||||
},
|
||||
{
|
||||
content: "Choose the mailing list 3 to come back",
|
||||
trigger: "ul#o_mailing_subscription_form_lists input[title='List3']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Add list 2",
|
||||
trigger: "ul#o_mailing_subscription_form_lists_additional input[title='List2']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Update subscription",
|
||||
trigger: "button#button_form_send",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Confirmation changes are done",
|
||||
trigger: "div#o_mailing_subscription_update_info span:contains('Membership updated')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List 3 is noted as subscribed again",
|
||||
trigger:
|
||||
"ul#o_mailing_subscription_form_lists li.list-group-item:contains('List3') span:contains('Subscribed')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List 2 has joined the subscriptions",
|
||||
trigger:
|
||||
"ul#o_mailing_subscription_form_lists li.list-group-item:contains('List2') span:contains('Subscribed')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "No list in proposals",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_form_manage:not(:has(ul#o_mailing_subscription_form_lists_additional))",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: "div#o_mailing_portal_subscription:not(fieldset)",
|
||||
},
|
||||
{
|
||||
content:
|
||||
"Feedback area is not displayed (nothing opt-out or no blocklist done, no feedback required)",
|
||||
trigger: "div#o_mailing_portal_subscription:not(textarea)",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Now exclude me (again)",
|
||||
trigger: "div#button_blocklist_add",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Confirmation exclusion is done",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_update_info span:contains('Email added to our blocklist')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Should display warning about mailing lists",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_form_blocklisted p:contains('You will not receive any news from those mailing lists you are a member of')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: "div#o_mailing_subscription_form_blocklisted li strong:contains('List3')",
|
||||
},
|
||||
{
|
||||
content: "Warning should contain reference to memberships",
|
||||
trigger: "div#o_mailing_subscription_form_blocklisted li strong:contains('List2')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Give a reason for blocklist (first one)",
|
||||
trigger: "fieldset input.o_mailing_subscription_opt_out_reason:first",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Hit Send",
|
||||
trigger: "button#button_feedback",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Confirmation feedback is sent",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_feedback_info span:contains('Sent. Thanks you for your feedback!')",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
|
||||
/*
|
||||
* Tour: use 'my' portal page of mailing to manage mailing lists subscription
|
||||
* as well as manage blocklist (add / remove my own email from block list).
|
||||
*/
|
||||
registry.category("web_tour.tours").add("mailing_portal_unsubscribe_from_my", {
|
||||
steps: () => [
|
||||
{
|
||||
content: "List1 is present, opt-in member",
|
||||
trigger:
|
||||
"ul#o_mailing_subscription_form_lists li.list-group-item:contains('List1') span:contains('Subscribed')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List3 is present, opt-outed (test starting data)",
|
||||
trigger:
|
||||
"ul#o_mailing_subscription_form_lists li.list-group-item:contains('List3') span:contains('Not subscribed')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List2 is proposed (not member -> proposal to join)",
|
||||
trigger:
|
||||
"ul#o_mailing_subscription_form_lists_additional li.list-group-item:contains('List2')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List4 is not proposed (not member but not private)",
|
||||
trigger:
|
||||
"ul#o_mailing_subscription_form_lists_additional:not(:has(li.list-group-item:contains('List4')))",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List5 is not proposed (not member and not public)",
|
||||
trigger: "body:not(:has(li.list-group-item:contains('List5')))",
|
||||
},
|
||||
{
|
||||
trigger: "div#o_mailing_portal_subscription:not(fieldset)",
|
||||
},
|
||||
{
|
||||
content: "Feedback area is not displayed (nothing done, no feedback required)",
|
||||
trigger: "div#o_mailing_portal_subscription:not(textarea)",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List3: come back (choose to opt-in instead of opt-out)",
|
||||
trigger: "ul#o_mailing_subscription_form_lists input[title='List3']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List2: join (opt-in, not already member)",
|
||||
trigger: "ul#o_mailing_subscription_form_lists_additional input[title='List2']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "List1: opt-out",
|
||||
trigger: "ul#o_mailing_subscription_form_lists input[title='List1']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Update subscription",
|
||||
trigger: "button#button_form_send",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Confirmation changes are done",
|
||||
trigger: "div#o_mailing_subscription_update_info span:contains('Membership updated')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: "div#o_mailing_portal_subscription:not(textarea)",
|
||||
},
|
||||
{
|
||||
content:
|
||||
"Should make feedback reasons choice appear (feedback still not displayed, linked to reasons)",
|
||||
trigger: "div#o_mailing_portal_subscription fieldset",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Choose first reason, which should not display feedback (see data)",
|
||||
trigger: "fieldset input.o_mailing_subscription_opt_out_reason:first",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Feedback textarea not displayed (see data)",
|
||||
trigger: "div#o_mailing_portal_subscription:not(textarea)",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Choose 'Other' reason",
|
||||
trigger: "fieldset label:contains('Other')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "This should display the Feedback area",
|
||||
trigger: "div#o_mailing_portal_subscription textarea",
|
||||
},
|
||||
{
|
||||
content: "Write feedback reason",
|
||||
trigger: "textarea[name='feedback']",
|
||||
run: "edit My feedback",
|
||||
},
|
||||
{
|
||||
content: "Hit Send",
|
||||
trigger: "button#button_feedback",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Confirmation feedback is sent",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_feedback_info span:contains('Sent. Thanks you for your feedback!')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: "textarea[disabled]",
|
||||
},
|
||||
{
|
||||
content: "Once sent feedback area is readonly",
|
||||
trigger: "fieldset input.o_mailing_subscription_opt_out_reason[disabled]",
|
||||
},
|
||||
{
|
||||
content: "Now exclude me",
|
||||
trigger: "div#button_blocklist_add",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Confirmation exclusion is done",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_update_info span:contains('Email added to our blocklist')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "This should disable the 'Update my subscriptions' (Apply changes) button",
|
||||
trigger: "div#o_mailing_subscription_blocklist:not(button#button_form_send)",
|
||||
},
|
||||
{
|
||||
content: "This should enabled Feedback again",
|
||||
trigger: "div#o_mailing_portal_subscription textarea",
|
||||
},
|
||||
{
|
||||
content: "Display warning about mailing lists",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_form_blocklisted p:contains('You will not receive any news from those mailing lists you are a member of')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: "div#o_mailing_subscription_form_blocklisted li strong:contains('List3')",
|
||||
},
|
||||
{
|
||||
content: "Warning should contain reference to memberships",
|
||||
trigger: "div#o_mailing_subscription_form_blocklisted li strong:contains('List2')",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Give a reason for blocklist (first one)",
|
||||
trigger: "fieldset input.o_mailing_subscription_opt_out_reason:first",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Hit Send",
|
||||
trigger: "button#button_feedback",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Confirmation feedback is sent",
|
||||
trigger:
|
||||
"div#o_mailing_subscription_feedback_info span:contains('Sent. Thanks you for your feedback!')",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
import { markup } from "@odoo/owl";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
registry.category("web_tour.tours").add('mass_mailing_code_view_tour', {
|
||||
url: '/odoo?debug=tests',
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
trigger: '.o_app[data-menu-xmlid="mass_mailing.mass_mailing_menu_root"]',
|
||||
run: "click",
|
||||
}, {
|
||||
trigger: 'button.o_list_button_add',
|
||||
run: "click",
|
||||
}, {
|
||||
trigger: 'input#subject_0',
|
||||
content: markup('Pick the <b>email subject</b>.'),
|
||||
tooltipPosition: 'bottom',
|
||||
run: "edit Test",
|
||||
}, {
|
||||
trigger: 'div[name="contact_list_ids"] .o_input_dropdown input[type="text"]',
|
||||
content: 'Click on the dropdown to open it and then start typing to search.',
|
||||
run: "edit Test"
|
||||
}, {
|
||||
trigger: 'div[name="contact_list_ids"] .ui-state-active',
|
||||
content: 'Select item from dropdown',
|
||||
run: 'click',
|
||||
}, {
|
||||
trigger: 'div[name="body_arch"] .o_mailing_template_preview_wrapper [data-name="default"]',
|
||||
content: markup('Choose this <b>theme</b>.'),
|
||||
run: 'click',
|
||||
}, {
|
||||
trigger: '.o_codeview_btn',
|
||||
content: markup('Click here to switch to <b>code view</b>'),
|
||||
run: 'click'
|
||||
}, {
|
||||
trigger: "textarea.o_codeview",
|
||||
content: "Remove all content from codeview",
|
||||
run: function () {
|
||||
const element = document.querySelector(".o_codeview");
|
||||
element.value = "";
|
||||
},
|
||||
}, {
|
||||
trigger: '.o_codeview_btn',
|
||||
content: markup('Click here to switch back from <b>code view</b>'),
|
||||
run: 'click'
|
||||
}, {
|
||||
trigger: '[name="body_arch"] :iframe .o_mail_wrapper_td',
|
||||
content: 'Verify that the dropable zone was not removed',
|
||||
}, {
|
||||
trigger: ".o_builder_sidebar_open",
|
||||
content: "Wait for the html_builder to be visible",
|
||||
}, {
|
||||
trigger: '.o_snippet[name="Text"] button',
|
||||
content: 'Click the "Text" snippet category to drop a snippet in the editor',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: ".modal-body :iframe .o_snippet_preview_wrap:has(.s_title)",
|
||||
content: "Select the Title Snippet",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: '[name="body_arch"] :iframe .o_editable h1',
|
||||
content: 'Verify that the title was inserted properly in the editor',
|
||||
},
|
||||
...stepUtils.discardForm(),
|
||||
]
|
||||
});
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
registry.category("web_tour.tours").add('mass_mailing_dynamic_placeholder_tour', {
|
||||
url: '/odoo',
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
content: "Select the 'Email Marketing' app.",
|
||||
trigger: '.o_app[data-menu-xmlid="mass_mailing.mass_mailing_menu_root"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the create button to create a new mailing.",
|
||||
trigger: 'button.o_list_button_add',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Fill in Subject",
|
||||
trigger: '#subject_0',
|
||||
run: "edit Test Dynamic Placeholder",
|
||||
},
|
||||
{
|
||||
trigger: ".o_mailing_template_preview_wrapper",
|
||||
},
|
||||
{
|
||||
content: "Pick the basic theme",
|
||||
trigger: '.o_mailing_template_preview_wrapper [data-name="basic"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Insert text inside editable",
|
||||
trigger: ':iframe .odoo-editor-editable',
|
||||
async run(actions) {
|
||||
await actions.editor(`/`);
|
||||
const iframe = document.querySelector("iframe");
|
||||
iframe?.contentDocument?.querySelector(".note-editable").dispatchEvent(
|
||||
new InputEvent("input", {
|
||||
inputType: "insertText",
|
||||
data: "/",
|
||||
})
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "Click on the the dynamic placeholder powerBox options",
|
||||
trigger: '.o-we-command-name:contains("Dynamic Placeholder")',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Check if the dynamic placeholder popover is opened",
|
||||
trigger: "div.o_model_field_selector_popover",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "filter the dph result",
|
||||
trigger: "div.o_model_field_selector_popover_search input[type='text']",
|
||||
run: "edit name",
|
||||
},
|
||||
{
|
||||
content: "Click on the first entry of the dynamic placeholder",
|
||||
trigger: 'div.o_model_field_selector_popover button:contains("Company Name")',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Enter a default value",
|
||||
trigger:
|
||||
'div.o_model_field_selector_popover .o_model_field_selector_default_value_input input[type="text"]',
|
||||
run: "edit defValue",
|
||||
},
|
||||
{
|
||||
content: "Click on the insert button",
|
||||
trigger: "div.o_model_field_selector_popover button:first-child",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Ensure the editable contain the dynamic placeholder t tag",
|
||||
trigger: `:iframe .note-editable.odoo-editor-editable t[t-out="object.company_name"]:contains("defValue")`,
|
||||
},
|
||||
{
|
||||
content: "Discard form changes",
|
||||
trigger: "button.o_form_button_cancel",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Wait for the form view to disappear",
|
||||
trigger: "body:not(:has(.o_form_sheet))",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
registry.category("web_tour.tours").add('snippets_mailing_menu_tabs', {
|
||||
url: '/odoo',
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(), {
|
||||
content: "Select the 'Email Marketing' app.",
|
||||
trigger: '.o_app[data-menu-xmlid="mass_mailing.mass_mailing_menu_root"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the create button to create a new mailing.",
|
||||
trigger: 'button.o_list_button_add',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the 'Start From Scratch' template.",
|
||||
trigger: '.o_mailing_template_preview_wrapper [data-name="empty"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the 'Design' tab.",
|
||||
trigger: 'button[data-name="theme"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Verify that the customize panel is not empty.",
|
||||
trigger: ".o_design_tab:not(:empty)",
|
||||
},
|
||||
{
|
||||
content: "Click on the style tab.",
|
||||
trigger: 'button[data-name="customize"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the 'Design' tab.",
|
||||
trigger: 'button[data-name="theme"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Verify that the customize panel is not empty.",
|
||||
trigger: ".tab-content .o_design_tab:not(:empty)",
|
||||
},
|
||||
...stepUtils.discardForm(),
|
||||
]});
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
registry.category("web_tour.tours").add('snippets_mailing_menu_toolbar', {
|
||||
url: '/odoo',
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(), {
|
||||
content: "Select the 'Email Marketing' app.",
|
||||
trigger: '.o_app[data-menu-xmlid="mass_mailing.mass_mailing_menu_root"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Click on the create button to create a new mailing.",
|
||||
trigger: 'button.o_list_button_add',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Wait for the theme selector to load.",
|
||||
trigger: '.o_mailing_template_preview_wrapper',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Make sure there does not exist a floating toolbar",
|
||||
trigger: "iframe:not(:visible)",
|
||||
run: function () {
|
||||
const iframeDocument = this.anchor.contentDocument;
|
||||
if (iframeDocument.querySelector('#toolbar.oe-floating')) {
|
||||
console.error('There should not be a floating toolbar in the iframe');
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "Make sure the empty template is an option on non-mobile devices.",
|
||||
trigger: '.o_mailing_template_preview_wrapper [data-name="empty"]',
|
||||
},
|
||||
{
|
||||
content: "Click on the default 'welcome' template.",
|
||||
trigger: '.o_mailing_template_preview_wrapper [data-name="default"]',
|
||||
run: "click",
|
||||
},
|
||||
{ // necessary to wait for the cursor to be placed in the first p
|
||||
// and to avoid leaving the page before the selection is added
|
||||
content: "Wait for template selection event to be over.",
|
||||
trigger: ":iframe .odoo-editor-editable .o_editable",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: "Make sure the snippets menu is not hidden",
|
||||
trigger: ".o-snippets-menu",
|
||||
},
|
||||
{
|
||||
content: "Wait for .s_text_block to be populated",
|
||||
trigger: ':iframe .s_text_block p',
|
||||
},
|
||||
{
|
||||
content: "Click and select p block inside the editor",
|
||||
trigger: 'iframe',
|
||||
run: function () {
|
||||
const iframeWindow = this.anchor.contentWindow;
|
||||
const iframeDocument = iframeWindow.document;
|
||||
const p = iframeDocument.querySelector('.s_text_block p');
|
||||
p.click();
|
||||
const selection = iframeWindow.getSelection();
|
||||
const range = iframeDocument.createRange();
|
||||
range.selectNodeContents(p);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
},
|
||||
},
|
||||
{
|
||||
content: "Make sure the toolbar is there",
|
||||
trigger: ".overlay .o-we-toolbar",
|
||||
},
|
||||
...stepUtils.discardForm(),
|
||||
],
|
||||
});
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
import { registry } from "@web/core/registry";
|
||||
import { stepUtils } from "@web_tour/tour_utils";
|
||||
|
||||
registry.category("web_tour.tours").add('snippets_mailing_menu_toolbar_mobile', {
|
||||
url: '/odoo',
|
||||
steps: () => [
|
||||
stepUtils.showAppsMenuItem(), {
|
||||
content: "Select the 'Email Marketing' app.",
|
||||
trigger: '.o_app[data-menu-xmlid="mass_mailing.mass_mailing_menu_root"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
isActive: ["mobile"],
|
||||
content: "Click on the create button to create a new mailing.",
|
||||
trigger: 'button.o_list_button_add',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
isActive: ["mobile"],
|
||||
content: "Check templates available in theme selector",
|
||||
trigger: '.o_mailing_template_preview_wrapper',
|
||||
run: function () {
|
||||
if (this.anchor.querySelector("#empty")) {
|
||||
console.error('The empty template should not be visible on mobile.');
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
isActive: ["mobile"],
|
||||
content: "Make sure the toolbar isn't floating",
|
||||
trigger: ':iframe',
|
||||
run: function () {
|
||||
const iframeDocument = this.anchor.contentDocument;
|
||||
if (iframeDocument.querySelector('#toolbar.oe-floating')) {
|
||||
console.error('There should not be a floating toolbar in the iframe');
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
isActive: ["mobile"],
|
||||
content: "Click on the 'Start From Scratch' template.",
|
||||
trigger: '.o_mailing_template_preview_wrapper [data-name="default"]',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
isActive: ["mobile"],
|
||||
content: "Select an editable element",
|
||||
trigger: ':iframe .s_text_block',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
isActive: ["mobile"],
|
||||
content: "Make sure the snippets menu is hidden",
|
||||
trigger: ':iframe',
|
||||
run: function () {
|
||||
const iframeDocument = this.anchor.contentDocument;
|
||||
if (iframeDocument.querySelector(".o-snippets-menu")) {
|
||||
console.error('The snippet menu should be hidden');
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
isActive: ["mobile"],
|
||||
content: "Make sure the toolbar is there",
|
||||
trigger: ':iframe #toolbar.oe-floating',
|
||||
},
|
||||
...stepUtils.discardForm().map(command => ({...command, isActive: ["mobile"]})),
|
||||
]
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue