650 lines
24 KiB
JavaScript
650 lines
24 KiB
JavaScript
/** @odoo-module **/
|
|
|
|
import { click, drag, editInput, getFixture } from "@web/../tests/helpers/utils";
|
|
import { registerCleanup } from "@web/../tests/helpers/cleanup";
|
|
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
|
import { sortableDrag } from "@web/../tests/core/utils/nested_sortable_tests"
|
|
|
|
let arch;
|
|
let serverData;
|
|
let target;
|
|
|
|
QUnit.module("Account Reports Builder", ({ beforeEach }) => {
|
|
beforeEach(async () => {
|
|
arch = `
|
|
<form>
|
|
<field class="w-100" name="line_ids" widget="account_report_lines_list_x2many">
|
|
<list>
|
|
<field name="id" column_invisible="1"/>
|
|
<field name="sequence" column_invisible="1"/>
|
|
<field name="parent_id" column_invisible="1"/>
|
|
<field name="hierarchy_level" column_invisible="1"/>
|
|
<field name="name"/>
|
|
<field name="code" optional="hide"/>
|
|
</list>
|
|
</field>
|
|
</form>
|
|
`;
|
|
|
|
serverData = {
|
|
models: {
|
|
report: {
|
|
fields: {
|
|
id: { string: "ID", type: "integer" },
|
|
line_ids: {
|
|
string: "Lines",
|
|
type: "one2many",
|
|
relation: "report_lines",
|
|
relation_field: "report_id",
|
|
},
|
|
},
|
|
records: [
|
|
{
|
|
id: 1,
|
|
line_ids: [1, 2, 3, 4, 5],
|
|
}
|
|
]
|
|
},
|
|
report_lines: {
|
|
fields: {
|
|
report_id: { string: "Report ID", type: "many2one", relation: "report" },
|
|
id: { string: "ID", type: "integer" },
|
|
sequence: { string: "Sequence", type: "integer" },
|
|
parent_id: {
|
|
string: "Parent Line",
|
|
type: "many2one",
|
|
relation: "report_lines",
|
|
relation_field: "id",
|
|
},
|
|
hierarchy_level: { string: "Level", type: "integer" },
|
|
name: { string: "Name", type: "char" },
|
|
code: { string: "Code", type: "char" },
|
|
},
|
|
records: [
|
|
{
|
|
id: 1,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 1,
|
|
name: "Root without children",
|
|
code: "RWOC",
|
|
},
|
|
{
|
|
id: 2,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 0,
|
|
name: "Root with children",
|
|
code: "RC",
|
|
},
|
|
{
|
|
id: 3,
|
|
sequence: null,
|
|
parent_id: 2,
|
|
hierarchy_level: 3,
|
|
name: "Child #1",
|
|
code: "C1",
|
|
},
|
|
{
|
|
id: 4,
|
|
sequence: null,
|
|
parent_id: 3,
|
|
hierarchy_level: 5,
|
|
name: "Grandchild",
|
|
code: "GC",
|
|
},
|
|
{
|
|
id: 5,
|
|
sequence: null,
|
|
parent_id: 2,
|
|
hierarchy_level: 3,
|
|
name: "Child #2",
|
|
code: "C2",
|
|
},
|
|
]
|
|
},
|
|
},
|
|
views: {
|
|
"report_lines,false,form": `
|
|
<form>
|
|
<field name="name"/>
|
|
</form>
|
|
`,
|
|
}
|
|
};
|
|
|
|
target = getFixture();
|
|
|
|
// Make fixture in visible range, so that document.elementFromPoint work as expected
|
|
target.style.position = "absolute";
|
|
target.style.top = "0";
|
|
target.style.left = "0";
|
|
target.style.height = "100%";
|
|
target.style.opacity = QUnit.config.debug ? "" : "0";
|
|
|
|
registerCleanup(async () => {
|
|
target.style.position = "";
|
|
target.style.top = "";
|
|
target.style.left = "";
|
|
target.style.height = "";
|
|
target.style.opacity = "";
|
|
});
|
|
|
|
setupViewRegistries();
|
|
});
|
|
|
|
//------------------------------------------------------------------------------------------------------------------
|
|
// Structure
|
|
//------------------------------------------------------------------------------------------------------------------
|
|
QUnit.test("have correct descendants count", async (assert) => {
|
|
await makeView({
|
|
type: "form",
|
|
resId: 1,
|
|
resModel: "report",
|
|
serverData,
|
|
arch,
|
|
});
|
|
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='0'] span:contains('Root without children')");
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='3'] span:contains('Root with children')");
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='1'] span:contains('Child #1')");
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='0'] span:contains('Grandchild')");
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='0'] span:contains('Child #2')");
|
|
});
|
|
|
|
//------------------------------------------------------------------------------------------------------------------
|
|
// Create
|
|
//------------------------------------------------------------------------------------------------------------------
|
|
QUnit.test("can create a line", async (assert) => {
|
|
await makeView({
|
|
type: "form",
|
|
resId: 1,
|
|
resModel: "report",
|
|
serverData,
|
|
arch,
|
|
});
|
|
|
|
await click(target.querySelector(".account_report_lines_list_x2many"), "li:last-of-type a");
|
|
|
|
assert.containsOnce(target, ".o_dialog");
|
|
|
|
await editInput(target.querySelector("div[name='name'] input"), null, "Created line");
|
|
await click(target.querySelector(".o_dialog"), ".o_form_button_save");
|
|
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Created line')");
|
|
});
|
|
|
|
//------------------------------------------------------------------------------------------------------------------
|
|
// Edit
|
|
//------------------------------------------------------------------------------------------------------------------
|
|
QUnit.test("can edit a line", async (assert) => {
|
|
await makeView({
|
|
type: "form",
|
|
resId: 1,
|
|
resModel: "report",
|
|
serverData,
|
|
arch,
|
|
});
|
|
|
|
await click(target.querySelector(".account_report_lines_list_x2many"), "li[data-record_id='1'] .column");
|
|
|
|
assert.containsOnce(target, ".o_dialog");
|
|
|
|
await editInput(target.querySelector("div[name='name'] input"), null, "Line without children (edited)");
|
|
await click(target.querySelector(".o_dialog"), ".o_form_button_save");
|
|
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Line without children (edited)')");
|
|
});
|
|
|
|
//------------------------------------------------------------------------------------------------------------------
|
|
// Delete
|
|
//------------------------------------------------------------------------------------------------------------------
|
|
QUnit.test("can delete a root", async (assert) => {
|
|
await makeView({
|
|
type: "form",
|
|
resId: 1,
|
|
resModel: "report",
|
|
serverData,
|
|
arch,
|
|
});
|
|
|
|
await click(target.querySelector(".account_report_lines_list_x2many"), "li[data-record_id='1'] > div > .trash");
|
|
|
|
assert.containsNone(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Root without children')");
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Root with children')");
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Child #1')");
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Grandchild')");
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Child #2')");
|
|
});
|
|
|
|
QUnit.test("can delete a root with children", async (assert) => {
|
|
await makeView({
|
|
type: "form",
|
|
resId: 1,
|
|
resModel: "report",
|
|
serverData,
|
|
arch,
|
|
});
|
|
|
|
await click(target.querySelector(".account_report_lines_list_x2many"), "li[data-record_id='2'] > div > .trash");
|
|
|
|
// Confirmation dialog "This line and all its children will be deleted. Are you sure you want to proceed?"
|
|
assert.containsOnce(target, ".o_dialog");
|
|
|
|
await click(target.querySelector(".o_dialog"), ".btn-primary");
|
|
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Root without children')");
|
|
assert.containsNone(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Root with children')");
|
|
assert.containsNone(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Child #1')");
|
|
assert.containsNone(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Grandchild')");
|
|
assert.containsNone(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Child #2')");
|
|
});
|
|
|
|
QUnit.test("can delete a last child", async (assert) => {
|
|
await makeView({
|
|
type: "form",
|
|
resId: 1,
|
|
resModel: "report",
|
|
serverData,
|
|
arch,
|
|
});
|
|
|
|
await click(target.querySelector(".account_report_lines_list_x2many"), "li[data-record_id='4'] > div > .trash");
|
|
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Root without children')");
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='2'] span:contains('Root with children')");
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li[data-descendants_count='0'] span:contains('Child #1')");
|
|
assert.containsNone(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Grandchild')");
|
|
assert.containsOnce(target.querySelector(".account_report_lines_list_x2many"), "li span:contains('Child #2')");
|
|
});
|
|
|
|
//------------------------------------------------------------------------------------------------------------------
|
|
// Drag and drop
|
|
//------------------------------------------------------------------------------------------------------------------
|
|
QUnit.test("can move a root down", async (assert) => {
|
|
serverData.models.report.records[0].line_ids = [1, 2, 3, 4];
|
|
serverData.models.report_lines.records = [
|
|
{
|
|
id: 1,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 1,
|
|
name: "dragged",
|
|
code: "D",
|
|
},
|
|
{
|
|
id: 2,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 1,
|
|
name: "noChild",
|
|
code: "N",
|
|
},
|
|
{
|
|
id: 3,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 0,
|
|
name: "parent",
|
|
code: "P",
|
|
},
|
|
{
|
|
id: 4,
|
|
sequence: null,
|
|
parent_id: 3,
|
|
hierarchy_level: 3,
|
|
name: "child",
|
|
code: "C",
|
|
},
|
|
];
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resId: 1,
|
|
resModel: "report",
|
|
serverData,
|
|
arch,
|
|
mockRPC: (route, args) => {
|
|
if (args.method === 'web_save') {
|
|
const lineIds = args.args[1].line_ids;
|
|
|
|
// Parents
|
|
assert.equal(lineIds[0][2].parent_id, 3);
|
|
|
|
// Hierarchy levels
|
|
assert.equal(lineIds[0][2].hierarchy_level, 3);
|
|
|
|
// Sequences
|
|
assert.equal(lineIds[0][2].sequence, 4);
|
|
assert.equal(lineIds[1][2].sequence, 1);
|
|
assert.equal(lineIds[2][2].sequence, 2);
|
|
assert.equal(lineIds[3][2].sequence, 3);
|
|
}
|
|
}
|
|
});
|
|
|
|
const { drop, moveUnder } = await sortableDrag("li[data-record_id='1']");
|
|
|
|
await moveUnder("li[data-record_id='2']");
|
|
await moveUnder("li[data-record_id='4']");
|
|
await drop();
|
|
|
|
await click(target.querySelector(".o_form_button_save"));
|
|
});
|
|
|
|
QUnit.test("can move a root up", async (assert) => {
|
|
serverData.models.report.records[0].line_ids = [1, 2, 3, 4];
|
|
serverData.models.report_lines.records = [
|
|
{
|
|
id: 1,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 0,
|
|
name: "parent",
|
|
code: "P",
|
|
},
|
|
{
|
|
id: 2,
|
|
sequence: null,
|
|
parent_id: 1,
|
|
hierarchy_level: 3,
|
|
name: "child",
|
|
code: "C",
|
|
},
|
|
{
|
|
id: 3,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 1,
|
|
name: "noChild",
|
|
code: "N",
|
|
},
|
|
{
|
|
id: 4,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 1,
|
|
name: "dragged",
|
|
code: "D",
|
|
},
|
|
];
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resId: 1,
|
|
resModel: "report",
|
|
serverData,
|
|
arch,
|
|
mockRPC: (route, args) => {
|
|
if (args.method === 'web_save') {
|
|
const lineIds = args.args[1].line_ids;
|
|
|
|
// Parents
|
|
assert.equal(lineIds[0][2].parent_id, 1);
|
|
|
|
// Hierarchy levels
|
|
assert.equal(lineIds[0][2].hierarchy_level, 3);
|
|
|
|
// Sequences
|
|
assert.equal(lineIds[0][2].sequence, 2);
|
|
assert.equal(lineIds[1][2].sequence, 1);
|
|
assert.equal(lineIds[2][2].sequence, 3);
|
|
assert.equal(lineIds[3][2].sequence, 4);
|
|
}
|
|
}
|
|
});
|
|
|
|
const { drop, moveAbove } = await sortableDrag("li[data-record_id='4']");
|
|
|
|
await moveAbove("li[data-record_id='3']");
|
|
await moveAbove("li[data-record_id='2']");
|
|
await drop();
|
|
|
|
await click(target.querySelector(".o_form_button_save"));
|
|
});
|
|
|
|
QUnit.test("can move a child down", async (assert) => {
|
|
serverData.models.report.records[0].line_ids = [1, 2, 3, 4];
|
|
serverData.models.report_lines.records = [
|
|
{
|
|
id: 1,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 0,
|
|
name: "parent",
|
|
code: "P",
|
|
},
|
|
{
|
|
id: 2,
|
|
sequence: null,
|
|
parent_id: 1,
|
|
hierarchy_level: 3,
|
|
name: "dragged",
|
|
code: "D",
|
|
},
|
|
{
|
|
id: 3,
|
|
sequence: null,
|
|
parent_id: 1,
|
|
hierarchy_level: 3,
|
|
name: "child",
|
|
code: "C",
|
|
},
|
|
{
|
|
id: 4,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 1,
|
|
name: "noChild",
|
|
code: "N",
|
|
},
|
|
];
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resId: 1,
|
|
resModel: "report",
|
|
serverData,
|
|
arch,
|
|
mockRPC: (route, args) => {
|
|
if (args.method === 'web_save') {
|
|
const lineIds = args.args[1].line_ids;
|
|
|
|
// Parents
|
|
assert.equal(lineIds[0][2].parent_id, false);
|
|
|
|
// Hierarchy levels
|
|
assert.equal(lineIds[0][2].hierarchy_level, 1);
|
|
|
|
// Sequences
|
|
assert.equal(lineIds[0][2].sequence, 4);
|
|
assert.equal(lineIds[1][2].sequence, 1);
|
|
assert.equal(lineIds[2][2].sequence, 2);
|
|
assert.equal(lineIds[3][2].sequence, 3);
|
|
}
|
|
}
|
|
});
|
|
|
|
const { drop, moveUnder } = await sortableDrag("li[data-record_id='2']");
|
|
|
|
await moveUnder("li[data-record_id='3']");
|
|
await moveUnder("li[data-record_id='4']");
|
|
await drop();
|
|
|
|
await click(target.querySelector(".o_form_button_save"));
|
|
});
|
|
|
|
QUnit.test("can move a child up", async (assert) => {
|
|
serverData.models.report.records[0].line_ids = [1, 2, 3];
|
|
serverData.models.report_lines.records = [
|
|
{
|
|
id: 1,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 0,
|
|
name: "parent",
|
|
code: "P",
|
|
},
|
|
{
|
|
id: 2,
|
|
sequence: null,
|
|
parent_id: 1,
|
|
hierarchy_level: 3,
|
|
name: "child",
|
|
code: "C",
|
|
},
|
|
{
|
|
id: 3,
|
|
sequence: null,
|
|
parent_id: 1,
|
|
hierarchy_level: 3,
|
|
name: "dragged",
|
|
code: "D",
|
|
},
|
|
];
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resId: 1,
|
|
resModel: "report",
|
|
serverData,
|
|
arch,
|
|
mockRPC: (route, args) => {
|
|
if (args.method === 'web_save') {
|
|
const lineIds = args.args[1].line_ids;
|
|
|
|
// Parents
|
|
assert.equal(lineIds[0][2].parent_id, false);
|
|
|
|
// Hierarchy levels
|
|
assert.equal(lineIds[0][2].hierarchy_level, 1);
|
|
|
|
// Sequences
|
|
assert.equal(lineIds[0][2].sequence, 1);
|
|
assert.equal(lineIds[1][2].sequence, 2);
|
|
assert.equal(lineIds[2][2].sequence, 3);
|
|
}
|
|
}
|
|
});
|
|
|
|
const { drop, moveAbove } = await sortableDrag("li[data-record_id='3']");
|
|
|
|
await moveAbove("li[data-record_id='2']");
|
|
await moveAbove("li[data-record_id='1']");
|
|
await drop();
|
|
|
|
await click(target.querySelector(".o_form_button_save"));
|
|
});
|
|
|
|
QUnit.test("can move a new root into a child", async (assert) => {
|
|
serverData.models.report.records[0].line_ids = [1, 2, 3];
|
|
serverData.models.report_lines.records = [
|
|
{
|
|
id: 1,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 0,
|
|
name: "parent",
|
|
code: "P",
|
|
},
|
|
{
|
|
id: 2,
|
|
sequence: null,
|
|
parent_id: 1,
|
|
hierarchy_level: 3,
|
|
name: "child",
|
|
code: "C",
|
|
},
|
|
{
|
|
id: 3,
|
|
sequence: null,
|
|
parent_id: false,
|
|
hierarchy_level: 1,
|
|
name: "noChild",
|
|
code: "N",
|
|
},
|
|
];
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resId: 1,
|
|
resModel: "report",
|
|
serverData,
|
|
arch,
|
|
mockRPC: (route, args) => {
|
|
if (args.method === 'web_save' && !target.querySelector(".o_dialog")) {
|
|
const lineIds = args.args[1].line_ids;
|
|
|
|
// Parents
|
|
assert.equal(lineIds[0][2].parent_id, 1);
|
|
|
|
// Hierarchy levels
|
|
assert.equal(lineIds[0][2].hierarchy_level, 3);
|
|
|
|
// Sequences
|
|
assert.equal(lineIds[0][2].sequence, 2);
|
|
assert.equal(lineIds[1][2].sequence, 1);
|
|
assert.equal(lineIds[2][2].sequence, 3);
|
|
assert.equal(lineIds[3][2].sequence, 4);
|
|
}
|
|
}
|
|
});
|
|
|
|
await click(target.querySelector(".account_report_lines_list_x2many"), "li:last-of-type a");
|
|
await editInput(target.querySelector("div[name='name'] input"), null, "dragged");
|
|
await click(target.querySelector(".o_dialog"), ".o_form_button_save");
|
|
|
|
const { drop, moveAbove } = await sortableDrag("li[data-record_id='4']");
|
|
|
|
await moveAbove("li[data-record_id='3']");
|
|
await moveAbove("li[data-record_id='2']");
|
|
await drop();
|
|
|
|
await click(target.querySelector(".o_form_button_save"));
|
|
});
|
|
|
|
QUnit.test("can move a child into a new root", async (assert) => {
|
|
serverData.models.report.records[0].line_ids = [];
|
|
serverData.models.report_lines.records = [];
|
|
|
|
await makeView({
|
|
type: "form",
|
|
resId: 1,
|
|
resModel: "report",
|
|
serverData,
|
|
arch,
|
|
mockRPC: (route, args) => {
|
|
if (args.method === 'web_save' && !target.querySelector(".o_dialog")) {
|
|
const lineIds = args.args[1].line_ids;
|
|
|
|
// Parents
|
|
assert.equal(lineIds[0][2].parent_id, 1);
|
|
|
|
// Hierarchy levels
|
|
assert.equal(lineIds[0][2].hierarchy_level, 3);
|
|
|
|
// Sequences
|
|
assert.equal(lineIds[0][2].sequence, 2);
|
|
assert.equal(lineIds[1][2].sequence, 1);
|
|
}
|
|
}
|
|
});
|
|
|
|
await click(target.querySelector(".account_report_lines_list_x2many"), "li:last-of-type a");
|
|
await editInput(target.querySelector("div[name='name'] input"), null, "parent");
|
|
await click(target.querySelector(".o_dialog"), ".o_form_button_save");
|
|
|
|
await click(target.querySelector(".account_report_lines_list_x2many"), "li:last-of-type a");
|
|
await editInput(target.querySelector("div[name='name'] input"), null, "dragged");
|
|
await click(target.querySelector(".o_dialog"), ".o_form_button_save");
|
|
|
|
const toSelector = target.querySelector("li[data-record_id='2']");
|
|
const { drop, moveTo } = await drag(toSelector);
|
|
|
|
await moveTo(toSelector, { x: 600 });
|
|
await drop();
|
|
|
|
await click(target.querySelector(".o_form_button_save"));
|
|
});
|
|
});
|