Odoo18-Base/addons/web/static/tests/views/fields/html_field.test.js
2025-01-06 10:57:38 +07:00

335 lines
10 KiB
JavaScript

import {
clickSave,
contains,
defineModels,
fields,
models,
mountView,
onRpc,
serverState,
} from "@web/../tests/web_test_helpers";
import { expect, test } from "@odoo/hoot";
import { animationFrame } from "@odoo/hoot-mock";
import { click, edit, queryAll, queryFirst } from "@odoo/hoot-dom";
import { pointerDown } from "../../../lib/hoot-dom/hoot-dom";
const RED_TEXT = /* html */ `<div class="kek" style="color:red">some text</div>`;
const GREEN_TEXT = /* html */ `<div class="kek" style="color:green">hello</div>`;
const BLUE_TEXT = /* html */ `<div class="kek" style="color:blue">hello world</div>`;
class Partner extends models.Model {
txt = fields.Html({ string: "txt", trim: true });
_records = [{ id: 1, txt: RED_TEXT }];
}
defineModels([Partner]);
test("html fields are correctly rendered in form view (readonly)", async () => {
await mountView({
type: "form",
resModel: "partner",
resId: 1,
arch: /* xml */ `<form><field name="txt" readonly="1" /></form>`,
});
expect("div.kek").toHaveCount(1);
expect(".o_field_html .kek").toHaveStyle({ color: "rgb(255, 0, 0)" });
expect(".o_field_html").toHaveText("some text");
});
test("html field with required attribute", async () => {
await mountView({
type: "form",
resModel: "partner",
resId: 1,
arch: /* xml */ `<form><field name="txt" required="1"/></form>`,
});
expect(".o_field_html textarea").toHaveCount(1, { message: "should have a text area" });
await click(".o_field_html textarea");
await edit("");
await animationFrame();
expect(".o_field_html textarea").toHaveValue("");
await clickSave();
expect(".o_notification_title").toHaveText("Invalid fields:");
expect(queryFirst(".o_notification_content")).toHaveInnerHTML("<ul><li>txt</li></ul>");
});
test("html fields are correctly rendered (edit)", async () => {
onRpc("has_group", () => true);
await mountView({
type: "form",
resModel: "partner",
resId: 1,
arch: /* xml */ `<form><field name="txt" /></form>`,
});
expect(".o_field_html textarea").toHaveCount(1, { message: "should have a text area" });
expect(".o_field_html textarea").toHaveValue(RED_TEXT);
await click(".o_field_html textarea");
await edit(GREEN_TEXT);
await animationFrame();
expect(".o_field_html textarea").toHaveValue(GREEN_TEXT);
expect(".o_field_html .kek").toHaveCount(0);
await edit(BLUE_TEXT);
await animationFrame();
expect(".o_field_html textarea").toHaveValue(BLUE_TEXT);
});
test("html fields are correctly rendered in list view", async () => {
onRpc("has_group", () => true);
await mountView({
type: "list",
resModel: "partner",
arch: /* xml */ `<list editable="top"><field name="txt"/></list>`,
});
expect(".o_data_row [name='txt']").toHaveText("some text");
expect(".o_data_row [name='txt'] .kek").toHaveStyle({ color: "rgb(255, 0, 0)" });
await click(".o_data_row [name='txt']");
await animationFrame();
expect(".o_data_row [name='txt'] textarea").toHaveValue(
'<div class="kek" style="color:red">some text</div>'
);
});
test("html field displays an empty string for the value false in list view", async () => {
Partner._records[0].txt = false;
onRpc("has_group", () => true);
await mountView({
type: "list",
resModel: "partner",
arch: /* xml */ `<list editable="top"><field name="txt"/></list>`,
});
expect(".o_data_row [name='txt']").toHaveText("");
await click(".o_data_row [name='txt']");
await animationFrame();
expect(".o_data_row [name='txt'] textarea").toHaveValue("");
});
test("html fields are correctly rendered in kanban view", async () => {
await mountView({
type: "kanban",
resModel: "partner",
arch: /* xml */ `
<kanban class="o_kanban_test">
<templates>
<t t-name="card">
<field name="txt"/>
</t>
</templates>
</kanban>`,
});
expect(".kek").toHaveText("some text");
expect(".kek").toHaveStyle({ color: "rgb(255, 0, 0)" });
});
test("field html translatable", async () => {
expect.assertions(10);
Partner._fields.txt = fields.Html({ string: "txt", trim: true, translate: true });
serverState.lang = "en_US";
serverState.multiLang = true;
onRpc("has_group", () => true);
onRpc("get_field_translations", function ({ args }) {
expect(args).toEqual([[1], "txt"], {
message: "should translate the txt field of the record",
});
return [
[
{ lang: "en_US", source: "first paragraph", value: "first paragraph" },
{
lang: "en_US",
source: "second paragraph",
value: "second paragraph",
},
{
lang: "fr_BE",
source: "first paragraph",
value: "",
},
{
lang: "fr_BE",
source: "second paragraph",
value: "deuxième paragraphe",
},
],
{ translation_type: "char", translation_show_source: true },
];
});
onRpc("get_installed", () => {
return [
["en_US", "English"],
["fr_BE", "French (Belgium)"],
];
});
onRpc("update_field_translations", ({ args }) => {
expect(args).toEqual(
[
[1],
"txt",
{
en_US: { "first paragraph": "first paragraph modified" },
fr_BE: {
"first paragraph": "premier paragraphe modifié",
"second paragraph": "deuxième paragraphe modifié",
},
},
],
{ message: "the new translation value should be written" }
);
return [];
});
await mountView({
type: "form",
resModel: "partner",
resId: 1,
arch: /* xml */ `
<form string="Partner">
<sheet>
<group>
<field name="txt" widget="html"/>
</group>
</sheet>
</form>`,
});
expect("[name=txt] textarea").toHaveClass("o_field_translate");
await contains("[name=txt] textarea").click();
expect(".o_field_html .btn.o_field_translate").toHaveCount(1, {
message: "should have a translate button",
});
expect(".o_field_html .btn.o_field_translate").toHaveText("EN", {
message: "the button should have as test the current language",
});
await click(".o_field_html .btn.o_field_translate");
await animationFrame();
expect(".modal").toHaveCount(1, { message: "a translate modal should be visible" });
expect(".translation").toHaveCount(4, { message: "four rows should be visible" });
const translations = queryAll(".modal .o_translation_dialog .translation input");
const enField1 = translations[0];
expect(enField1).toHaveValue("first paragraph", {
message: "first part of english translation should be filled",
});
await click(enField1);
await edit("first paragraph modified");
const frField1 = translations[2];
expect(frField1).toHaveValue("", {
message: "first part of french translation should not be filled",
});
await click(frField1);
await edit("premier paragraphe modifié");
const frField2 = translations[3];
expect(frField2).toHaveValue("deuxième paragraphe", {
message: "second part of french translation should be filled",
});
await click(frField2);
await edit("deuxième paragraphe modifié");
await click(".modal button.btn-primary"); // save
await animationFrame();
});
test("html fields: spellcheck is disabled on blur", async () => {
await mountView({
type: "form",
resModel: "partner",
resId: 1,
arch: /* xml */ `<form><field name="txt" /></form>`,
});
const textarea = queryFirst(".o_field_html textarea");
expect(textarea).toHaveProperty("spellcheck", true, {
message: "by default, spellcheck is enabled",
});
await click(textarea);
await edit("nev walue");
await pointerDown(document.body);
await animationFrame();
expect(textarea).toHaveProperty("spellcheck", false, {
message: "spellcheck is disabled once the field has lost its focus",
});
await pointerDown(textarea);
expect(textarea).toHaveProperty("spellcheck", true, {
message: "spellcheck is re-enabled once the field is focused",
});
});
test("Setting an html field to empty string is saved as a false value", async () => {
expect.assertions(1);
onRpc("web_save", ({ args }) => {
expect(args[1].txt).toBe(false, { message: "the txt value should be false" });
});
await mountView({
type: "form",
resModel: "partner",
arch: /* xml */ `
<form>
<sheet>
<group>
<field name="txt" />
</group>
</sheet>
</form>`,
resId: 1,
});
await click(".o_field_widget[name=txt] textarea");
await edit("");
await clickSave();
});
test("html field: correct value is used to evaluate the modifiers", async () => {
Partner._fields.foo = fields.Char({
string: "foo",
onChange: (obj) => {
if (obj.foo === "a") {
obj.txt = false;
} else if (obj.foo === "b") {
obj.txt = "";
}
},
});
Partner._records[0].foo = false;
Partner._records[0].txt = false;
await mountView({
type: "form",
resModel: "partner",
resId: 1,
arch: /* xml */ `
<form>
<field name="foo" />
<field name="txt" invisible="'' == txt"/>
</form>`,
});
expect("[name='txt'] textarea").toHaveCount(1);
await click("[name='foo'] input");
await edit("a", { confirm: "enter" });
await animationFrame();
expect("[name='txt'] textarea").toHaveCount(1);
await edit("b", { confirm: "enter" });
await animationFrame();
expect("[name='txt'] textarea").toHaveCount(0);
});