1162 lines
42 KiB
JavaScript
1162 lines
42 KiB
JavaScript
/** @odoo-module **/
|
|
|
|
import { browser } from "@web/core/browser/browser";
|
|
import { actionService } from "@web/webclient/actions/action_service";
|
|
import {
|
|
click,
|
|
editInput,
|
|
getFixture,
|
|
patchWithCleanup,
|
|
triggerEvent,
|
|
editSelect,
|
|
clickSave,
|
|
triggerHotkey,
|
|
nextTick,
|
|
} from "@web/../tests/helpers/utils";
|
|
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
|
import { Many2XAutocomplete } from "@web/views/fields/relational_utils";
|
|
|
|
let target;
|
|
let serverData;
|
|
|
|
QUnit.module("Fields", (hooks) => {
|
|
hooks.beforeEach(() => {
|
|
target = getFixture();
|
|
|
|
serverData = {
|
|
models: {
|
|
partner: {
|
|
fields: {
|
|
display_name: { string: "Displayed name", type: "char" },
|
|
foo: { string: "Foo", type: "char", default: "My little Foo Value" },
|
|
bar: { string: "Bar", type: "boolean", default: true },
|
|
int_field: { string: "int_field", type: "integer", sortable: true },
|
|
qux: { string: "Qux", type: "float", digits: [16, 1] },
|
|
p: {
|
|
string: "one2many field",
|
|
type: "one2many",
|
|
relation: "partner",
|
|
relation_field: "trululu",
|
|
},
|
|
turtles: {
|
|
string: "one2many turtle field",
|
|
type: "one2many",
|
|
relation: "turtle",
|
|
relation_field: "turtle_trululu",
|
|
},
|
|
trululu: { string: "Trululu", type: "many2one", relation: "partner" },
|
|
timmy: { string: "pokemon", type: "many2many", relation: "partner_type" },
|
|
product_id: { string: "Product", type: "many2one", relation: "product" },
|
|
color: {
|
|
type: "selection",
|
|
selection: [
|
|
["red", "Red"],
|
|
["black", "Black"],
|
|
],
|
|
default: "red",
|
|
string: "Color",
|
|
},
|
|
date: { string: "Some Date", type: "date" },
|
|
datetime: { string: "Datetime Field", type: "datetime" },
|
|
reference: {
|
|
string: "Reference Field",
|
|
type: "reference",
|
|
selection: [
|
|
["product", "Product"],
|
|
["partner_type", "Partner Type"],
|
|
["partner", "Partner"],
|
|
],
|
|
},
|
|
reference_char: {
|
|
string: "Reference Field (Char)",
|
|
type: "char",
|
|
},
|
|
model_id: { string: "Model", type: "many2one", relation: "ir.model" },
|
|
},
|
|
records: [
|
|
{
|
|
id: 1,
|
|
display_name: "first record",
|
|
bar: true,
|
|
foo: "yop",
|
|
int_field: 10,
|
|
qux: 0.44,
|
|
p: [],
|
|
turtles: [2],
|
|
timmy: [],
|
|
trululu: 4,
|
|
reference: "product,37",
|
|
},
|
|
{
|
|
id: 2,
|
|
display_name: "second record",
|
|
bar: true,
|
|
foo: "blip",
|
|
int_field: 9,
|
|
qux: 13,
|
|
p: [],
|
|
timmy: [],
|
|
trululu: 1,
|
|
product_id: 37,
|
|
date: "2017-01-25",
|
|
datetime: "2016-12-12 10:55:05",
|
|
},
|
|
{
|
|
id: 4,
|
|
display_name: "aaa",
|
|
bar: false,
|
|
},
|
|
],
|
|
onchanges: {},
|
|
},
|
|
product: {
|
|
fields: {
|
|
name: { string: "Product Name", type: "char" },
|
|
},
|
|
records: [
|
|
{
|
|
id: 37,
|
|
display_name: "xphone",
|
|
},
|
|
{
|
|
id: 41,
|
|
display_name: "xpad",
|
|
},
|
|
],
|
|
},
|
|
partner_type: {
|
|
fields: {
|
|
name: { string: "Partner Type", type: "char" },
|
|
color: { string: "Color index", type: "integer" },
|
|
},
|
|
records: [
|
|
{ id: 12, display_name: "gold", color: 2 },
|
|
{ id: 14, display_name: "silver", color: 5 },
|
|
],
|
|
},
|
|
turtle: {
|
|
fields: {
|
|
display_name: { string: "Displayed name", type: "char" },
|
|
turtle_foo: { string: "Foo", type: "char" },
|
|
turtle_bar: { string: "Bar", type: "boolean", default: true },
|
|
turtle_int: { string: "int", type: "integer", sortable: true },
|
|
turtle_description: { string: "Description", type: "text" },
|
|
turtle_trululu: {
|
|
string: "Trululu",
|
|
type: "many2one",
|
|
relation: "partner",
|
|
},
|
|
turtle_ref: {
|
|
string: "Reference",
|
|
type: "reference",
|
|
selection: [
|
|
["product", "Product"],
|
|
["partner", "Partner"],
|
|
],
|
|
},
|
|
product_id: {
|
|
string: "Product",
|
|
type: "many2one",
|
|
relation: "product",
|
|
required: true,
|
|
},
|
|
partner_ids: { string: "Partner", type: "many2many", relation: "partner" },
|
|
},
|
|
records: [
|
|
{
|
|
id: 1,
|
|
display_name: "leonardo",
|
|
turtle_bar: true,
|
|
turtle_foo: "yop",
|
|
partner_ids: [],
|
|
},
|
|
{
|
|
id: 2,
|
|
display_name: "donatello",
|
|
turtle_bar: true,
|
|
turtle_foo: "blip",
|
|
turtle_int: 9,
|
|
partner_ids: [2, 4],
|
|
},
|
|
{
|
|
id: 3,
|
|
display_name: "raphael",
|
|
product_id: 37,
|
|
turtle_bar: false,
|
|
turtle_foo: "kawa",
|
|
turtle_int: 21,
|
|
partner_ids: [],
|
|
turtle_ref: "product,37",
|
|
},
|
|
],
|
|
onchanges: {},
|
|
},
|
|
"ir.model": {
|
|
fields: {
|
|
model: { string: "Model", type: "char" },
|
|
},
|
|
records: [
|
|
{
|
|
id: 17,
|
|
name: "Partner",
|
|
model: "partner",
|
|
},
|
|
{
|
|
id: 20,
|
|
name: "Product",
|
|
model: "product",
|
|
},
|
|
{
|
|
id: 21,
|
|
name: "Partner Type",
|
|
model: "partner_type",
|
|
},
|
|
],
|
|
onchanges: {},
|
|
},
|
|
},
|
|
};
|
|
|
|
setupViewRegistries();
|
|
|
|
patchWithCleanup(browser, {
|
|
setTimeout: (fn) => fn(),
|
|
});
|
|
});
|
|
|
|
QUnit.module("ReferenceField");
|
|
|
|
QUnit.test("ReferenceField can quick create models", async function (assert) {
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
serverData,
|
|
arch: '<form><field name="reference" /></form>',
|
|
mockRPC(route, { method }) {
|
|
assert.step(method || route);
|
|
},
|
|
});
|
|
|
|
await editSelect(target, "select", "partner");
|
|
|
|
await click(target, ".o_field_widget[name='reference'] input");
|
|
await editInput(target, ".o_field_widget[name='reference'] input", "new partner");
|
|
await click(target, ".o_field_widget[name='reference'] .o_m2o_dropdown_option_create");
|
|
|
|
await clickSave(target);
|
|
|
|
assert.verifySteps(
|
|
[
|
|
"get_views",
|
|
"onchange",
|
|
"name_search", // for the select
|
|
"name_search", // for the spawned many2one
|
|
"name_create",
|
|
"create",
|
|
"read",
|
|
"name_get",
|
|
],
|
|
"The name_create method should have been called"
|
|
);
|
|
});
|
|
|
|
QUnit.test("ReferenceField respects no_quick_create", async function (assert) {
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
serverData,
|
|
arch: `<form><field name="reference" options="{'no_quick_create': 1}" /></form>`,
|
|
});
|
|
|
|
await editSelect(target, "select", "partner");
|
|
await click(target, ".o_field_widget[name='reference'] input");
|
|
await editInput(target, ".o_field_widget[name='reference'] input", "new partner");
|
|
assert.containsOnce(
|
|
target,
|
|
".ui-autocomplete .o_m2o_dropdown_option",
|
|
"Dropdown should be opened and have only one item"
|
|
);
|
|
assert.hasClass(
|
|
target.querySelector(".ui-autocomplete .o_m2o_dropdown_option"),
|
|
"o_m2o_dropdown_option_create_edit"
|
|
);
|
|
});
|
|
|
|
QUnit.test("ReferenceField in modal readonly mode", async function (assert) {
|
|
serverData.models.partner.records[0].p = [2];
|
|
serverData.models.partner.records[1].trululu = 1;
|
|
serverData.models.partner.records[1].reference = "product,41";
|
|
|
|
serverData.views = {
|
|
"partner,false,form": `
|
|
<form>
|
|
<field name="display_name" />
|
|
<field name="reference" />
|
|
</form>`,
|
|
"partner,false,list": `
|
|
<tree>
|
|
<field name="display_name"/>
|
|
<field name="reference" />
|
|
</tree>`,
|
|
};
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
resId: 1,
|
|
serverData,
|
|
arch: `
|
|
<form edit="0">
|
|
<field name="reference" />
|
|
<field name="p" />
|
|
</form>`,
|
|
});
|
|
|
|
// Current Form
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name=reference] .o_form_uri").textContent,
|
|
"xphone",
|
|
"the field reference of the form should have the right value"
|
|
);
|
|
|
|
const cell = target.querySelector(".o_data_cell");
|
|
assert.strictEqual(cell.textContent, "second record", "the list should have one record");
|
|
await click(cell);
|
|
|
|
// In modal
|
|
assert.containsOnce(document.body, ".modal-lg");
|
|
assert.strictEqual(
|
|
document.body.querySelector(".modal-lg .o_field_widget[name=reference] .o_form_uri")
|
|
.textContent,
|
|
"xpad",
|
|
"The field reference in the modal should have the right value"
|
|
);
|
|
|
|
await click(document.body, ".modal .o_form_button_cancel");
|
|
});
|
|
|
|
QUnit.test("ReferenceField in modal write mode", async function (assert) {
|
|
serverData.models.partner.records[0].p = [2];
|
|
serverData.models.partner.records[1].trululu = 1;
|
|
serverData.models.partner.records[1].reference = "product,41";
|
|
|
|
serverData.views = {
|
|
"partner,false,form": `
|
|
<form>
|
|
<field name="display_name" />
|
|
<field name="reference" />
|
|
</form>`,
|
|
"partner,false,list": `
|
|
<tree>
|
|
<field name="display_name"/>
|
|
<field name="reference" />
|
|
</tree>`,
|
|
};
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
resId: 1,
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<field name="reference" />
|
|
<field name="p" />
|
|
</form>`,
|
|
});
|
|
|
|
let fieldRef = target.querySelector(".o_field_widget[name=reference]");
|
|
assert.strictEqual(
|
|
fieldRef.querySelector("option:checked").textContent,
|
|
"Product",
|
|
"The reference field's model should be Product"
|
|
);
|
|
assert.strictEqual(
|
|
fieldRef.querySelector(".o-autocomplete--input").value,
|
|
"xphone",
|
|
"The reference field's record should be xphone"
|
|
);
|
|
|
|
await click(target.querySelector(".o_data_cell"));
|
|
|
|
// In modal
|
|
assert.containsOnce(document.body, ".modal-lg", "there should be one modal opened");
|
|
|
|
fieldRef = document.querySelector(".modal-lg .o_field_widget[name=reference]");
|
|
|
|
assert.strictEqual(
|
|
fieldRef.querySelector("option:checked").textContent,
|
|
"Product",
|
|
"The reference field's model should be Product"
|
|
);
|
|
assert.strictEqual(
|
|
fieldRef.querySelector(".o-autocomplete--input").value,
|
|
"xpad",
|
|
"The reference field's record should be xpad"
|
|
);
|
|
});
|
|
|
|
QUnit.test("reference in form view", async function (assert) {
|
|
assert.expect(11);
|
|
|
|
serverData.views = {
|
|
"product,false,form": `
|
|
<form>
|
|
<field name="display_name" />
|
|
</form>`,
|
|
};
|
|
|
|
patchWithCleanup(actionService, {
|
|
start() {
|
|
const service = this._super(...arguments);
|
|
return {
|
|
...service,
|
|
doAction(action) {
|
|
assert.strictEqual(
|
|
action.res_id,
|
|
17,
|
|
"should do a do_action with correct parameters"
|
|
);
|
|
},
|
|
};
|
|
},
|
|
});
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
resId: 1,
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<sheet>
|
|
<group>
|
|
<field name="reference" string="custom label" open_target="new" />
|
|
</group>
|
|
</sheet>
|
|
</form>`,
|
|
mockRPC(route, { args, method, model }) {
|
|
if (method === "get_formview_action") {
|
|
assert.deepEqual(
|
|
args[0],
|
|
[37],
|
|
"should call get_formview_action with correct id"
|
|
);
|
|
return Promise.resolve({
|
|
res_id: 17,
|
|
type: "ir.actions.act_window",
|
|
target: "current",
|
|
res_model: "res.partner",
|
|
});
|
|
}
|
|
if (method === "get_formview_id") {
|
|
assert.deepEqual(args[0], [37], "should call get_formview_id with correct id");
|
|
return Promise.resolve(false);
|
|
}
|
|
if (method === "name_search") {
|
|
assert.strictEqual(
|
|
model,
|
|
"partner_type",
|
|
"the name_search should be done on the newly set model"
|
|
);
|
|
}
|
|
if (method === "write") {
|
|
assert.strictEqual(model, "partner", "should write on the current model");
|
|
assert.deepEqual(
|
|
args,
|
|
[[1], { reference: "partner_type,12" }],
|
|
"should write the correct value"
|
|
);
|
|
}
|
|
},
|
|
});
|
|
|
|
// assert.strictEqual(
|
|
// target.querySelector("a.o_form_uri").textContent,
|
|
// "xphone",
|
|
// "should contain a link"
|
|
// );
|
|
// await click(target, "a.o_form_uri");
|
|
|
|
assert.containsOnce(target, ".o_field_many2one_selection", "should contain one many2one");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget select").value,
|
|
"product",
|
|
"widget should contain one select with the model"
|
|
);
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget input").value,
|
|
"xphone",
|
|
"widget should contain one input with the record"
|
|
);
|
|
|
|
const options = [...target.querySelectorAll(".o_field_widget select > option")].map(
|
|
(el) => el.value
|
|
);
|
|
assert.deepEqual(
|
|
options,
|
|
["", "product", "partner_type", "partner"],
|
|
"the options should be correctly set"
|
|
);
|
|
|
|
await click(target, ".o_external_button");
|
|
|
|
assert.strictEqual(
|
|
target.querySelector(".modal .modal-title").textContent.trim(),
|
|
"Open: custom label",
|
|
"dialog title should display the custom string label"
|
|
);
|
|
await click(target, ".modal .o_form_button_cancel");
|
|
|
|
await editSelect(target, ".o_field_widget select", "partner_type");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget input").value,
|
|
"",
|
|
"many2one value should be reset after model change"
|
|
);
|
|
|
|
await click(target, ".o_field_widget[name=reference] input");
|
|
await click(target.querySelector(".o_field_widget[name=reference] .ui-menu-item"));
|
|
|
|
await clickSave(target);
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name=reference] input").value,
|
|
"gold",
|
|
"should contain a link with the new value"
|
|
);
|
|
});
|
|
|
|
QUnit.test("Many2One 'Search More...' updates on resModel change", async function (assert) {
|
|
|
|
// Patch the Many2XAutocomplete default search limit options
|
|
patchWithCleanup(Many2XAutocomplete.defaultProps, {
|
|
searchLimit: -1,
|
|
});
|
|
|
|
serverData.views = {
|
|
"product,false,list": '<tree><field name="display_name"/></tree>',
|
|
"product,false,search": '<search/>',
|
|
};
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
serverData,
|
|
arch: '<form><field name="reference"/></form>',
|
|
});
|
|
|
|
// Selecting a relation
|
|
await editSelect(target.querySelector("div.o_field_reference"), "select.o_input", "partner_type");
|
|
|
|
// Selecting another relation
|
|
await editSelect(target.querySelector("div.o_field_reference"), "select.o_input", "product");
|
|
|
|
// Opening the Search More... option
|
|
await click(target.querySelector("div.o_field_reference"), "input.o_input");
|
|
await click(target.querySelector("div.o_field_reference"), ".o_m2o_dropdown_option_search_more");
|
|
|
|
assert.strictEqual(
|
|
target.querySelector("div.modal td.o_data_cell").innerText,
|
|
"xphone",
|
|
"The search more should lead to the values of product."
|
|
);
|
|
});
|
|
|
|
QUnit.test("computed reference field changed by onchange to 'False,0' value", async function (assert) {
|
|
assert.expect(1);
|
|
|
|
serverData.models.partner.onchanges = {
|
|
bar(obj) {
|
|
if (!obj.bar) {
|
|
obj.reference_char = "False,0";
|
|
}
|
|
},
|
|
};
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<field name="bar"/>
|
|
<field name="reference_char" widget="reference"/>
|
|
</form>`,
|
|
mockRPC(route, { args, method }) {
|
|
if (method === "create") {
|
|
assert.deepEqual(args[0], {
|
|
bar: false,
|
|
reference_char: "False,0",
|
|
});
|
|
}
|
|
},
|
|
});
|
|
|
|
// trigger the onchange to set a value for the reference field
|
|
await click(target, ".o_field_boolean input");
|
|
|
|
// save
|
|
await clickSave(target);
|
|
});
|
|
|
|
QUnit.test("ReferenceField with model field", async function (assert) {
|
|
serverData.models.partner.onchanges = {
|
|
color(obj) {
|
|
if (obj.color === "black") {
|
|
obj.model_id = 20;
|
|
obj.reference = "product,37";
|
|
} else {
|
|
obj.model_id = 17;
|
|
obj.reference = "partner,1";
|
|
}
|
|
},
|
|
};
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
resId: 1,
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<field name="color" />
|
|
<field name="model_id" invisible="1"/>
|
|
<field name="reference" options="{'model_field': 'model_id'}" />
|
|
</form>`,
|
|
mockRPC(route, { args, method }) {
|
|
if (method === "write") {
|
|
assert.step("write");
|
|
assert.strictEqual(args[1].reference, "partner,4");
|
|
}
|
|
},
|
|
});
|
|
await editSelect(target, "select", '"black"');
|
|
await editSelect(target, "select", '"red"');
|
|
|
|
await editInput(target, ".o_field_widget[name=reference] input", "aaa");
|
|
|
|
await click(target, ".ui-autocomplete .ui-menu-item:first-child");
|
|
await clickSave(target);
|
|
assert.verifySteps(["write"]);
|
|
});
|
|
|
|
QUnit.test("interact with reference field changed by onchange", async function (assert) {
|
|
assert.expect(2);
|
|
|
|
serverData.models.partner.onchanges = {
|
|
bar(obj) {
|
|
if (!obj.bar) {
|
|
obj.reference = "partner,1";
|
|
}
|
|
},
|
|
};
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<field name="bar"/>
|
|
<field name="reference"/>
|
|
</form>`,
|
|
mockRPC(route, { args, method }) {
|
|
if (method === "create") {
|
|
assert.deepEqual(args[0], {
|
|
bar: false,
|
|
reference: "partner,4",
|
|
});
|
|
}
|
|
},
|
|
});
|
|
|
|
// trigger the onchange to set a value for the reference field
|
|
await click(target, ".o_field_boolean input");
|
|
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name=reference] select").value,
|
|
"partner"
|
|
);
|
|
|
|
// manually update reference field
|
|
await editInput(target, ".o_field_widget[name=reference] input", "aaa");
|
|
await click(target.querySelector(".ui-autocomplete .ui-menu-item"));
|
|
|
|
// save
|
|
await clickSave(target);
|
|
});
|
|
|
|
QUnit.test("default_get and onchange with a reference field", async function (assert) {
|
|
serverData.models.partner.fields.reference.default = "product,37";
|
|
serverData.models.partner.onchanges = {
|
|
int_field(obj) {
|
|
if (obj.int_field) {
|
|
obj.reference = "partner_type," + obj.int_field;
|
|
}
|
|
},
|
|
};
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<sheet>
|
|
<group>
|
|
<field name="int_field" />
|
|
<field name="reference" />
|
|
</group>
|
|
</sheet>
|
|
</form>`,
|
|
mockRPC(route, { method, model }) {
|
|
if (method === "name_get") {
|
|
assert.step(model);
|
|
}
|
|
},
|
|
});
|
|
|
|
assert.verifySteps(["product"], "the first name_get should have been done");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name='reference'] select").value,
|
|
"product",
|
|
"reference field model should be correctly set"
|
|
);
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name='reference'] input").value,
|
|
"xphone",
|
|
"reference field value should be correctly set"
|
|
);
|
|
|
|
// trigger onchange
|
|
await editInput(target, ".o_field_widget[name=int_field] input", 12);
|
|
|
|
assert.verifySteps(["partner_type"], "the second name_get should have been done");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name='reference'] select").value,
|
|
"partner_type",
|
|
"reference field model should be correctly set"
|
|
);
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name='reference'] input").value,
|
|
"gold",
|
|
"reference field value should be correctly set"
|
|
);
|
|
});
|
|
|
|
QUnit.test("default_get a reference field in a x2m", async function (assert) {
|
|
serverData.models.partner.fields.turtles.default = [
|
|
[0, false, { turtle_ref: "product,37" }],
|
|
];
|
|
serverData.views = {
|
|
"turtle,false,form": `
|
|
<form>
|
|
<field name="display_name" />
|
|
<field name="turtle_ref" />
|
|
</form>`,
|
|
};
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<sheet>
|
|
<field name="turtles">
|
|
<tree>
|
|
<field name="turtle_ref" />
|
|
</tree>
|
|
</field>
|
|
</sheet>
|
|
</form>`,
|
|
});
|
|
|
|
assert.strictEqual(
|
|
target.querySelector('.o_field_widget[name="turtles"] .o_data_row').textContent,
|
|
"xphone",
|
|
"the default value should be correctly handled"
|
|
);
|
|
});
|
|
|
|
QUnit.test("ReferenceField on char field, reset by onchange", async function (assert) {
|
|
serverData.models.partner.records[0].foo = "product,37";
|
|
serverData.models.partner.onchanges = {
|
|
int_field(obj) {
|
|
obj.foo = "product," + obj.int_field;
|
|
},
|
|
};
|
|
|
|
let nbNameGet = 0;
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
resId: 1,
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<sheet>
|
|
<group>
|
|
<field name="int_field" />
|
|
<field name="foo" widget="reference" readonly="1" />
|
|
</group>
|
|
</sheet>
|
|
</form>`,
|
|
mockRPC(route, { model, method }) {
|
|
if (model === "product" && method === "name_get") {
|
|
nbNameGet++;
|
|
}
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(nbNameGet, 1, "the first name_get should have been done");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name=foo]").textContent,
|
|
"xphone",
|
|
"foo field should be correctly set"
|
|
);
|
|
|
|
// trigger onchange
|
|
await editInput(target, ".o_field_widget[name=int_field] input", 41);
|
|
|
|
assert.strictEqual(nbNameGet, 2, "the second name_get should have been done");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name=foo]").textContent,
|
|
"xpad",
|
|
"foo field should have been updated"
|
|
);
|
|
});
|
|
|
|
QUnit.test("reference and list navigation", async function (assert) {
|
|
await makeView({
|
|
type: "list",
|
|
resModel: "partner",
|
|
serverData,
|
|
arch: `
|
|
<tree editable="bottom">
|
|
<field name="reference" />
|
|
</tree>`,
|
|
});
|
|
|
|
// edit first row
|
|
await click(target.querySelector(".o_data_row .o_data_cell"));
|
|
assert.strictEqual(
|
|
document.activeElement,
|
|
target.querySelector(".o_data_row [name='reference'] input")
|
|
);
|
|
|
|
triggerHotkey("Tab");
|
|
await nextTick();
|
|
|
|
assert.strictEqual(
|
|
document.activeElement,
|
|
target.querySelector(".o_data_row:nth-child(2) [name='reference'] select")
|
|
);
|
|
});
|
|
|
|
QUnit.test("ReferenceField with model_field option", async function (assert) {
|
|
serverData.models.partner.records[0].reference = false;
|
|
serverData.models.partner.records[0].model_id = 20;
|
|
serverData.models.partner.records[1].display_name = "John Smith";
|
|
serverData.models.product.records[0].display_name = "Product 1";
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
resId: 1,
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<field name="model_id" />
|
|
<field name="reference" options="{'model_field': 'model_id'}" />
|
|
</form>`,
|
|
});
|
|
|
|
assert.containsNone(
|
|
target,
|
|
"select",
|
|
"the selection list of the reference field should not exist."
|
|
);
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name='reference'] input").value,
|
|
"",
|
|
"no record should be selected in the reference field"
|
|
);
|
|
|
|
await editInput(target, ".o_field_widget[name='reference'] input", "Product 1");
|
|
await click(target, ".ui-autocomplete .ui-menu-item:first-child");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name='reference'] input").value,
|
|
"Product 1",
|
|
"the Product 1 record should be selected in the reference field"
|
|
);
|
|
|
|
await editInput(target, ".o_field_widget[name='model_id'] input", "Partner");
|
|
await click(target, ".ui-autocomplete .ui-menu-item:first-child");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name='reference'] input").value,
|
|
"",
|
|
"no record should be selected in the reference field"
|
|
);
|
|
|
|
await editInput(target, ".o_field_widget[name='reference'] input", "John");
|
|
await click(target, ".ui-autocomplete .ui-menu-item:first-child");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name='reference'] input").value,
|
|
"John Smith",
|
|
"the John Smith record should be selected in the reference field"
|
|
);
|
|
});
|
|
|
|
QUnit.test(
|
|
"ReferenceField with model_field option (model_field not synchronized with reference)",
|
|
async function (assert) {
|
|
// Checks that the data is not modified even though it is not synchronized.
|
|
// Not synchronized = model_id contains a different model than the one used in reference.
|
|
serverData.models.partner.records[0].reference = "partner,1";
|
|
serverData.models.partner.records[0].model_id = 20;
|
|
serverData.models.partner.records[0].display_name = "John Smith";
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
resId: 1,
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<field name="model_id" />
|
|
<field name="reference" options="{'model_field': 'model_id'}" />
|
|
</form>`,
|
|
});
|
|
|
|
assert.containsNone(
|
|
target,
|
|
"select",
|
|
"the selection list of the reference field should not exist."
|
|
);
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name='model_id'] input").value,
|
|
"Product",
|
|
"the Product model should be selected in the model_id field"
|
|
);
|
|
assert.strictEqual(
|
|
target.querySelector(".o_field_widget[name='reference'] input").value,
|
|
"John Smith",
|
|
"the John Smith record should be selected in the reference field"
|
|
);
|
|
}
|
|
);
|
|
|
|
QUnit.test("Reference field with default value in list view", async function (assert) {
|
|
assert.expect(2);
|
|
|
|
await makeView({
|
|
type: "list",
|
|
resModel: "partner",
|
|
serverData,
|
|
arch: `
|
|
<tree string="Test" editable="top">
|
|
<field name="reference"/>
|
|
<field name="display_name"/>
|
|
</tree>`,
|
|
mockRPC: (route, { method, args }) => {
|
|
if (method === "onchange") {
|
|
return {
|
|
value: {reference: "partner,2"},
|
|
};
|
|
} else if (method === "create") {
|
|
assert.strictEqual(args.length, 1);
|
|
assert.strictEqual(args[0].reference, "partner,2");
|
|
}
|
|
},
|
|
});
|
|
|
|
await click(target, '.o_list_button_add');
|
|
await click(target, '.o_list_char[name="display_name"] input');
|
|
await editInput(target, '.o_list_char[name="display_name"] input', "Blabla");
|
|
await click(target, '.o_list_button_save');
|
|
});
|
|
|
|
QUnit.test(
|
|
"ReferenceField with model_field option (tree list in form view)",
|
|
async function (assert) {
|
|
serverData.models.turtle.records[0].partner_ids = [1];
|
|
serverData.models.partner.records[0].reference = "product,41";
|
|
serverData.models.partner.records[0].model_id = 20;
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "turtle",
|
|
resId: 1,
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<field name="partner_ids">
|
|
<tree editable="bottom">
|
|
<field name="name" />
|
|
<field name="model_id" />
|
|
<field name="reference" options="{'model_field': 'model_id'}" class="reference_field" />
|
|
</tree>
|
|
</field>
|
|
</form>`,
|
|
});
|
|
|
|
assert.strictEqual(target.querySelector(".reference_field").textContent, "xpad");
|
|
|
|
// Select the second product without changing the model
|
|
await click(target, ".o_list_table .reference_field");
|
|
await click(target, ".o_list_table .reference_field input");
|
|
|
|
// Enter to select it
|
|
await triggerEvent(target, ".o_list_table .reference_field input", "keydown", {
|
|
key: "Enter",
|
|
});
|
|
|
|
assert.strictEqual(
|
|
target.querySelector(".reference_field input").value,
|
|
"xphone",
|
|
"should have selected the first product"
|
|
);
|
|
}
|
|
);
|
|
|
|
QUnit.test(
|
|
"edit a record containing a ReferenceField with model_field option (list in form view)",
|
|
async function (assert) {
|
|
serverData.models.turtle.records[0].partner_ids = [1];
|
|
serverData.models.partner.records[0].reference = "product,41";
|
|
serverData.models.partner.records[0].model_id = 20;
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "turtle",
|
|
resId: 1,
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<field name="partner_ids">
|
|
<tree editable="bottom">
|
|
<field name="name" />
|
|
<field name="model_id" />
|
|
<field name="reference" options='{"model_field": "model_id"}'/>
|
|
</tree>
|
|
</field>
|
|
</form>`,
|
|
});
|
|
assert.strictEqual(
|
|
target.querySelector(".o_list_table [name='name']").textContent,
|
|
"name"
|
|
);
|
|
assert.strictEqual(
|
|
target.querySelector(".o_list_table [name='reference']").textContent,
|
|
"xpad"
|
|
);
|
|
|
|
await click(target.querySelector(".o_list_table .o_data_cell"));
|
|
await editInput(target, ".o_list_table [name='name'] input", "plop");
|
|
await click(target, ".o_form_view");
|
|
assert.strictEqual(
|
|
target.querySelector(".o_list_table [name='name']").textContent,
|
|
"plop"
|
|
);
|
|
assert.strictEqual(
|
|
target.querySelector(".o_list_table [name='reference']").textContent,
|
|
"xpad"
|
|
);
|
|
}
|
|
);
|
|
|
|
QUnit.test(
|
|
"Change model field of a ReferenceField then select an invalid value (tree list in form view)",
|
|
async function (assert) {
|
|
serverData.models.turtle.records[0].partner_ids = [1];
|
|
serverData.models.partner.records[0].reference = "product,41";
|
|
serverData.models.partner.records[0].model_id = 20;
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "turtle",
|
|
resId: 1,
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<field name="partner_ids">
|
|
<tree editable="bottom">
|
|
<field name="name" />
|
|
<field name="model_id"/>
|
|
<field name="reference" required="true" options="{'model_field': 'model_id'}" class="reference_field" />
|
|
</tree>
|
|
</field>
|
|
</form>`,
|
|
});
|
|
assert.strictEqual(target.querySelector(".reference_field").textContent, "xpad");
|
|
assert.strictEqual(target.querySelector(".o_list_many2one").textContent, "Product");
|
|
|
|
await click(target, ".o_list_table td.o_list_many2one");
|
|
await click(target, ".o_list_table .o_list_many2one input");
|
|
//Select the "Partner" option, different from original "Product"
|
|
const dropdownItems = [...target.querySelectorAll(".o_list_table .o_list_many2one .o_input_dropdown .dropdown-item")];
|
|
await click(dropdownItems.filter(item => item.text === "Partner")[0]);
|
|
assert.strictEqual(target.querySelector(".reference_field input").value, "");
|
|
assert.strictEqual(target.querySelector(".o_list_many2one input").value, "Partner");
|
|
//Void the associated, required, "reference" field and make sure the form marks the field as required
|
|
await click(target, ".o_list_table .reference_field input");
|
|
const textInput = target.querySelector(".o_list_table .reference_field input");
|
|
textInput.setSelectionRange(0, textInput.value.length);
|
|
await triggerEvent(target, ".o_list_table .reference_field input", "keydown", {
|
|
key: "Backspace",
|
|
});
|
|
await click(target, ".o_form_view_container");
|
|
|
|
assert.containsOnce(target, ".o_list_table .reference_field.o_field_invalid");
|
|
}
|
|
);
|
|
|
|
QUnit.test("model selector is displayed only when it should be", async function (assert) {
|
|
//The model selector should be only displayed if
|
|
//there is no hide_model=True options AND no model_field specified
|
|
await makeView({
|
|
type: "form",
|
|
resModel: "partner",
|
|
resId: 1,
|
|
serverData,
|
|
arch: `
|
|
<form>
|
|
<group>
|
|
<field name="reference" options="{'model_field': 'model_id'}" />
|
|
</group>
|
|
<group>
|
|
<field name="reference" options="{'model_field': 'model_id', 'hide_model': True}" />
|
|
</group>
|
|
<group>
|
|
<field name="reference" options="{'hide_model': True}" />
|
|
</group>
|
|
<group>
|
|
<field name="reference" />
|
|
</group>
|
|
</form>`,
|
|
});
|
|
|
|
const groups = target.querySelectorAll(".o_inner_group");
|
|
|
|
assert.containsNone(
|
|
groups[0],
|
|
"select",
|
|
"the selection list of the reference field should not exist when model_field is specified."
|
|
);
|
|
assert.containsNone(
|
|
groups[1],
|
|
"select",
|
|
"the selection list of the reference field should not exist when model_field is specified and hide_model=True."
|
|
);
|
|
assert.containsNone(
|
|
groups[2],
|
|
"select",
|
|
"the selection list of the reference field should not exist when hide_model=True."
|
|
);
|
|
assert.containsOnce(
|
|
groups[3],
|
|
"select",
|
|
"the selection list of the reference field should exist when hide_model=False and no model_field specified."
|
|
);
|
|
});
|
|
});
|