1105 lines
50 KiB
JavaScript
1105 lines
50 KiB
JavaScript
|
/** @odoo-module **/
|
||
|
|
||
|
import { browser } from "@web/core/browser/browser";
|
||
|
import {
|
||
|
click,
|
||
|
drag,
|
||
|
dragAndDrop,
|
||
|
getFixture,
|
||
|
getNodesTextContent,
|
||
|
mockAnimationFrame,
|
||
|
nextTick,
|
||
|
patchWithCleanup,
|
||
|
triggerHotkey,
|
||
|
} from "@web/../tests/helpers/utils";
|
||
|
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
||
|
|
||
|
let serverData, target;
|
||
|
|
||
|
QUnit.module("Views", (hooks) => {
|
||
|
hooks.beforeEach(() => {
|
||
|
serverData = {
|
||
|
models: {
|
||
|
"hr.employee": {
|
||
|
fields: {
|
||
|
parent_id: { string: "Manager", type: "many2one", relation: "hr.employee" },
|
||
|
name: { string: "Name" },
|
||
|
child_ids: { string: "Subordinates", type: "one2many", relation: "hr.employee", relation_field: "parent_id" },
|
||
|
},
|
||
|
records: [
|
||
|
{ id: 1, name: "Albert", parent_id: false, child_ids: [2, 3] },
|
||
|
{ id: 2, name: "Georges", parent_id: 1, child_ids: [] },
|
||
|
{ id: 3, name: "Josephine", parent_id: 1, child_ids: [4] },
|
||
|
{ id: 4, name: "Louis", parent_id: 3, child_ids: [] },
|
||
|
],
|
||
|
},
|
||
|
},
|
||
|
views: {
|
||
|
"hr.employee,false,hierarchy": `
|
||
|
<hierarchy>
|
||
|
<templates>
|
||
|
<t t-name="hierarchy-box">
|
||
|
<div class="o_hierarchy_node_header">
|
||
|
<field name="name"/>
|
||
|
</div>
|
||
|
<div class="o_hierarchy_node_body">
|
||
|
<field name="parent_id"/>
|
||
|
</div>
|
||
|
</t>
|
||
|
</templates>
|
||
|
</hierarchy>
|
||
|
`,
|
||
|
"hr.employee,1,hierarchy": `
|
||
|
<hierarchy child_field="child_ids">
|
||
|
<field name="child_ids" invisible="1"/>
|
||
|
<templates>
|
||
|
<t t-name="hierarchy-box">
|
||
|
<div class="o_hierarchy_node_header">
|
||
|
<field name="name"/>
|
||
|
</div>
|
||
|
<div class="o_hierarchy_node_body">
|
||
|
<field name="parent_id"/>
|
||
|
</div>
|
||
|
</t>
|
||
|
</templates>
|
||
|
</hierarchy>
|
||
|
`,
|
||
|
"hr.employee,false,form": `
|
||
|
<form>
|
||
|
<sheet>
|
||
|
<group>
|
||
|
<field name="name"/>
|
||
|
<field name="parent_id"/>
|
||
|
</group>
|
||
|
</sheet>
|
||
|
</form>
|
||
|
`,
|
||
|
},
|
||
|
};
|
||
|
setupViewRegistries();
|
||
|
target = getFixture();
|
||
|
});
|
||
|
|
||
|
QUnit.module("Hierarchy View");
|
||
|
|
||
|
QUnit.test("load hierarchy view", async function (assert) {
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
|
||
|
assert.containsOnce(target, ".o_hierarchy_view");
|
||
|
assert.containsN(target, ".o_hierarchy_button_add", 2);
|
||
|
assert.containsOnce(target, ".o_hierarchy_view .o_hierarchy_renderer");
|
||
|
assert.containsOnce(target, ".o_hierarchy_view .o_hierarchy_renderer > .o_hierarchy_container");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsOnce(target, ".o_hierarchy_separator");
|
||
|
assert.containsN(target, ".o_hierarchy_line_part", 2);
|
||
|
assert.containsOnce(target, ".o_hierarchy_line_left");
|
||
|
assert.containsOnce(target, ".o_hierarchy_line_right");
|
||
|
assert.containsN(target, ".o_hierarchy_node_container", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_node_button", 2);
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_button.btn-primary.d-grid");
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_button.btn-primary.rounded-0");
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_button.btn-primary .o_hierarchy_icon");
|
||
|
assert.strictEqual(target.querySelector(".o_hierarchy_node_button.btn-primary").textContent.trim(), "Unfold 1");
|
||
|
// check nodes in each row
|
||
|
const row = target.querySelector(".o_hierarchy_row");
|
||
|
assert.containsOnce(row, ".o_hierarchy_node");
|
||
|
assert.strictEqual(row.querySelector(".o_hierarchy_node_content").textContent, "Albert");
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_button.btn-secondary");
|
||
|
assert.strictEqual(target.querySelector(".o_hierarchy_node_button.btn-secondary").textContent.trim(), "Fold");
|
||
|
});
|
||
|
|
||
|
QUnit.test("display child nodes", async function (assert) {
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
async mockRPC(route, args) {
|
||
|
if (args.method === "read") {
|
||
|
assert.step("get child data");
|
||
|
} else if (args.method === "read_group") {
|
||
|
assert.step("fetch descendants");
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node_button", 2);
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_button.btn-secondary");
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
await click(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_separator", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_line_part", 4);
|
||
|
assert.containsN(target, ".o_hierarchy_line_left", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_line_right", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node_container", 4);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 4);
|
||
|
assert.containsN(target, ".o_hierarchy_node_button", 2);
|
||
|
assert.containsNone(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_node_button.btn-secondary", 2);
|
||
|
assert.strictEqual(target.querySelector(".o_hierarchy_node_button.btn-secondary").textContent.trim(), "Fold");
|
||
|
// check nodes in each row
|
||
|
const rows = target.querySelectorAll(".o_hierarchy_row");
|
||
|
let row = rows[0];
|
||
|
assert.containsOnce(row, ".o_hierarchy_node");
|
||
|
assert.strictEqual(row.querySelector(".o_hierarchy_node_content").textContent, "Albert");
|
||
|
row = rows[1];
|
||
|
assert.containsN(row, ".o_hierarchy_node", 2);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(row.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
[ // Name + Parent name
|
||
|
"GeorgesAlbert",
|
||
|
"JosephineAlbert",
|
||
|
],
|
||
|
);
|
||
|
row = rows[2];
|
||
|
assert.containsOnce(row, ".o_hierarchy_node");
|
||
|
assert.strictEqual(row.querySelector(".o_hierarchy_node_content").textContent, "LouisJosephine");
|
||
|
assert.verifySteps([
|
||
|
"get child data",
|
||
|
"fetch descendants",
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
QUnit.test("display child nodes with child_field set on the view", async function (assert) {
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
viewId: 1,
|
||
|
async mockRPC(route, args) {
|
||
|
if (args.method === "read") {
|
||
|
assert.step("get child data with descendants");
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node_button", 2);
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_button.btn-secondary");
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
await click(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_separator", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_line_part", 4);
|
||
|
assert.containsN(target, ".o_hierarchy_line_left", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_line_right", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node_container", 4);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 4);
|
||
|
assert.containsN(target, ".o_hierarchy_node_button", 2);
|
||
|
assert.containsNone(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_node_button.btn-secondary", 2);
|
||
|
assert.verifySteps([
|
||
|
"get child data with descendants",
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
QUnit.test("collapse child nodes", async function (assert) {
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsOnce(target, ".o_hierarchy_separator");
|
||
|
assert.containsN(target, ".o_hierarchy_line_part", 2);
|
||
|
assert.containsOnce(target, ".o_hierarchy_line_left");
|
||
|
assert.containsOnce(target, ".o_hierarchy_line_right");
|
||
|
assert.containsN(target, ".o_hierarchy_node_container", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
await click(target, ".o_hierarchy_node_button.btn-secondary");
|
||
|
assert.containsOnce(target, ".o_hierarchy_row");
|
||
|
assert.containsNone(target, ".o_hierarchy_separator");
|
||
|
assert.containsNone(target, ".o_hierarchy_line_part", 2);
|
||
|
assert.containsNone(target, ".o_hierarchy_line_left");
|
||
|
assert.containsNone(target, ".o_hierarchy_line_right");
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_container");
|
||
|
assert.containsOnce(target, ".o_hierarchy_node");
|
||
|
assert.containsNone(target, ".o_hierarchy_node_button.btn-secondary");
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_button");
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_container:not(.o_hierarchy_node_button)");
|
||
|
assert.deepEqual(getNodesTextContent(target.querySelectorAll(".o_hierarchy_row .o_hierarchy_node_content")), ["Albert"]);
|
||
|
});
|
||
|
|
||
|
QUnit.test("display the parent above the line when many records on the parent row", async function (assert) {
|
||
|
serverData.models["hr.employee"].records.push({
|
||
|
name: "Alfred",
|
||
|
parent_id: false,
|
||
|
child_ids: [],
|
||
|
})
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
|
||
|
assert.containsOnce(target, ".o_hierarchy_row");
|
||
|
assert.containsNone(target, ".o_hierarchy_separator");
|
||
|
assert.containsN(target, ".o_hierarchy_node", 2);
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
await click(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsOnce(target, ".o_hierarchy_separator");
|
||
|
assert.containsOnce(target, ".o_hierarchy_line_left");
|
||
|
assert.containsOnce(target, ".o_hierarchy_line_right");
|
||
|
assert.containsOnce(target, ".o_hierarchy_parent_node_container");
|
||
|
assert.strictEqual(target.querySelector(".o_hierarchy_parent_node_container").textContent, "Albert");
|
||
|
});
|
||
|
|
||
|
QUnit.test("search record in hierarchy view", async function (assert) {
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
domain: [["id", "=", 4]], // simulate a search
|
||
|
});
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_separator", 1);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["JosephineAlbert", "LouisJosephine"],
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("search record in hierarchy view with child field name defined in the arch", async function (assert) {
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
viewId: 1,
|
||
|
serverData,
|
||
|
domain: [["id", "=", 4]], // simulate a search
|
||
|
});
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_separator", 1);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["JosephineAlbert", "LouisJosephine"],
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("fetch parent record", async function (assert) {
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
domain: [["id", "=", 4]], // simulate a search
|
||
|
});
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_separator", 1);
|
||
|
let rows = target.querySelectorAll(".o_hierarchy_row");
|
||
|
let row = rows[0];
|
||
|
assert.containsOnce(row, ".o_hierarchy_node");
|
||
|
assert.strictEqual(row.querySelector(".o_hierarchy_node_content").textContent, "JosephineAlbert");
|
||
|
row = rows[1];
|
||
|
assert.containsOnce(row, ".o_hierarchy_node");
|
||
|
assert.strictEqual(row.querySelector(".o_hierarchy_node_content").textContent, "LouisJosephine");
|
||
|
assert.containsOnce(
|
||
|
target,
|
||
|
".o_hierarchy_node_container button .fa-chevron-up",
|
||
|
"Button to fetch the parent node should be visible on the first node displayed in the view."
|
||
|
);
|
||
|
await click(target, ".o_hierarchy_node_container button .fa-chevron-up");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 4);
|
||
|
assert.containsN(target, ".o_hierarchy_separator", 2);
|
||
|
rows = target.querySelectorAll(".o_hierarchy_row");
|
||
|
row = rows[0];
|
||
|
assert.containsOnce(row, ".o_hierarchy_node");
|
||
|
assert.strictEqual(row.querySelector(".o_hierarchy_node_content").textContent, "Albert");
|
||
|
row = rows[1];
|
||
|
assert.containsN(row, ".o_hierarchy_node", 2);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(row.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["GeorgesAlbert", "JosephineAlbert"],
|
||
|
);
|
||
|
row = rows[2];
|
||
|
assert.containsOnce(row, ".o_hierarchy_node");
|
||
|
assert.strictEqual(row.querySelector(".o_hierarchy_node_content").textContent, "LouisJosephine");
|
||
|
});
|
||
|
|
||
|
QUnit.test("fetch parent when there are many records without the same parent in the same row", async function (assert) {
|
||
|
serverData.models["hr.employee"].records.push(
|
||
|
{ id: 5, name: "Lisa", parent_id: 2, child_ids: []},
|
||
|
);
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
domain: [["name", "ilike", "l"]], // simulate a search
|
||
|
});
|
||
|
assert.containsOnce(target, ".o_hierarchy_row");
|
||
|
assert.containsN(target, ".o_hierarchy_node_container", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
[
|
||
|
"LisaGeorges", "LouisJosephine", "Albert",
|
||
|
],
|
||
|
);
|
||
|
assert.containsN(target, ".o_hierarchy_node_container button .fa-chevron-up", 2);
|
||
|
const firstNode = target.querySelector(".o_hierarchy_node_container");
|
||
|
await click(firstNode, ".o_hierarchy_node_container button .fa-chevron-up");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 2);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
[
|
||
|
"GeorgesAlbert", "LisaGeorges",
|
||
|
],
|
||
|
);
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_container button .fa-chevron-up");
|
||
|
await click(target, ".o_hierarchy_node_container button .fa-chevron-up");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 4);
|
||
|
});
|
||
|
|
||
|
QUnit.test("fetch parent when parent record is in the same row", async function (assert) {
|
||
|
serverData.models["hr.employee"].records.push(
|
||
|
{ id: 5, name: "Lisa", parent_id: 2, child_ids: []},
|
||
|
);
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
domain: [["id", "in", [1, 2, 3, 4, 5]]], // simulate a search
|
||
|
});
|
||
|
assert.containsOnce(target, ".o_hierarchy_row");
|
||
|
assert.containsN(target, ".o_hierarchy_node_container", 5);
|
||
|
assert.containsN(target, ".o_hierarchy_node_container button .fa-chevron-up", 4);
|
||
|
const firstNodeWithParentBtn = target.querySelector(".o_hierarchy_node_container:has(button .fa-chevron-up)");
|
||
|
await click(firstNodeWithParentBtn, ".o_hierarchy_node_container button .fa-chevron-up");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
[
|
||
|
"Albert", "GeorgesAlbert", "JosephineAlbert",
|
||
|
],
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("fetch parent of node with children displayed", async function (assert) {
|
||
|
serverData.models["hr.employee"].records.push(
|
||
|
{ id: 5, name: "Lisa", parent_id: 2, child_ids: []},
|
||
|
);
|
||
|
serverData.models["hr.employee"].records.find((rec) => rec.id === 2).child_ids.push(5);
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
domain: [["id", "in", [1, 2, 3, 4, 5]]], // simulate a search
|
||
|
});
|
||
|
assert.containsOnce(target, ".o_hierarchy_row");
|
||
|
assert.containsN(target, ".o_hierarchy_node_container", 5);
|
||
|
assert.containsN(target, ".o_hierarchy_node_container button .fa-chevron-up", 4);
|
||
|
const georgesNode = target.querySelector(".o_hierarchy_node_container:has(button[name=hierarchy_search_parent_node])");
|
||
|
assert.strictEqual(georgesNode.querySelector(".o_hierarchy_node_content").textContent, "GeorgesAlbert");
|
||
|
await click(georgesNode, "button[name=hierarchy_search_subsidiaries]");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 5);
|
||
|
const rows = target.querySelectorAll(".o_hierarchy_row");
|
||
|
let row = rows[0];
|
||
|
assert.containsN(row, ".o_hierarchy_node", 4);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(row.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert", "LouisJosephine"],
|
||
|
);
|
||
|
row = rows[1];
|
||
|
assert.containsN(row, ".o_hierarchy_node", 1);
|
||
|
assert.strictEqual(row.querySelector(".o_hierarchy_node_content").textContent, "LisaGeorges");
|
||
|
const firstNodeWithParentBtn = target.querySelector(".o_hierarchy_node_container:has(button .fa-chevron-up)");
|
||
|
await click(firstNodeWithParentBtn, ".o_hierarchy_node_container button .fa-chevron-up");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 4);
|
||
|
});
|
||
|
|
||
|
QUnit.test("drag and drop is disabled by default", async function (assert) {
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert"],
|
||
|
);
|
||
|
|
||
|
const nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const georgesNodeContainer = nodeContainers[1];
|
||
|
assert.strictEqual(georgesNodeContainer.querySelector(".o_hierarchy_node_content").textContent, "GeorgesAlbert");
|
||
|
|
||
|
await dragAndDrop(
|
||
|
georgesNodeContainer.querySelector(".o_hierarchy_node"),
|
||
|
".o_hierarchy_row:first-child"
|
||
|
);
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert"],
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("drag and drop record on another row", async function (assert) {
|
||
|
serverData.views["hr.employee,false,hierarchy"] = serverData.views["hr.employee,false,hierarchy"].replace("<hierarchy>", "<hierarchy draggable='1'>");
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert"],
|
||
|
);
|
||
|
|
||
|
const nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const georgesNodeContainer = nodeContainers[1];
|
||
|
assert.strictEqual(georgesNodeContainer.querySelector(".o_hierarchy_node_content").textContent, "GeorgesAlbert");
|
||
|
|
||
|
await dragAndDrop(
|
||
|
georgesNodeContainer.querySelector(".o_hierarchy_node"),
|
||
|
".o_hierarchy_row:first-child"
|
||
|
);
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "Georges", "JosephineAlbert"],
|
||
|
"Georges should no longer have a manager"
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("drag and drop record on sibling node", async function (assert) {
|
||
|
serverData.views["hr.employee,false,hierarchy"] = serverData.views["hr.employee,false,hierarchy"].replace("<hierarchy>", "<hierarchy draggable='1'>");
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert"],
|
||
|
);
|
||
|
|
||
|
const nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const georgesNodeContainer = nodeContainers[1];
|
||
|
const josephineNodeContainer = nodeContainers[2];
|
||
|
assert.strictEqual(georgesNodeContainer.querySelector(".o_hierarchy_node_content").textContent, "GeorgesAlbert");
|
||
|
assert.strictEqual(josephineNodeContainer.querySelector(".o_hierarchy_node_content").textContent, "JosephineAlbert");
|
||
|
|
||
|
await dragAndDrop(
|
||
|
georgesNodeContainer.querySelector(".o_hierarchy_node"),
|
||
|
josephineNodeContainer,
|
||
|
);
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 4);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "JosephineAlbert", "LouisJosephine", "GeorgesJosephine"],
|
||
|
"Georges should have Josephine as manager"
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("drag and drop record on node of another tree", async function (assert) {
|
||
|
serverData.views["hr.employee,1,hierarchy"] = serverData.views[
|
||
|
"hr.employee,1,hierarchy"
|
||
|
].replace(`<hierarchy child_field="child_ids">`, `<hierarchy child_field="child_ids" draggable="1">`);
|
||
|
serverData.models["hr.employee"].records = [
|
||
|
{ id: 1, name: "A", parent_id: false, child_ids: [3, 4] },
|
||
|
{ id: 2, name: "B", parent_id: false, child_ids: [] },
|
||
|
{ id: 3, name: "C", parent_id: 1, child_ids: [5] },
|
||
|
{ id: 4, name: "D", parent_id: 1, child_ids: [] },
|
||
|
{ id: 5, name: "E", parent_id: 3, child_ids: [] },
|
||
|
];
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
viewId: 1,
|
||
|
});
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 1);
|
||
|
await click(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
await click(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
let rowsContent = target.querySelectorAll(".o_hierarchy_row .o_hierarchy_node_content");
|
||
|
assert.deepEqual(getNodesTextContent(rowsContent), ["A", "B", "CA", "DA", "EC"]);
|
||
|
|
||
|
let nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const bNode = nodeContainers[1];
|
||
|
const dNode = nodeContainers[3];
|
||
|
assert.strictEqual(bNode.querySelector(".o_hierarchy_node_content").textContent, "B");
|
||
|
assert.strictEqual(dNode.querySelector(".o_hierarchy_node_content").textContent, "DA");
|
||
|
|
||
|
await dragAndDrop(
|
||
|
dNode.querySelector(".o_hierarchy_node"),
|
||
|
bNode,
|
||
|
);
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
rowsContent = target.querySelectorAll(".o_hierarchy_row .o_hierarchy_node_content");
|
||
|
assert.deepEqual(getNodesTextContent(rowsContent), ["A", "B", "DB"]);
|
||
|
|
||
|
nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const aNode = nodeContainers[0];
|
||
|
assert.strictEqual(aNode.querySelector(".o_hierarchy_node_content").textContent, "A");
|
||
|
|
||
|
await click(aNode, ".o_hierarchy_node_button.btn-primary");
|
||
|
|
||
|
nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const cNode = nodeContainers[2];
|
||
|
assert.strictEqual(cNode.querySelector(".o_hierarchy_node_content").textContent, "CA");
|
||
|
|
||
|
await click(cNode, ".o_hierarchy_node_button.btn-primary");
|
||
|
|
||
|
rowsContent = target.querySelectorAll(".o_hierarchy_row .o_hierarchy_node_content");
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(rowsContent),
|
||
|
["A", "B", "CA", "EC"],
|
||
|
"Nodes that were folded as a result of the drop operation should all still be unfoldable"
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("drag and drop node unfolded on first row", async function (assert) {
|
||
|
serverData.views["hr.employee,false,hierarchy"] = serverData.views["hr.employee,false,hierarchy"].replace("<hierarchy>", "<hierarchy draggable='1'>");
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert"],
|
||
|
);
|
||
|
|
||
|
let nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const josephineNodeContainer = nodeContainers[2];
|
||
|
assert.strictEqual(josephineNodeContainer.querySelector(".o_hierarchy_node_content").textContent, "JosephineAlbert");
|
||
|
await click(josephineNodeContainer, "button[name='hierarchy_search_subsidiaries']");
|
||
|
|
||
|
await dragAndDrop(
|
||
|
josephineNodeContainer.querySelector(".o_hierarchy_node"),
|
||
|
".o_hierarchy_row:first-child"
|
||
|
);
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "Josephine", "LouisJosephine"],
|
||
|
"Georges should have Josephine as manager"
|
||
|
);
|
||
|
|
||
|
nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const louisNodeContainer = nodeContainers[2];
|
||
|
assert.strictEqual(
|
||
|
louisNodeContainer.querySelector(".o_hierarchy_node_content").textContent,
|
||
|
"LouisJosephine"
|
||
|
);
|
||
|
|
||
|
await dragAndDrop(
|
||
|
louisNodeContainer.querySelector(".o_hierarchy_node"),
|
||
|
".o_hierarchy_row:first-child"
|
||
|
);
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 1);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "Josephine", "Louis"],
|
||
|
"Louis should still be draggable after being dragged along with Josephine"
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("drag and drop node when other node is unfolded on first row", async function (assert) {
|
||
|
serverData.views["hr.employee,false,hierarchy"] = serverData.views["hr.employee,false,hierarchy"].replace("<hierarchy>", "<hierarchy draggable='1'>");
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert"],
|
||
|
);
|
||
|
|
||
|
const nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const georgesNodeContainer = nodeContainers[1];
|
||
|
const josephineNodeContainer = nodeContainers[2];
|
||
|
assert.strictEqual(georgesNodeContainer.querySelector(".o_hierarchy_node_content").textContent, "GeorgesAlbert");
|
||
|
assert.strictEqual(josephineNodeContainer.querySelector(".o_hierarchy_node_content").textContent, "JosephineAlbert");
|
||
|
await click(josephineNodeContainer, "button[name='hierarchy_search_subsidiaries']");
|
||
|
|
||
|
await dragAndDrop(
|
||
|
georgesNodeContainer.querySelector(".o_hierarchy_node"),
|
||
|
".o_hierarchy_row:first-child"
|
||
|
);
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 4);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "Georges", "JosephineAlbert", "LouisJosephine"],
|
||
|
"Georges should no longer have a manager"
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("drag and drop node unfolded on another row", async function (assert) {
|
||
|
serverData.views["hr.employee,false,hierarchy"] = serverData.views[
|
||
|
"hr.employee,false,hierarchy"
|
||
|
].replace("<hierarchy>", "<hierarchy draggable='1'>");
|
||
|
serverData.models["hr.employee"].records = [
|
||
|
{ id: 1, name: "Albert", parent_id: false, child_ids: [2] },
|
||
|
{ id: 2, name: "Georges", parent_id: 1, child_ids: [3] },
|
||
|
{ id: 3, name: "Josephine", parent_id: 2, child_ids: [4] },
|
||
|
{ id: 4, name: "Louis", parent_id: 3, child_ids: [] },
|
||
|
{ id: 5, name: "Kelly", parent_id: 2, child_ids: [] },
|
||
|
];
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 2);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert"]
|
||
|
);
|
||
|
|
||
|
let nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const georgeNodeContainer = nodeContainers[1];
|
||
|
assert.strictEqual(
|
||
|
georgeNodeContainer.querySelector(".o_hierarchy_node_content").textContent,
|
||
|
"GeorgesAlbert"
|
||
|
);
|
||
|
await click(georgeNodeContainer, "button[name='hierarchy_search_subsidiaries']");
|
||
|
|
||
|
nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
let josephineNodeContainer = nodeContainers[2];
|
||
|
assert.strictEqual(
|
||
|
josephineNodeContainer.querySelector(".o_hierarchy_node_content").textContent,
|
||
|
"JosephineGeorges"
|
||
|
);
|
||
|
await click(josephineNodeContainer, "button[name='hierarchy_search_subsidiaries']");
|
||
|
|
||
|
nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
josephineNodeContainer = nodeContainers[2];
|
||
|
assert.strictEqual(
|
||
|
josephineNodeContainer.querySelector(".o_hierarchy_node_content").textContent,
|
||
|
"JosephineGeorges"
|
||
|
);
|
||
|
let louisNodeContainer = nodeContainers[4];
|
||
|
assert.strictEqual(
|
||
|
louisNodeContainer.querySelector(".o_hierarchy_node_content").textContent,
|
||
|
"LouisJosephine"
|
||
|
);
|
||
|
assert.containsN(target, ".o_hierarchy_row", 4);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineGeorges", "KellyGeorges", "LouisJosephine"],
|
||
|
"Kelly should be displayed"
|
||
|
);
|
||
|
|
||
|
await dragAndDrop(
|
||
|
josephineNodeContainer.querySelector(".o_hierarchy_node"),
|
||
|
":nth-child(2 of .o_hierarchy_row)"
|
||
|
);
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 4);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert", "LouisJosephine"],
|
||
|
"Josephine should have Albert as a manager and Kelly should be hidden"
|
||
|
);
|
||
|
|
||
|
nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
louisNodeContainer = nodeContainers[3];
|
||
|
assert.strictEqual(
|
||
|
louisNodeContainer.querySelector(".o_hierarchy_node_content").textContent,
|
||
|
"LouisJosephine"
|
||
|
);
|
||
|
|
||
|
await dragAndDrop(
|
||
|
louisNodeContainer.querySelector(".o_hierarchy_node"),
|
||
|
":nth-child(2 of .o_hierarchy_row)"
|
||
|
);
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 4);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert", "LouisAlbert"],
|
||
|
"Louis should still be draggable after being dragged along with Josephine"
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("drag and drop node as a child of a sibling of its parent", async function (assert) {
|
||
|
serverData.views["hr.employee,1,hierarchy"] = serverData.views[
|
||
|
"hr.employee,1,hierarchy"
|
||
|
].replace(`<hierarchy child_field="child_ids">`, `<hierarchy child_field="child_ids" draggable="1">`);
|
||
|
serverData.models["hr.employee"].records = [
|
||
|
{ id: 1, name: "A", parent_id: false, child_ids: [2, 3] },
|
||
|
{ id: 2, name: "B", parent_id: 1, child_ids: [4, 5] },
|
||
|
{ id: 3, name: "C", parent_id: 1, child_ids: [] },
|
||
|
{ id: 4, name: "D", parent_id: 2, child_ids: [] },
|
||
|
{ id: 5, name: "E", parent_id: 2, child_ids: [] },
|
||
|
];
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
viewId: 1,
|
||
|
});
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
await click(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
let rowsContent = target.querySelectorAll(".o_hierarchy_row .o_hierarchy_node_content");
|
||
|
assert.deepEqual(getNodesTextContent(rowsContent), ["A", "BA", "CA", "DB", "EB"]);
|
||
|
|
||
|
let nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const cNode = nodeContainers[2];
|
||
|
const eNode = nodeContainers[4];
|
||
|
assert.strictEqual(cNode.querySelector(".o_hierarchy_node_content").textContent, "CA");
|
||
|
assert.strictEqual(eNode.querySelector(".o_hierarchy_node_content").textContent, "EB");
|
||
|
|
||
|
await dragAndDrop(
|
||
|
eNode.querySelector(".o_hierarchy_node"),
|
||
|
cNode,
|
||
|
);
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
rowsContent = target.querySelectorAll(".o_hierarchy_row .o_hierarchy_node_content");
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(rowsContent), ["A", "BA", "CA", "EC"],
|
||
|
"B should be folded and C unfolded"
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("drag node and move it on a row", async function (assert) {
|
||
|
serverData.views["hr.employee,false,hierarchy"] = serverData.views["hr.employee,false,hierarchy"].replace("<hierarchy>", "<hierarchy draggable='1'>");
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
const nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const georgesNodeContainer = nodeContainers[1];
|
||
|
assert.strictEqual(georgesNodeContainer.querySelector(".o_hierarchy_node_content").textContent, "GeorgesAlbert");
|
||
|
|
||
|
const { drop, moveTo } = await drag(georgesNodeContainer.querySelector(".o_hierarchy_node"));
|
||
|
|
||
|
await moveTo(".o_hierarchy_row:first-child");
|
||
|
assert.hasClass(georgesNodeContainer, "o_hierarchy_dragged");
|
||
|
assert.hasClass(target.querySelector(".o_hierarchy_row"), "o_hierarchy_hover");
|
||
|
|
||
|
await drop();
|
||
|
assert.containsNone(target, ".o_hierarchy_node.o_hierarchy_dragged");
|
||
|
assert.containsNone(target, ".o_hierarchy_row.o_hierarchy_hover");
|
||
|
});
|
||
|
|
||
|
QUnit.test("drag node and move it on another node", async function (assert) {
|
||
|
serverData.views["hr.employee,false,hierarchy"] = serverData.views["hr.employee,false,hierarchy"].replace("<hierarchy>", "<hierarchy draggable='1'>");
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
const nodeContainers = target.querySelectorAll(".o_hierarchy_node_container");
|
||
|
const georgesNodeContainer = nodeContainers[1];
|
||
|
const josephineNodeContainer = nodeContainers[2];
|
||
|
assert.strictEqual(georgesNodeContainer.querySelector(".o_hierarchy_node_content").textContent, "GeorgesAlbert");
|
||
|
assert.strictEqual(josephineNodeContainer.querySelector(".o_hierarchy_node_content").textContent, "JosephineAlbert");
|
||
|
|
||
|
const { drop, moveTo } = await drag(georgesNodeContainer.querySelector(".o_hierarchy_node"));
|
||
|
|
||
|
await moveTo(josephineNodeContainer.querySelector(".o_hierarchy_node"));
|
||
|
assert.hasClass(georgesNodeContainer, "o_hierarchy_dragged");
|
||
|
assert.hasClass(georgesNodeContainer.querySelector(".o_hierarchy_node"), "shadow");
|
||
|
assert.hasClass(josephineNodeContainer, "o_hierarchy_hover");
|
||
|
|
||
|
await drop();
|
||
|
assert.containsNone(target, ".o_hierarchy_node.o_hierarchy_dragged");
|
||
|
assert.containsNone(target, ".o_hierarchy_node.o_hierarchy_hover");
|
||
|
assert.containsNone(target, ".o_hierarchy_node.shadow");
|
||
|
});
|
||
|
|
||
|
QUnit.test("drag node to scroll", async function (assert) {
|
||
|
serverData.views["hr.employee,false,hierarchy"] = serverData.views[
|
||
|
"hr.employee,false,hierarchy"
|
||
|
].replace("<hierarchy>", "<hierarchy draggable='1'>");
|
||
|
serverData.models["hr.employee"].records = [
|
||
|
{ id: 1, name: "A", parent_id: false, child_ids: [2] },
|
||
|
{ id: 2, name: "B", parent_id: 1, child_ids: [3] },
|
||
|
{ id: 3, name: "C", parent_id: 2, child_ids: [4] },
|
||
|
{ id: 4, name: "D", parent_id: 3, child_ids: [5] },
|
||
|
{ id: 5, name: "E", parent_id: 4, child_ids: [] },
|
||
|
{ id: 6, name: "F", parent_id: false, child_ids: [] },
|
||
|
];
|
||
|
const { advanceFrame } = mockAnimationFrame();
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
|
||
|
// Fully open the view
|
||
|
assert.containsN(target, ".o_hierarchy_row", 1);
|
||
|
await click(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
await click(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
await click(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 4);
|
||
|
await click(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 5);
|
||
|
const rowsContent = target.querySelectorAll(".o_hierarchy_row .o_hierarchy_node_content");
|
||
|
assert.deepEqual(getNodesTextContent(rowsContent), ["A", "F", "BA", "CB", "DC", "ED"]);
|
||
|
await nextTick();
|
||
|
|
||
|
// Limit the height and enable scrolling
|
||
|
const content = target.querySelector(".o_content");
|
||
|
content.setAttribute("style", "min-height:600px;max-height:600px;overflow-y:auto;");
|
||
|
assert.strictEqual(content.scrollTop, 0);
|
||
|
assert.strictEqual(content.getBoundingClientRect().height, 600);
|
||
|
|
||
|
const nodes = [...content.querySelectorAll(".o_hierarchy_node")];
|
||
|
const fNode = nodes.find((n) => n.textContent === "F");
|
||
|
const dragActions = await drag(fNode);
|
||
|
await dragActions.moveTo(".o_hierarchy_row:last-child");
|
||
|
assert.strictEqual(content.scrollTop, 0);
|
||
|
|
||
|
await advanceFrame();
|
||
|
|
||
|
// default speed of 20px per frame
|
||
|
assert.strictEqual(content.scrollTop, 20);
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_container.o_hierarchy_dragged");
|
||
|
|
||
|
// next 100 frames (2000px of scrolling)
|
||
|
await advanceFrame(100);
|
||
|
|
||
|
// should be at the end of the content
|
||
|
assert.strictEqual(content.clientHeight + content.scrollTop, content.scrollHeight);
|
||
|
|
||
|
await dragActions.moveTo(".o_hierarchy_row:first-child");
|
||
|
assert.strictEqual(content.clientHeight + content.scrollTop, content.scrollHeight);
|
||
|
|
||
|
await advanceFrame();
|
||
|
|
||
|
// default speed of 20px per frame
|
||
|
assert.strictEqual(content.clientHeight + content.scrollTop, content.scrollHeight - 20);
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_container.o_hierarchy_dragged");
|
||
|
|
||
|
// next 100 frames (2000px of scrolling)
|
||
|
await advanceFrame(100);
|
||
|
|
||
|
// should be at the top of the content
|
||
|
assert.strictEqual(content.scrollTop, 0);
|
||
|
|
||
|
// cancel drag: press "Escape"
|
||
|
triggerHotkey("Escape");
|
||
|
await nextTick();
|
||
|
|
||
|
assert.containsNone(target, ".o_hierarchy_node_container.o_hierarchy_dragged");
|
||
|
});
|
||
|
|
||
|
QUnit.test("check default icon is correctly used inside button to display child nodes", async function (assert) {
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
|
||
|
assert.containsOnce(target, ".o_hierarchy_node button[name=hierarchy_search_subsidiaries].btn-primary");
|
||
|
assert.strictEqual(target.querySelector(".o_hierarchy_node button[name=hierarchy_search_subsidiaries].btn-primary").textContent.trim(), "Unfold 1");
|
||
|
assert.containsOnce(
|
||
|
target,
|
||
|
".o_hierarchy_node button[name=hierarchy_search_subsidiaries] i.fa-share-alt.o_hierarchy_icon",
|
||
|
"The default icon of the hierarchy view should be displayed inside the button to unfold the node."
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("use other icon used next to Unfold string displayed inside the button", async function (assert) {
|
||
|
serverData.views["hr.employee,false,hierarchy"] = serverData.views["hr.employee,false,hierarchy"].replace("<hierarchy>", "<hierarchy icon='fa-users'>");
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
});
|
||
|
|
||
|
assert.containsOnce(target, ".o_hierarchy_node button[name=hierarchy_search_subsidiaries].btn-primary");
|
||
|
assert.strictEqual(target.querySelector(".o_hierarchy_node button[name=hierarchy_search_subsidiaries].btn-primary").textContent.trim(), "Unfold 1");
|
||
|
assert.containsOnce(
|
||
|
target,
|
||
|
".o_hierarchy_node button[name=hierarchy_search_subsidiaries] i.fa-users",
|
||
|
"The icon defined in the attribute icon in hierarchy tag should be displayed inside the button to unfold the node instead of the default one."
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("use `hierarchy_res_id` context to load the view at that specific node with its siblings and parent node", async function (assert) {
|
||
|
serverData.models["hr.employee"].records.push(
|
||
|
{ id: 5, name: "Lisa", parent_id: 3, child_ids: []},
|
||
|
);
|
||
|
serverData.models["hr.employee"].records.find((rec) => rec.id === 3).child_ids.push(5);
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
context: {
|
||
|
hierarchy_res_id: 5,
|
||
|
},
|
||
|
});
|
||
|
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["JosephineAlbert", "LisaJosephine", "LouisJosephine"]
|
||
|
);
|
||
|
assert.containsOnce(target, ".o_hierarchy_node_container button[name=hierarchy_search_parent_node]");
|
||
|
});
|
||
|
|
||
|
QUnit.test("cannot set the record dragged as parent", async function (assert) {
|
||
|
serverData.views["hr.employee,false,hierarchy"] = serverData.views["hr.employee,false,hierarchy"].replace("<hierarchy>", "<hierarchy draggable='1'>");
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
mockRPC(route, { method, model }) {
|
||
|
if (method === "write" && model === "hr.employee") {
|
||
|
assert.step("setManager");
|
||
|
}
|
||
|
},
|
||
|
});
|
||
|
|
||
|
patchWithCleanup(browser, {
|
||
|
setTimeout: () => 1,
|
||
|
});
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert"]
|
||
|
);
|
||
|
const rows = target.querySelectorAll(".o_hierarchy_row");
|
||
|
await dragAndDrop(
|
||
|
target.querySelector(".o_hierarchy_node"), // select first node (Albert)
|
||
|
rows[1]
|
||
|
);
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert"]
|
||
|
);
|
||
|
assert.containsOnce(target, ".o_notification");
|
||
|
assert.containsOnce(target, ".o_notification.border-danger");
|
||
|
|
||
|
assert.verifySteps([]);
|
||
|
});
|
||
|
|
||
|
QUnit.test("cannot create cyclic", async function (assert) {
|
||
|
serverData.views["hr.employee,false,hierarchy"] = serverData.views["hr.employee,false,hierarchy"].replace("<hierarchy>", "<hierarchy draggable='1'>");
|
||
|
await makeView({
|
||
|
type: "hierarchy",
|
||
|
resModel: "hr.employee",
|
||
|
serverData,
|
||
|
mockRPC(route, { method, model }) {
|
||
|
if (method === "write" && model === "hr.employee") {
|
||
|
assert.step("setManager");
|
||
|
}
|
||
|
},
|
||
|
});
|
||
|
|
||
|
patchWithCleanup(browser, {
|
||
|
setTimeout: () => 1,
|
||
|
});
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert"]
|
||
|
);
|
||
|
let nodes = target.querySelectorAll(".o_hierarchy_node");
|
||
|
await dragAndDrop(
|
||
|
nodes[0], // albert node
|
||
|
nodes[1] // georges node
|
||
|
);
|
||
|
assert.containsN(target, ".o_hierarchy_row", 2);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 3);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert"]
|
||
|
);
|
||
|
assert.containsOnce(target, ".o_notification");
|
||
|
assert.containsOnce(target, ".o_notification.border-danger");
|
||
|
|
||
|
await click(target, ".o_hierarchy_node_button.btn-primary");
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 4);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert", "LouisJosephine"]
|
||
|
);
|
||
|
nodes = target.querySelectorAll(".o_hierarchy_node");
|
||
|
await dragAndDrop(
|
||
|
nodes[0],
|
||
|
nodes[3]
|
||
|
);
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 4);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert", "LouisJosephine"]
|
||
|
);
|
||
|
assert.containsN(target, ".o_notification", 2);
|
||
|
assert.containsN(target, ".o_notification.border-danger", 2);
|
||
|
|
||
|
const rows = target.querySelectorAll(".o_hierarchy_row");
|
||
|
await dragAndDrop(
|
||
|
nodes[0],
|
||
|
rows[2]
|
||
|
);
|
||
|
assert.containsN(target, ".o_hierarchy_row", 3);
|
||
|
assert.containsN(target, ".o_hierarchy_node", 4);
|
||
|
assert.deepEqual(
|
||
|
getNodesTextContent(target.querySelectorAll(".o_hierarchy_node_content")),
|
||
|
["Albert", "GeorgesAlbert", "JosephineAlbert", "LouisJosephine"]
|
||
|
);
|
||
|
assert.containsN(target, ".o_notification", 3);
|
||
|
assert.containsN(target, ".o_notification.border-danger", 3);
|
||
|
|
||
|
assert.verifySteps([]);
|
||
|
});
|
||
|
});
|