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

268 lines
9.2 KiB
JavaScript

import { expect, test } from "@odoo/hoot";
import { press, queryAll, queryOne } from "@odoo/hoot-dom";
import { animationFrame } from "@odoo/hoot-mock";
import {
contains,
defineModels,
fieldInput,
fields,
models,
mountView,
onRpc,
serverState,
} from "@web/../tests/web_test_helpers";
function fieldTextArea(name) {
return contains(`.o_field_widget[name='${name}'] textarea`);
}
class Product extends models.Model {
description = fields.Text();
}
defineModels([Product]);
onRpc("has_group", () => true);
test("basic rendering", async () => {
Product._records = [{ id: 1, description: "Description as text" }];
await mountView({
type: "form",
resModel: "product",
resId: 1,
arch: '<form><field name="description"/></form>',
});
expect(".o_field_text textarea").toHaveCount(1);
expect(".o_field_text textarea").toHaveValue("Description as text");
});
test("doesn't have a scrollbar with long content", async () => {
Product._records = [{ id: 1, description: "L\no\nn\ng\nD\ne\ns\nc\nr\ni\np\nt\ni\no\nn\n" }];
await mountView({
type: "form",
resModel: "product",
resId: 1,
arch: '<form><field name="description"/></form>',
});
const textarea = queryOne(".o_field_text textarea");
expect(textarea.clientHeight).toBe(textarea.scrollHeight);
});
test("render following an onchange", async () => {
Product._fields.name = fields.Char({
onChange: (record) => {
expect.step("onchange");
record.description = "Content ".repeat(100); // long text
},
});
Product._records = [{ id: 1, description: "Description as text" }];
await mountView({
type: "form",
resModel: "product",
resId: 1,
arch: `<form><field name="description"/><field name="name"/></form>`,
});
const textarea = queryOne(".o_field_text textarea");
const initialHeight = textarea.offsetHeight;
await fieldInput("name").edit("Let's trigger the onchange");
await animationFrame();
expect(textarea.offsetHeight).toBeGreaterThan(initialHeight);
await fieldTextArea("description").edit("Description as text");
expect(textarea.offsetHeight).toBe(initialHeight);
expect(textarea.clientHeight).toBe(textarea.scrollHeight);
expect.verifySteps(["onchange"]);
});
test("no scroll bar in editable list", async () => {
Product._records = [{ id: 1, description: "L\no\nn\ng\nD\ne\ns\nc\nr\ni\np\nt\ni\no\nn\n" }];
await mountView({
type: "list",
resModel: "product",
arch: '<list editable="top"><field name="description"/></list>',
});
await contains(".o_data_row .o_data_cell").click();
const textarea = queryOne(".o_field_text textarea");
expect(textarea.clientHeight).toBe(textarea.scrollHeight);
await contains("tr:not(.o_data_row)").click();
const cell = queryOne(".o_data_row .o_data_cell");
expect(cell.clientHeight).toBe(cell.scrollHeight);
});
test("set row on text fields", async () => {
Product._records = [{ id: 1, description: "Description as text" }];
await mountView({
type: "form",
resModel: "product",
resId: 1,
arch: `<form><field name="description" rows="40"/><field name="description"/></form>`,
});
const textareas = queryAll(".o_field_text textarea");
expect(textareas[0].rows).toBe(40);
expect(textareas[0].clientHeight).toBeGreaterThan(textareas[1].clientHeight);
});
test("is translatable", async () => {
Product._fields.description.translate = true;
Product._records = [{ id: 1, description: "Description as text" }];
serverState.multiLang = true;
onRpc("get_installed", () => [
["en_US", "English"],
["fr_BE", "French (Belgium)"],
]);
onRpc("get_field_translations", () => [
[
{ lang: "en_US", source: "Description as text", value: "Description as text" },
{
lang: "fr_BE",
source: "Description as text",
value: "Description sous forme de texte",
},
],
{ translation_type: "text", translation_show_source: false },
]);
await mountView({
type: "form",
resModel: "product",
resId: 1,
arch: `<form><sheet><group><field name="description"/></group></sheet></form>`,
});
expect(".o_field_text textarea").toHaveClass("o_field_translate");
await contains(".o_field_text textarea").click();
expect(".o_field_text .btn.o_field_translate").toHaveCount(1);
await contains(".o_field_text .btn.o_field_translate").click();
expect(".modal").toHaveCount(1);
});
test("is translatable on new record", async () => {
Product._fields.description.translate = true;
Product._records = [{ id: 1, description: "Description as text" }];
serverState.multiLang = true;
await mountView({
type: "form",
resModel: "product",
arch: `<form><sheet><group><field name="description"/></group></sheet></form>`,
});
expect(".o_field_text .btn.o_field_translate").toHaveCount(1);
});
test("press enter inside editable list", async () => {
Product._records = [{ id: 1, description: "Description as text" }];
await mountView({
type: "list",
resModel: "product",
arch: `
<list editable="top">
<field name="description" />
</list>`,
});
await contains(".o_data_row .o_data_cell").click();
expect("textarea.o_input").toHaveCount(1);
expect("textarea.o_input").toHaveValue("Description as text");
expect("textarea.o_input").toBeFocused();
expect("textarea.o_input").toHaveValue("Description as text");
// clear selection before enter
await fieldTextArea("description").press(["right", "Enter"]);
expect("textarea.o_input").toHaveValue("Description as text\n");
expect("textarea.o_input").toBeFocused();
expect("tr.o_data_row").toHaveCount(1);
});
test("in editable list view", async () => {
Product._records = [{ id: 1, description: "Description as text" }];
await mountView({
type: "list",
resModel: "product",
arch: '<list editable="top"><field name="description"/></list>',
});
await contains(".o_list_button_add").click();
expect("textarea").toBeFocused();
});
test.tags("desktop");
test("with dynamic placeholder", async () => {
onRpc("mail_allowed_qweb_expressions", () => []);
Product._fields.placeholder = fields.Char({ default: "product" });
await mountView({
type: "form",
resModel: "product",
arch: `
<form>
<field name="placeholder" invisible="1"/>
<sheet>
<group>
<field
name="description"
options="{
'dynamic_placeholder': true,
'dynamic_placeholder_model_reference_field': 'placeholder'
}"
/>
</group>
</sheet>
</form>`,
});
expect(".o_popover .o_model_field_selector_popover").toHaveCount(0);
await press(["alt", "#"]);
await animationFrame();
expect(".o_popover .o_model_field_selector_popover").toHaveCount(1);
});
test.tags("mobile");
test("with dynamic placeholder in mobile", async () => {
onRpc("mail_allowed_qweb_expressions", () => []);
Product._fields.placeholder = fields.Char({ default: "product" });
await mountView({
type: "form",
resModel: "product",
arch: `
<form>
<field name="placeholder" invisible="1"/>
<sheet>
<group>
<field
name="description"
options="{
'dynamic_placeholder': true,
'dynamic_placeholder_model_reference_field': 'placeholder'
}"
/>
</group>
</sheet>
</form>`,
});
expect(".o_popover .o_model_field_selector_popover").toHaveCount(0);
await fieldTextArea("description").focus();
await press(["alt", "#"]);
await animationFrame();
expect(".o_popover .o_model_field_selector_popover").toHaveCount(1);
});
test("text field without line breaks", async () => {
Product._records = [{ id: 1, description: "Description as text" }];
await mountView({
type: "form",
resModel: "product",
resId: 1,
arch: `<form><field name="description" options="{'line_breaks': False}"/></form>`,
});
expect(".o_field_text textarea").toHaveCount(1);
expect(".o_field_text textarea").toHaveValue("Description as text");
await contains(".o_field_text textarea").click();
await press("Enter");
expect(".o_field_text textarea").toHaveValue("Description as text");
await contains(".o_field_text textarea").clear({ confirm: false });
await navigator.clipboard.writeText("text\nwith\nline\nbreaks\n"); // copy
await press(["ctrl", "v"]); // paste
expect(".o_field_text textarea").toHaveValue("text with line breaks ", {
message: "no line break should appear",
});
});