Files
enterprise-addons/documents_spreadsheet/static/tests/pivot/ui/pivot_sidepanel.test.js
T

183 lines
7.3 KiB
JavaScript

import { defineDocumentSpreadsheetModels } from "@documents_spreadsheet/../tests/helpers/data";
import { createSpreadsheetFromPivotView } from "@documents_spreadsheet/../tests/helpers/pivot_helpers";
import { getHighlightsFromStore } from "@documents_spreadsheet/../tests/helpers/store_helpers";
import { beforeEach, describe, expect, getFixture, test } from "@odoo/hoot";
import { animationFrame } from "@odoo/hoot-dom";
import { getBasicPivotArch } from "@spreadsheet/../tests/helpers/data";
import {
getZoneOfInsertedDataSource,
insertPivotInSpreadsheet,
} from "@spreadsheet/../tests/helpers/pivot";
import * as dsHelpers from "@web/../tests/core/tree_editor/condition_tree_editor_test_helpers";
import { contains, onRpc, MockServer } from "@web/../tests/web_test_helpers";
import { updatePivot } from "@spreadsheet/../tests/helpers/commands";
defineDocumentSpreadsheetModels();
describe.current.tags("desktop");
let target;
beforeEach(() => {
target = getFixture();
});
test("Update the pivot domain from the side panel", async function () {
onRpc("/web/domain/validate", () => true);
const { model, env, pivotId } = await createSpreadsheetFromPivotView();
env.openSidePanel("PivotSidePanel", { pivotId });
await animationFrame();
await contains(".pivot-defer-update input").click();
await contains(".o_edit_domain").click();
await dsHelpers.addNewRule();
await contains(".modal-footer .btn-primary").click();
expect(model.getters.getPivotCoreDefinition(pivotId).domain).toEqual([], {
message: "update is deferred",
});
await contains(".pivot-defer-update .o-button-link").click();
expect(model.getters.getPivotCoreDefinition(pivotId).domain).toEqual([["id", "=", 1]]);
expect(dsHelpers.getConditionText()).toBe("Id = 1");
});
test("Opening the sidepanel of a pivot while the panel of another pivot is open updates the side panel", async function () {
const { model, env, pivotId } = await createSpreadsheetFromPivotView();
const arch = /* xml */ `
<pivot string="Product">
<field name="name" type="col"/>
<field name="active" type="row"/>
<field name="__count" type="measure"/>
</pivot>`;
const pivotId2 = "PIVOT#2";
await insertPivotInSpreadsheet(model, "PIVOT#2", {
arch,
resModel: "product",
id: pivotId2,
});
env.openSidePanel("PivotSidePanel", { pivotId });
await animationFrame();
expect(".o-section .o_model_name").toHaveText("Partner (partner)");
env.openSidePanel("PivotSidePanel", { pivotId: pivotId2 });
await animationFrame();
expect(".o-section .o_model_name").toHaveText("Product (product)");
});
test("Deleting the pivot open the side panel with all pivots", async function () {
const { model, env, pivotId } = await createSpreadsheetFromPivotView();
await insertPivotInSpreadsheet(model, "pivot2", { arch: getBasicPivotArch() });
env.openSidePanel("PivotSidePanel", { pivotId });
await animationFrame();
expect(".o-sidePanelTitle").toHaveText("Pivot #1");
model.dispatch("REMOVE_PIVOT", { pivotId });
await animationFrame();
expect(".o-sidePanel").toHaveCount(0);
});
test("Pivot with missing dimension does not crash when opening side panel", async function () {
const { model, env } = await createSpreadsheetFromPivotView({
mockRPC: async function (route, { model, method, kwargs }) {
if (model === "res.currency" && method === "fields_get") {
const fields = MockServer.env["res.currency"].fields_get();
delete fields["name"];
return fields;
}
},
});
await insertPivotInSpreadsheet(model, "pivot2", {
arch: `<pivot string="Product">
<field name="name" type="col"/>
<field name="currency_id" type="row"/>
<field name="__count" type="measure"/>
</pivot>`,
resModel: "product",
id: "pivot2",
});
updatePivot(model, "pivot2", {
rows: [{ fieldName: "currency_id.name", order: "asc" }],
columns: [],
});
env.openSidePanel("PivotSidePanel", { pivotId: "pivot2" });
await animationFrame();
expect(".o-sidePanelTitle").toHaveText("Pivot #2");
});
test("Undo a pivot insertion open the side panel with all pivots", async function () {
const { model, env } = await createSpreadsheetFromPivotView();
await insertPivotInSpreadsheet(model, "pivot2", { arch: getBasicPivotArch() });
env.openSidePanel("PivotSidePanel", { pivotId: "pivot2" });
await animationFrame();
expect(".o-sidePanelTitle").toHaveText("Pivot #2");
/**
* This is a bit bad because we need three undo to remove the pivot
* - AUTORESIZE
* - INSERT_PIVOT
* - ADD_PIVOT
*/
model.dispatch("REQUEST_UNDO");
model.dispatch("REQUEST_UNDO");
model.dispatch("REQUEST_UNDO");
await animationFrame();
expect(".o-sidePanel").toHaveCount(0);
});
test("Pivot cells are highlighted when their side panel is open", async function () {
const { model, env, pivotId } = await createSpreadsheetFromPivotView();
const sheetId = model.getters.getActiveSheetId();
const range = model.getters.getRangeFromZone(
sheetId,
getZoneOfInsertedDataSource(model, "pivot", pivotId)
);
expect(getHighlightsFromStore(env)).toEqual([{ color: "#017E84", range, noFill: true }]);
await contains(".o-sidePanelClose").click();
expect(getHighlightsFromStore(env)).toEqual([]);
});
test("Can change measure display as from the side panel", async function () {
const { model, env } = await createSpreadsheetFromPivotView();
const pivotId = model.getters.getPivotIds()[0];
env.openSidePanel("PivotSidePanel", { pivotId });
await animationFrame();
await contains(".pivot-measure .fa-cog").click();
await contains(".o-sidePanel select").select("%_of");
expect(model.getters.getPivotCoreDefinition(pivotId).measures[0]).toEqual({
id: "probability:avg",
fieldName: "probability",
aggregator: "avg",
display: {
type: "%_of",
fieldNameWithGranularity: "foo",
value: "(previous)",
},
});
});
test("Pivot side panel is disabled and dimmed in read-only mode but still scrollable", async function () {
const { model, env } = await createSpreadsheetFromPivotView();
const pivotId = model.getters.getPivotIds()[0];
env.openSidePanel("PivotSidePanel", { pivotId });
await animationFrame();
const sidePanel = target.querySelector(".o-sidePanel");
expect(".o-sidePanelBody div[inert]").toHaveCount(0);
model.updateMode("readonly");
await animationFrame();
const scrollableContainer = sidePanel.querySelector(".overflow-y-auto");
expect(scrollableContainer).toHaveCount(1);
// The [inert] wrapper with `pe-none` and `opacity-50` is placed inside the scrollable container,
// ensuring that user interactions are blocked while still allowing vertical scrolling.
const interactiveWrapper = scrollableContainer.querySelector(".o-sidePanelBody div[inert]");
expect(interactiveWrapper).toHaveClass("pe-none");
expect(interactiveWrapper).toHaveClass("opacity-50");
expect(interactiveWrapper).toHaveAttribute("inert", "1");
expect(".pivot-defer-update").toHaveCount(0);
});