338 lines
12 KiB
JavaScript
338 lines
12 KiB
JavaScript
|
/** @odoo-module */
|
||
|
|
||
|
import {
|
||
|
getFixture,
|
||
|
click,
|
||
|
nextTick,
|
||
|
editInput,
|
||
|
makeDeferred,
|
||
|
patchWithCleanup,
|
||
|
} from "@web/../tests/helpers/utils";
|
||
|
import { browser } from "@web/core/browser/browser";
|
||
|
import { getDashboardServerData } from "../utils/data";
|
||
|
import { getBasicData, getBasicListArchs } from "@spreadsheet/../tests/utils/data";
|
||
|
import { createSpreadsheetDashboard } from "../utils/dashboard_action";
|
||
|
import { keyDown } from "@spreadsheet/../tests/utils/ui";
|
||
|
import { RPCError } from "@web/core/network/rpc_service";
|
||
|
import { errorService } from "@web/core/errors/error_service";
|
||
|
import { registry } from "@web/core/registry";
|
||
|
|
||
|
QUnit.module("spreadsheet_dashboard > Dashboard > Dashboard action");
|
||
|
|
||
|
function getServerData(spreadsheetData) {
|
||
|
const serverData = getDashboardServerData();
|
||
|
serverData.models = {
|
||
|
...serverData.models,
|
||
|
...getBasicData(),
|
||
|
};
|
||
|
serverData.views = getBasicListArchs();
|
||
|
serverData.models["spreadsheet.dashboard.group"].records = [
|
||
|
{
|
||
|
dashboard_ids: [789],
|
||
|
id: 1,
|
||
|
name: "Pivot",
|
||
|
},
|
||
|
];
|
||
|
serverData.models["spreadsheet.dashboard"].records = [
|
||
|
{
|
||
|
id: 789,
|
||
|
name: "Spreadsheet with Pivot",
|
||
|
json_data: JSON.stringify(spreadsheetData),
|
||
|
spreadsheet_data: JSON.stringify(spreadsheetData),
|
||
|
dashboard_group_id: 1,
|
||
|
},
|
||
|
];
|
||
|
return serverData;
|
||
|
}
|
||
|
|
||
|
QUnit.test("display available spreadsheets", async (assert) => {
|
||
|
await createSpreadsheetDashboard();
|
||
|
assert.containsN(getFixture(), ".o_search_panel section", 2);
|
||
|
assert.containsN(getFixture(), ".o_search_panel li", 3);
|
||
|
});
|
||
|
|
||
|
QUnit.test("display the active spreadsheet", async (assert) => {
|
||
|
await createSpreadsheetDashboard();
|
||
|
assert.containsOnce(
|
||
|
getFixture(),
|
||
|
".o_search_panel li.active",
|
||
|
"It should have one active element"
|
||
|
);
|
||
|
assert.containsOnce(getFixture(), ".o-spreadsheet", "It should display the spreadsheet");
|
||
|
});
|
||
|
|
||
|
QUnit.test("load action with specific dashboard", async (assert) => {
|
||
|
await createSpreadsheetDashboard({ spreadsheetId: 3 });
|
||
|
const active = getFixture().querySelector(".o_search_panel li.active");
|
||
|
assert.strictEqual(active.innerText, "Dashboard Accounting 1");
|
||
|
});
|
||
|
|
||
|
QUnit.test("can switch spreadsheet", async (assert) => {
|
||
|
await createSpreadsheetDashboard();
|
||
|
const fixture = getFixture();
|
||
|
const spreadsheets = fixture.querySelectorAll(".o_search_panel li");
|
||
|
assert.ok(spreadsheets[0].className.includes("active"));
|
||
|
assert.notOk(spreadsheets[1].className.includes("active"));
|
||
|
assert.notOk(spreadsheets[2].className.includes("active"));
|
||
|
await click(spreadsheets[1]);
|
||
|
assert.notOk(spreadsheets[0].className.includes("active"));
|
||
|
assert.ok(spreadsheets[1].className.includes("active"));
|
||
|
assert.notOk(spreadsheets[2].className.includes("active"));
|
||
|
});
|
||
|
|
||
|
QUnit.test("display no dashboard message", async (assert) => {
|
||
|
await createSpreadsheetDashboard({
|
||
|
mockRPC: function (route, { model, method, args }) {
|
||
|
if (method === "web_search_read" && model === "spreadsheet.dashboard.group") {
|
||
|
return {
|
||
|
records: [],
|
||
|
length: 0,
|
||
|
};
|
||
|
}
|
||
|
},
|
||
|
});
|
||
|
const fixture = getFixture();
|
||
|
assert.containsNone(fixture, ".o_search_panel li", "It should not display any spreadsheet");
|
||
|
assert.strictEqual(
|
||
|
fixture.querySelector(".dashboard-loading-status").innerText,
|
||
|
"No available dashboard",
|
||
|
"It should display no dashboard message"
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test("display error message", async (assert) => {
|
||
|
registry.category("services").add("error", errorService);
|
||
|
await createSpreadsheetDashboard({
|
||
|
mockRPC: function (route, args) {
|
||
|
if (
|
||
|
args.model === "spreadsheet.dashboard" &&
|
||
|
args.method === "get_readonly_dashboard" &&
|
||
|
args.args[0] === 2
|
||
|
) {
|
||
|
const error = new RPCError();
|
||
|
error.data = {};
|
||
|
throw error;
|
||
|
}
|
||
|
},
|
||
|
});
|
||
|
const fixture = getFixture();
|
||
|
const spreadsheets = fixture.querySelectorAll(".o_search_panel li");
|
||
|
assert.containsOnce(fixture, ".o-spreadsheet", "It should display the spreadsheet");
|
||
|
await click(spreadsheets[1]);
|
||
|
assert.containsOnce(
|
||
|
fixture,
|
||
|
".o_spreadsheet_dashboard_action .dashboard-loading-status.error",
|
||
|
"It should display an error"
|
||
|
);
|
||
|
await click(spreadsheets[0]);
|
||
|
assert.containsOnce(fixture, ".o-spreadsheet", "It should display the spreadsheet");
|
||
|
assert.containsNone(fixture, ".o_renderer .error", "It should not display an error");
|
||
|
});
|
||
|
|
||
|
QUnit.test("load dashboard that doesn't exist", async (assert) => {
|
||
|
registry.category("services").add("error", errorService);
|
||
|
await createSpreadsheetDashboard({
|
||
|
spreadsheetId: 999,
|
||
|
});
|
||
|
const fixture = getFixture();
|
||
|
assert.containsOnce(
|
||
|
fixture,
|
||
|
".o_spreadsheet_dashboard_action .dashboard-loading-status.error",
|
||
|
"It should display an error"
|
||
|
);
|
||
|
});
|
||
|
|
||
|
QUnit.test(
|
||
|
"Last selected spreadsheet is kept when go back from breadcrumb",
|
||
|
async function (assert) {
|
||
|
const spreadsheetData = {
|
||
|
sheets: [
|
||
|
{
|
||
|
id: "sheet1",
|
||
|
cells: { A1: { content: `=PIVOT("1", "probability")` } },
|
||
|
},
|
||
|
],
|
||
|
pivots: {
|
||
|
1: {
|
||
|
id: 1,
|
||
|
colGroupBys: ["foo"],
|
||
|
domain: [],
|
||
|
measures: [{ field: "probability", operator: "avg" }],
|
||
|
model: "partner",
|
||
|
rowGroupBys: ["bar"],
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
const serverData = getServerData(spreadsheetData);
|
||
|
const fixture = getFixture();
|
||
|
await createSpreadsheetDashboard({ serverData });
|
||
|
await click(fixture, ".o_search_panel li:last-child");
|
||
|
await click(fixture, ".o-dashboard-clickable-cell");
|
||
|
assert.containsOnce(fixture, ".o_list_view");
|
||
|
await click(document.body.querySelector(".o_back_button"));
|
||
|
assert.hasClass(fixture.querySelector(".o_search_panel li:last-child"), "active");
|
||
|
}
|
||
|
);
|
||
|
|
||
|
QUnit.test(
|
||
|
"Can clear filter date filter value that defaults to current period",
|
||
|
async function (assert) {
|
||
|
const spreadsheetData = {
|
||
|
globalFilters: [
|
||
|
{
|
||
|
id: "1",
|
||
|
type: "date",
|
||
|
label: "Date Filter",
|
||
|
rangeType: "fixedPeriod",
|
||
|
defaultValue: "this_year",
|
||
|
},
|
||
|
],
|
||
|
};
|
||
|
const serverData = getServerData(spreadsheetData);
|
||
|
const fixture = getFixture();
|
||
|
await createSpreadsheetDashboard({ serverData });
|
||
|
const year = fixture.querySelector(".o_control_panel_actions input.o_datetime_input");
|
||
|
const this_year = luxon.DateTime.local().year;
|
||
|
assert.equal(year.value, String(this_year));
|
||
|
const input = fixture.querySelector("input.o_datetime_input");
|
||
|
await click(input);
|
||
|
await editInput(input, null, String(this_year - 1));
|
||
|
await nextTick();
|
||
|
|
||
|
assert.equal(year.value, String(this_year - 1));
|
||
|
assert.containsOnce(fixture, ".o_control_panel_actions .fa-times");
|
||
|
await click(fixture.querySelector(".o_control_panel_actions .fa-times"));
|
||
|
|
||
|
assert.containsNone(fixture, ".o_control_panel_actions .fa-times");
|
||
|
assert.equal(year.placeholder, "Select year...");
|
||
|
}
|
||
|
);
|
||
|
|
||
|
QUnit.test("Can delete record tag in the filter by hitting Backspace", async function (assert) {
|
||
|
const spreadsheetData = {
|
||
|
globalFilters: [
|
||
|
{
|
||
|
id: "1",
|
||
|
type: "relation",
|
||
|
label: "Relation Filter",
|
||
|
modelName: "product",
|
||
|
defaultValue: [37],
|
||
|
automaticDefaultValue: true,
|
||
|
},
|
||
|
],
|
||
|
};
|
||
|
const serverData = getServerData(spreadsheetData);
|
||
|
const fixture = getFixture();
|
||
|
await createSpreadsheetDashboard({ serverData });
|
||
|
const filter = fixture.querySelector(".o_control_panel_actions div.o_multi_record_selector");
|
||
|
const autoCompleteInput = filter.querySelector(".o-autocomplete--input.o_input");
|
||
|
assert.equal(filter.querySelectorAll(".o_tag").length, 1);
|
||
|
|
||
|
autoCompleteInput.focus();
|
||
|
await keyDown({ key: "Backspace" });
|
||
|
assert.equal(filter.querySelectorAll(".o_tag").length, 0);
|
||
|
});
|
||
|
|
||
|
QUnit.test("share dashboard from dashboard view", async function (assert) {
|
||
|
const target = getFixture();
|
||
|
patchWithCleanup(browser, {
|
||
|
navigator: {
|
||
|
clipboard: {
|
||
|
writeText: (url) => {
|
||
|
assert.step("share url copied");
|
||
|
assert.strictEqual(url, "localhost:8069/share/url/132465");
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
});
|
||
|
const def = makeDeferred();
|
||
|
await createSpreadsheetDashboard({
|
||
|
mockRPC: async function (route, args) {
|
||
|
if (args.method === "action_get_share_url") {
|
||
|
await def;
|
||
|
assert.step("dashboard_shared");
|
||
|
assert.strictEqual(args.model, "spreadsheet.dashboard.share");
|
||
|
return "localhost:8069/share/url/132465";
|
||
|
}
|
||
|
},
|
||
|
});
|
||
|
assert.strictEqual(target.querySelector(".spreadsheet_share_dropdown"), null);
|
||
|
await click(target, "i.fa-share-alt");
|
||
|
assert.equal(
|
||
|
target.querySelector(".spreadsheet_share_dropdown")?.innerText,
|
||
|
"Generating sharing link"
|
||
|
);
|
||
|
def.resolve();
|
||
|
await nextTick();
|
||
|
assert.verifySteps(["dashboard_shared", "share url copied"]);
|
||
|
assert.strictEqual(
|
||
|
target.querySelector(".o_field_CopyClipboardChar").innerText,
|
||
|
"localhost:8069/share/url/132465"
|
||
|
);
|
||
|
await click(target, ".fa-clipboard");
|
||
|
assert.verifySteps(["share url copied"]);
|
||
|
});
|
||
|
|
||
|
QUnit.test("Changing filter values will create a new share", async function (assert) {
|
||
|
const spreadsheetData = {
|
||
|
globalFilters: [
|
||
|
{
|
||
|
id: "1",
|
||
|
type: "date",
|
||
|
label: "Date Filter",
|
||
|
rangeType: "fixedPeriod",
|
||
|
defaultValue: "this_year",
|
||
|
},
|
||
|
],
|
||
|
};
|
||
|
const serverData = getServerData(spreadsheetData);
|
||
|
const target = getFixture();
|
||
|
let counter = 0;
|
||
|
patchWithCleanup(browser, {
|
||
|
navigator: {
|
||
|
clipboard: {
|
||
|
writeText: (url) => {},
|
||
|
},
|
||
|
},
|
||
|
});
|
||
|
await createSpreadsheetDashboard({
|
||
|
serverData,
|
||
|
mockRPC: async function (route, args) {
|
||
|
if (args.method === "action_get_share_url") {
|
||
|
return `localhost:8069/share/url/${++counter}`;
|
||
|
}
|
||
|
},
|
||
|
});
|
||
|
await click(target, "i.fa-share-alt");
|
||
|
await nextTick();
|
||
|
assert.strictEqual(
|
||
|
target.querySelector(".o_field_CopyClipboardChar").innerText,
|
||
|
`localhost:8069/share/url/1`
|
||
|
);
|
||
|
|
||
|
await click(target, "i.fa-share-alt"); // close share dropdown
|
||
|
|
||
|
await click(target, "i.fa-share-alt");
|
||
|
await nextTick();
|
||
|
assert.strictEqual(
|
||
|
target.querySelector(".o_field_CopyClipboardChar").innerText,
|
||
|
`localhost:8069/share/url/1`
|
||
|
);
|
||
|
|
||
|
await click(target, "i.fa-share-alt");
|
||
|
const year = target.querySelector(".o_control_panel_actions input.o_datetime_input");
|
||
|
const this_year = luxon.DateTime.local().year;
|
||
|
assert.equal(year.value, String(this_year));
|
||
|
const input = target.querySelector("input.o_datetime_input");
|
||
|
await click(input);
|
||
|
await editInput(input, null, String(this_year - 1));
|
||
|
await nextTick();
|
||
|
|
||
|
await click(target, "i.fa-share-alt");
|
||
|
await nextTick();
|
||
|
assert.strictEqual(
|
||
|
target.querySelector(".o_field_CopyClipboardChar")?.innerText,
|
||
|
`localhost:8069/share/url/2`
|
||
|
);
|
||
|
});
|