1113 lines
47 KiB
JavaScript
1113 lines
47 KiB
JavaScript
import { defineSpreadsheetModels, Partner, Product } from "@spreadsheet/../tests/helpers/data";
|
|
import { describe, expect, test } from "@odoo/hoot";
|
|
import { animationFrame } from "@odoo/hoot-mock";
|
|
import * as spreadsheet from "@odoo/o-spreadsheet";
|
|
const { toCartesian, toZone } = spreadsheet.helpers;
|
|
import {
|
|
autofill,
|
|
selectCell,
|
|
setCellContent,
|
|
setCellFormat,
|
|
setCellStyle,
|
|
updatePivot,
|
|
} from "@spreadsheet/../tests/helpers/commands";
|
|
import { getCellFormula, getCell } from "@spreadsheet/../tests/helpers/getters";
|
|
import { createSpreadsheetWithPivot } from "@spreadsheet/../tests/helpers/pivot";
|
|
import { createModelFromGrid } from "@spreadsheet/../tests/helpers/model";
|
|
import { waitForDataLoaded } from "@spreadsheet/helpers/model";
|
|
import { allowTranslations } from "@web/../tests/web_test_helpers";
|
|
|
|
describe.current.tags("headless");
|
|
defineSpreadsheetModels();
|
|
|
|
/**
|
|
* Get the computed value that would be autofilled starting from the given xc.
|
|
* The starting xc should contains a Pivot formula
|
|
*/
|
|
function getPivotAutofillValue(model, xc, { direction, steps }) {
|
|
const content = getCellFormula(model, xc);
|
|
const column = ["left", "right"].includes(direction);
|
|
const increment = ["left", "top"].includes(direction) ? -steps : steps;
|
|
return model.getters.getPivotNextAutofillValue(content, column, increment);
|
|
}
|
|
|
|
test("Autofill pivot values", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({ pivotType: "static" });
|
|
|
|
// From value to value
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "bottom", steps: 1 })).toBe(
|
|
getCellFormula(model, "C4")
|
|
);
|
|
expect(getPivotAutofillValue(model, "B4", { direction: "top", steps: 1 })).toBe(
|
|
getCellFormula(model, "B3")
|
|
);
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "right", steps: 1 })).toBe(
|
|
getCellFormula(model, "D3")
|
|
);
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "left", steps: 1 })).toBe(
|
|
getCellFormula(model, "B3")
|
|
);
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "bottom", steps: 2 })).toBe(
|
|
getCellFormula(model, "C5")
|
|
);
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "bottom", steps: 3 })).toBe("");
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "right", steps: 4 })).toBe("");
|
|
// From value to header
|
|
expect(getPivotAutofillValue(model, "B4", { direction: "left", steps: 1 })).toBe(
|
|
getCellFormula(model, "A4")
|
|
);
|
|
expect(getPivotAutofillValue(model, "B4", { direction: "top", steps: 1 })).toBe(
|
|
getCellFormula(model, "B3")
|
|
);
|
|
expect(getPivotAutofillValue(model, "B4", { direction: "top", steps: 2 })).toBe(
|
|
getCellFormula(model, "B2")
|
|
);
|
|
expect(getPivotAutofillValue(model, "B4", { direction: "top", steps: 3 })).toBe(
|
|
getCellFormula(model, "B1")
|
|
);
|
|
// From header to header
|
|
expect(getPivotAutofillValue(model, "B3", { direction: "right", steps: 1 })).toBe(
|
|
getCellFormula(model, "C3")
|
|
);
|
|
expect(getPivotAutofillValue(model, "B3", { direction: "right", steps: 2 })).toBe(
|
|
getCellFormula(model, "D3")
|
|
);
|
|
expect(getPivotAutofillValue(model, "B3", { direction: "left", steps: 1 })).toBe(
|
|
getCellFormula(model, "A3")
|
|
);
|
|
expect(getPivotAutofillValue(model, "B1", { direction: "bottom", steps: 1 })).toBe(
|
|
getCellFormula(model, "B2")
|
|
);
|
|
expect(getPivotAutofillValue(model, "B3", { direction: "top", steps: 1 })).toBe(
|
|
getCellFormula(model, "B2")
|
|
);
|
|
expect(getPivotAutofillValue(model, "A4", { direction: "bottom", steps: 1 })).toBe(
|
|
getCellFormula(model, "A5")
|
|
);
|
|
expect(getPivotAutofillValue(model, "A4", { direction: "top", steps: 1 })).toBe(
|
|
getCellFormula(model, "A3")
|
|
);
|
|
expect(getPivotAutofillValue(model, "A4", { direction: "bottom", steps: 2 })).toBe("");
|
|
expect(getPivotAutofillValue(model, "A4", { direction: "top", steps: 3 })).toBe("");
|
|
// From header to value
|
|
expect(getPivotAutofillValue(model, "B2", { direction: "bottom", steps: 1 })).toBe(
|
|
getCellFormula(model, "B3")
|
|
);
|
|
expect(getPivotAutofillValue(model, "B2", { direction: "bottom", steps: 2 })).toBe(
|
|
getCellFormula(model, "B4")
|
|
);
|
|
expect(getPivotAutofillValue(model, "B2", { direction: "bottom", steps: 4 })).toBe("");
|
|
expect(getPivotAutofillValue(model, "A3", { direction: "right", steps: 1 })).toBe(
|
|
getCellFormula(model, "B3")
|
|
);
|
|
expect(getPivotAutofillValue(model, "A3", { direction: "right", steps: 5 })).toBe(
|
|
getCellFormula(model, "F3")
|
|
);
|
|
expect(getPivotAutofillValue(model, "A3", { direction: "right", steps: 6 })).toBe("");
|
|
// From total row header to value
|
|
expect(getPivotAutofillValue(model, "A5", { direction: "right", steps: 1 })).toBe(
|
|
getCellFormula(model, "B5")
|
|
);
|
|
expect(getPivotAutofillValue(model, "A5", { direction: "right", steps: 5 })).toBe(
|
|
getCellFormula(model, "F5")
|
|
);
|
|
});
|
|
|
|
test("Autofill with pivot positions", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({ pivotType: "static" });
|
|
setCellContent(model, "C3", `=PIVOT.VALUE(1,"probability","#bar",1,"#foo",1)`);
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "left", steps: 1 })).toBe(
|
|
`=PIVOT.VALUE(1,"probability","#bar",1,"#foo",0)`
|
|
);
|
|
/** Would be negative => just copy the value */
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "left", steps: 2 })).toBe(
|
|
`=PIVOT.VALUE(1,"probability","#bar",1,"#foo",1)`
|
|
);
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "right", steps: 1 })).toBe(
|
|
`=PIVOT.VALUE(1,"probability","#bar",1,"#foo",2)`
|
|
);
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "right", steps: 10 })).toBe(
|
|
`=PIVOT.VALUE(1,"probability","#bar",1,"#foo",11)`
|
|
);
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "top", steps: 1 })).toBe(
|
|
`=PIVOT.VALUE(1,"probability","#bar",0,"#foo",1)`
|
|
);
|
|
/** Would be negative => just copy the value */
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "top", steps: 2 })).toBe(
|
|
`=PIVOT.VALUE(1,"probability","#bar",1,"#foo",1)`
|
|
);
|
|
expect(getPivotAutofillValue(model, "C3", { direction: "bottom", steps: 1 })).toBe(
|
|
`=PIVOT.VALUE(1,"probability","#bar",2,"#foo",1)`
|
|
);
|
|
expect(
|
|
getPivotAutofillValue(model, "C3", {
|
|
direction: "bottom",
|
|
steps: 10,
|
|
})
|
|
).toBe(`=PIVOT.VALUE(1,"probability","#bar",11,"#foo",1)`);
|
|
});
|
|
|
|
test("Autofill with references works like any regular function (no custom autofill)", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({ pivotType: "static" });
|
|
setCellContent(model, "A1", `=PIVOT.VALUE(1,"probability","bar",B2,"foo",$C$3)`);
|
|
selectCell(model, "A1");
|
|
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 1 });
|
|
model.dispatch("AUTOFILL");
|
|
expect(getCellFormula(model, "A2")).toBe(`=PIVOT.VALUE(1,"probability","bar",B3,"foo",$C$3)`);
|
|
});
|
|
|
|
test("Autofill non-odoo pivot should copy the formula", function () {
|
|
allowTranslations();
|
|
// prettier-ignore
|
|
const grid = {
|
|
A1: "Customer",
|
|
B1: "Price",
|
|
C1: `=PIVOT.VALUE(1, "Price")`,
|
|
A2: "Alice",
|
|
B2: "10",
|
|
A3: "",
|
|
B3: "20",
|
|
A4: "Olaf",
|
|
B4: "30",
|
|
};
|
|
const model = createModelFromGrid(grid);
|
|
const pivot = {
|
|
name: "Pivot",
|
|
type: "SPREADSHEET",
|
|
dataSet: {
|
|
zone: toZone("A1:B4"),
|
|
sheetId: model.getters.getActiveSheetId(),
|
|
},
|
|
rows: [{ fieldName: "Customer", order: "asc" }],
|
|
columns: [],
|
|
measures: [{ id: "price", fieldName: "Price", aggregator: "sum" }],
|
|
};
|
|
model.dispatch("ADD_PIVOT", { pivot, pivotId: "1" });
|
|
selectCell(model, "C1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 2, row: 1 });
|
|
model.dispatch("AUTOFILL");
|
|
expect(getCellFormula(model, "C2")).toBe(`=PIVOT.VALUE(1, "Price")`);
|
|
});
|
|
|
|
test("Can autofill positional col headers horizontally", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="product_id" type="col"/>
|
|
<field name="date" interval="month" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
setCellContent(model, "B1", `=PIVOT.HEADER(1,"#product_id",1)`);
|
|
expect(getPivotAutofillValue(model, "B1", { direction: "right", steps: 1 })).toBe(
|
|
`=PIVOT.HEADER(1,"#product_id",2)`
|
|
);
|
|
selectCell(model, "B1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 2, row: 0 });
|
|
const tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent).toEqual([{ value: "xpad" }]);
|
|
});
|
|
|
|
test("Can autofill positional row headers vertically", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="tag_ids" type="col"/>
|
|
<field name="date" interval="month" type="row"/>
|
|
<field name="product_id" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
setCellContent(model, "A3", `=PIVOT.HEADER(1,"date:month",DATE(2016,4,1),"#product_id",1)`);
|
|
expect(getPivotAutofillValue(model, "A3", { direction: "bottom", steps: 1 })).toBe(
|
|
`=PIVOT.HEADER(1,"date:month",DATE(2016,4,1),"#product_id",2)`
|
|
);
|
|
selectCell(model, "A3");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 1, row: 3 });
|
|
const tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent).toEqual([{ value: "April 2016" }, { value: "" }]);
|
|
});
|
|
|
|
test("Can autofill positional row headers horizontally", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="date" interval="month" type="col"/>
|
|
<field name="product_id" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
});
|
|
setCellContent(model, "A3", `=PIVOT.HEADER(1,"#product_id",1)`);
|
|
expect(getPivotAutofillValue(model, "A3", { direction: "right", steps: 1 })).toBe(
|
|
`=PIVOT.VALUE(1,"probability:avg","date:month",DATE(2016,4,1))`
|
|
);
|
|
selectCell(model, "A3");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 1, row: 3 });
|
|
const tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent).toEqual([{ value: "xpad" }]);
|
|
});
|
|
|
|
test("Can autofill positional col horizontally", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="product_id" type="col"/>
|
|
<field name="date" interval="month" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
setCellContent(model, "B1", `=PIVOT.VALUE(1,"probability","#product_id",1)`);
|
|
expect(getPivotAutofillValue(model, "B1", { direction: "right", steps: 1 })).toBe(
|
|
`=PIVOT.VALUE(1,"probability","#product_id",2)`
|
|
);
|
|
selectCell(model, "B1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 2, row: 0 });
|
|
const tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent).toEqual([{ value: "xpad" }]);
|
|
});
|
|
|
|
test("Can autofill positional row vertically", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="tag_ids" type="col"/>
|
|
<field name="date" interval="month" type="row"/>
|
|
<field name="product_id" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
setCellContent(
|
|
model,
|
|
"A3",
|
|
`=PIVOT.VALUE(1,"probability","date:month",DATE(2016,4,1),"#product_id",1)`
|
|
);
|
|
expect(getPivotAutofillValue(model, "A3", { direction: "bottom", steps: 1 })).toBe(
|
|
`=PIVOT.VALUE(1,"probability","date:month",DATE(2016,4,1),"#product_id",2)`
|
|
);
|
|
selectCell(model, "A3");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 1, row: 3 });
|
|
const tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent).toEqual([{ value: "April 2016" }, { value: "" }]);
|
|
});
|
|
test("Autofill last column cells vertically by targeting col headers", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({ pivotType: "static" });
|
|
expect(getPivotAutofillValue(model, "F3", { direction: "top", steps: 1 })).toBe(
|
|
getCellFormula(model, "F2")
|
|
);
|
|
expect(getPivotAutofillValue(model, "F3", { direction: "top", steps: 2 })).toBe(
|
|
getCellFormula(model, "F1")
|
|
);
|
|
expect(getPivotAutofillValue(model, "F5", { direction: "top", steps: 3 })).toBe(
|
|
getCellFormula(model, "F2")
|
|
);
|
|
expect(getPivotAutofillValue(model, "F5", { direction: "top", steps: 4 })).toBe(
|
|
getCellFormula(model, "F1")
|
|
);
|
|
setCellContent(model, "H10", `=PIVOT.VALUE(1,"probability:avg","bar","true")`);
|
|
expect(getPivotAutofillValue(model, "H10", { direction: "top", steps: 5 })).toBe("");
|
|
});
|
|
|
|
test("Autofill pivot values with date in rows", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="foo" type="col"/>
|
|
<field name="date" interval="month" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
expect(getPivotAutofillValue(model, "A3", { direction: "bottom", steps: 1 })).toBe(
|
|
getCellFormula(model, "A4").replace("DATE(2016,10,1)", "DATE(2016,5,1)")
|
|
);
|
|
expect(getPivotAutofillValue(model, "A5", { direction: "bottom", steps: 1 })).toBe(
|
|
'=PIVOT.HEADER(1,"date:month",DATE(2017,1,1))'
|
|
);
|
|
expect(getPivotAutofillValue(model, "B3", { direction: "bottom", steps: 1 })).toBe(
|
|
getCellFormula(model, "B4").replace("DATE(2016,10,1)", "DATE(2016,5,1)")
|
|
);
|
|
expect(getPivotAutofillValue(model, "B5", { direction: "bottom", steps: 1 })).toBe(
|
|
getCellFormula(model, "B5").replace("DATE(2016,12,1)", "DATE(2017,1,1)")
|
|
);
|
|
expect(getPivotAutofillValue(model, "B5", { direction: "top", steps: 1 })).toBe(
|
|
getCellFormula(model, "B4").replace("DATE(2016,10,1)", "DATE(2016,11,1)")
|
|
);
|
|
expect(getPivotAutofillValue(model, "F6", { direction: "top", steps: 1 })).toBe("");
|
|
});
|
|
|
|
test("Autofill pivot values with date in cols", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="foo" type="row"/>
|
|
<field name="date" interval="day" type="col"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
expect(getCellFormula(model, "B1")).toBe('=PIVOT.HEADER(1,"date:day",DATE(2016,4,14))');
|
|
expect(getPivotAutofillValue(model, "B1", { direction: "right", steps: 1 })).toBe(
|
|
'=PIVOT.HEADER(1,"date:day",DATE(2016,4,15))'
|
|
);
|
|
expect(getCellFormula(model, "B2")).toBe(
|
|
'=PIVOT.HEADER(1,"date:day",DATE(2016,4,14),"measure","probability:avg")'
|
|
);
|
|
expect(getPivotAutofillValue(model, "B2", { direction: "right", steps: 1 })).toBe(
|
|
'=PIVOT.HEADER(1,"date:day",DATE(2016,4,15),"measure","probability:avg")'
|
|
);
|
|
expect(getCellFormula(model, "B3")).toBe(
|
|
'=PIVOT.VALUE(1,"probability:avg","foo",1,"date:day",DATE(2016,4,14))'
|
|
);
|
|
expect(getPivotAutofillValue(model, "B3", { direction: "right", steps: 1 })).toBe(
|
|
'=PIVOT.VALUE(1,"probability:avg","foo",1,"date:day",DATE(2016,4,15))'
|
|
);
|
|
|
|
setCellContent(model, "C1", '=PIVOT.HEADER(1,"date:day",DATE(2016,4,15))');
|
|
expect(getPivotAutofillValue(model, "C1", { direction: "bottom", steps: 1 })).toBe(
|
|
'=PIVOT.HEADER(1,"date:day",DATE(2016,4,15),"measure","probability:avg")'
|
|
);
|
|
expect(getPivotAutofillValue(model, "C1", { direction: "bottom", steps: 2 })).toBe(
|
|
'=PIVOT.VALUE(1,"probability:avg","foo",1,"date:day",DATE(2016,4,15))'
|
|
);
|
|
});
|
|
|
|
test("Autofill pivot values with date in cols and multiple cols", async (assert) => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="date" interval="month" type="col"/>
|
|
<field name="product_id" type="col"/>
|
|
<field name="tag_ids" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
});
|
|
setCellContent(model, "H2", '=PIVOT.HEADER(1,"date:month","05/2016")');
|
|
expect(getPivotAutofillValue(model, "H2", { direction: "bottom", steps: 1 })).toBe("");
|
|
expect(getPivotAutofillValue(model, "H2", { direction: "bottom", steps: 2 })).toBe("");
|
|
expect(getPivotAutofillValue(model, "H2", { direction: "bottom", steps: 3 })).toBe("");
|
|
});
|
|
|
|
test("Autofill pivot values with date (day)", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="foo" type="col"/>
|
|
<field name="date" interval="day" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
expect(getCellFormula(model, "A3")).toBe('=PIVOT.HEADER(1,"date:day",DATE(2016,4,14))');
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "A3"))).toEqual([
|
|
{ value: "14 Apr 2016" },
|
|
]);
|
|
expect(getPivotAutofillValue(model, "A3", { direction: "bottom", steps: 1 })).toBe(
|
|
'=PIVOT.HEADER(1,"date:day",DATE(2016,4,15))'
|
|
);
|
|
});
|
|
|
|
test("Autofill pivot values with date (week) 2020 has 53 weeks", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="date" interval="week" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
setCellContent(model, "A1", '=PIVOT.HEADER(1,"date:week","52/2020")');
|
|
expect(getPivotAutofillValue(model, "A1", { direction: "bottom", steps: 1 })).toBe(
|
|
'=PIVOT.HEADER(1,"date:week","53/2020")'
|
|
);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "A1"))).toEqual([
|
|
{ value: "W52 2020" },
|
|
]);
|
|
});
|
|
|
|
test("Autofill empty pivot date value", async function () {
|
|
const { model, pivotId } = await createSpreadsheetWithPivot({
|
|
arch: /* xml */ `
|
|
<pivot>
|
|
<field name="date" interval="year" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
for (const granularity of [
|
|
"day",
|
|
"week",
|
|
"month",
|
|
"quarter",
|
|
"year",
|
|
"quarter_number",
|
|
"month_number",
|
|
"iso_week_number",
|
|
"day_of_month",
|
|
]) {
|
|
updatePivot(model, pivotId, {
|
|
rows: [{ fieldName: "date", granularity, order: "asc" }],
|
|
});
|
|
await animationFrame();
|
|
setCellContent(model, "A1", `=PIVOT.HEADER(1,"date:${granularity}",FALSE)`);
|
|
expect(getPivotAutofillValue(model, "A1", { direction: "bottom", steps: 1 })).toBe(
|
|
`=PIVOT.HEADER(1,"date:${granularity}",FALSE)`
|
|
);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "A1"))).toEqual([
|
|
{ value: "None" },
|
|
]);
|
|
}
|
|
});
|
|
|
|
test("Autofill past bound pivot date value", async function () {
|
|
const { model, pivotId } = await createSpreadsheetWithPivot({
|
|
arch: /* xml */ `
|
|
<pivot>
|
|
<field name="date" interval="year" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
});
|
|
|
|
const granularities = [
|
|
["quarter_number", 1, 4],
|
|
["month_number", 1, 12],
|
|
["iso_week_number", 0, 54],
|
|
["day_of_month", 1, 31],
|
|
];
|
|
|
|
const steps = [1, 10, 20, 30, 40, 50, 60, 70, 80];
|
|
|
|
for (const grIdx in granularities) {
|
|
const [granularity, lowerBound, upperBound] = granularities[grIdx];
|
|
updatePivot(model, pivotId, {
|
|
rows: [{ fieldName: "date", granularity, order: "asc" }],
|
|
});
|
|
await animationFrame();
|
|
setCellContent(model, "A1", `=PIVOT.HEADER(1,"date:${granularity}",1)`);
|
|
for (const stepIdx in steps) {
|
|
const step = steps[stepIdx];
|
|
const expectedValue = 1 + step;
|
|
const expectedFormula =
|
|
lowerBound <= expectedValue && expectedValue <= upperBound
|
|
? `=PIVOT.HEADER(1,"date:${granularity}",${expectedValue})`
|
|
: "";
|
|
expect(getPivotAutofillValue(model, "A1", { direction: "bottom", steps: step })).toBe(
|
|
expectedFormula
|
|
);
|
|
}
|
|
}
|
|
});
|
|
|
|
test("Autofill pivot values with date (month)", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="foo" type="col"/>
|
|
<field name="date" interval="month" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
expect(getPivotAutofillValue(model, "A3", { direction: "bottom", steps: 1 })).toBe(
|
|
`=PIVOT.HEADER(1,"date:month",DATE(2016,5,1))`
|
|
);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "A3"))).toEqual([
|
|
{ value: "April 2016" },
|
|
]);
|
|
});
|
|
|
|
test("Autofill pivot values with date (quarter)", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="foo" type="col"/>
|
|
<field name="date" interval="quarter" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
expect(getPivotAutofillValue(model, "A3", { direction: "bottom", steps: 1 })).toBe(
|
|
getCellFormula(model, "A3").replace("2/2016", "3/2016")
|
|
);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "A3"))).toEqual([
|
|
{ value: "Q2 2016" },
|
|
]);
|
|
});
|
|
|
|
test("Autofill pivot values with date (year)", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="foo" type="col"/>
|
|
<field name="date" interval="year" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
expect(getPivotAutofillValue(model, "A3", { direction: "bottom", steps: 1 })).toBe(
|
|
getCellFormula(model, "A3").replace("2016", "2017")
|
|
);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "A3"))).toEqual([
|
|
{ value: "2016" },
|
|
]);
|
|
});
|
|
|
|
test("Autofill pivot values with date (no defined interval)", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="foo" type="col"/>
|
|
<field name="date" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
expect(getPivotAutofillValue(model, "A3", { direction: "bottom", steps: 1 })).toBe(
|
|
`=PIVOT.HEADER(1,"date:month",DATE(2016,5,1))`
|
|
);
|
|
});
|
|
|
|
test("Tooltip of pivot formulas", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="foo" type="col"/>
|
|
<field name="date" interval="year" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "A3"))).toEqual([
|
|
{ value: "2016" },
|
|
]);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "B3"))).toEqual([
|
|
{ value: "2016" },
|
|
]);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "E3"))).toEqual([
|
|
{ value: "2016" },
|
|
]);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "F3"))).toEqual([
|
|
{ value: "2016" },
|
|
]);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "B1"))).toEqual([{ value: "1" }]);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "B2"))).toEqual([
|
|
{ value: "1" },
|
|
{ value: "Probability" },
|
|
]);
|
|
expect(model.getters.getTooltipFormula(`=PIVOT.HEADER("1")`, true)).toEqual([
|
|
{ value: "Total" },
|
|
]);
|
|
expect(model.getters.getTooltipFormula(`=PIVOT.HEADER("1")`, false)).toEqual([
|
|
{ value: "Total" },
|
|
]);
|
|
});
|
|
|
|
test("Tooltip of pivot formulas with 2 measures", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="name" type="col"/>
|
|
<field name="date" interval="year" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
<field name="foo" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "A3"))).toEqual([
|
|
{ value: "2016" },
|
|
]);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "B3"))).toEqual([
|
|
{ value: "2016" },
|
|
]);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "C3"), true)).toEqual([
|
|
{ value: "Raoul" },
|
|
{ value: "Foo" },
|
|
]);
|
|
});
|
|
|
|
test("Tooltip of empty pivot formula is empty", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="name" type="col"/>
|
|
<field name="date" interval="year" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
<field name="foo" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
selectCell(model, "A3");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 15, row: 15 });
|
|
expect(model.getters.getAutofillTooltip()).toBe(undefined);
|
|
});
|
|
|
|
test("Autofill content which contains pivots but which is not a pivot", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="foo" type="col"/>
|
|
<field name="date" interval="year" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
const a3 = getCellFormula(model, "A3").replace("=", "");
|
|
const content = `=${a3} + ${a3}`;
|
|
setCellContent(model, "F6", content);
|
|
expect(getPivotAutofillValue(model, "F6", { direction: "bottom", steps: 1 })).toBe(content);
|
|
expect(getPivotAutofillValue(model, "F6", { direction: "right", steps: 1 })).toBe(content);
|
|
});
|
|
|
|
test("Autofill pivot formula with missing pivotId", async function () {
|
|
allowTranslations();
|
|
const model = new spreadsheet.Model({
|
|
sheets: [
|
|
{
|
|
colNumber: 1,
|
|
rowNumber: 2,
|
|
cells: {
|
|
A1: '=PIVOT.VALUE("1","bar","date","05/2023")',
|
|
B1: '=PIVOT.HEADER("1","date","05/2023")',
|
|
},
|
|
},
|
|
],
|
|
});
|
|
expect(getPivotAutofillValue(model, "A1", { direction: "bottom", steps: 1 })).toBe(
|
|
'=PIVOT.VALUE("1","bar","date","05/2023")'
|
|
);
|
|
expect(getPivotAutofillValue(model, "B1", { direction: "bottom", steps: 1 })).toBe(
|
|
'=PIVOT.HEADER("1","date","05/2023")'
|
|
);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "A1"), false)).toEqual([
|
|
{
|
|
title: "Missing pivot",
|
|
value: "Missing pivot #1",
|
|
},
|
|
]);
|
|
expect(model.getters.getTooltipFormula(getCellFormula(model, "B1"), false)).toEqual([
|
|
{
|
|
title: "Missing pivot",
|
|
value: "Missing pivot #1",
|
|
},
|
|
]);
|
|
});
|
|
|
|
test("Can autofill col headers horizontally", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="tag_ids" type="col"/>
|
|
<field name="date" interval="year" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
const sortedTagNames = ["isCool", "Growing", "None"];
|
|
selectCell(model, "B1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 2, row: 0 });
|
|
let tooltipContent;
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe(sortedTagNames[1]);
|
|
selectCell(model, "C1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 3, row: 0 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe(sortedTagNames[2]);
|
|
selectCell(model, "D1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 4, row: 0 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("Total");
|
|
selectCell(model, "E1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 5, row: 0 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe(sortedTagNames[0]);
|
|
});
|
|
|
|
test("Can autofill col headers vertically", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="tag_ids" type="col"/>
|
|
<field name="date" interval="year" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
|
|
selectCell(model, "B1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 1, row: 1 });
|
|
let tooltipContent;
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("Probability");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 1, row: 2 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("2016");
|
|
selectCell(model, "C1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 2, row: 1 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("Probability");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 2, row: 2 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("2016");
|
|
selectCell(model, "D1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 3, row: 1 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("Probability");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 3, row: 2 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("2016");
|
|
selectCell(model, "E1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 4, row: 1 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("Probability");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 4, row: 2 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("2016");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 4, row: 3 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("Total");
|
|
});
|
|
|
|
test("Can autofill row headers horizontally", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="tag_ids" type="col"/>
|
|
<field name="date" interval="month" type="row"/>
|
|
<field name="product_id" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
const sortedTagNames = ["isCool", "Growing", "None"];
|
|
let tooltipContent;
|
|
selectCell(model, "A3");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 1, row: 2 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe(sortedTagNames[0]);
|
|
selectCell(model, "A4");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 2, row: 3 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe(sortedTagNames[1]);
|
|
selectCell(model, "A5");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 1, row: 4 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe(sortedTagNames[0]);
|
|
selectCell(model, "A6");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 3, row: 5 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe(sortedTagNames[2]);
|
|
selectCell(model, "A7");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 1, row: 6 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe(sortedTagNames[0]);
|
|
selectCell(model, "A8");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 4, row: 7 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("Total");
|
|
selectCell(model, "A9");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 1, row: 8 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe(sortedTagNames[0]);
|
|
});
|
|
|
|
test("Can autofill row headers vertically", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="tag_ids" type="col"/>
|
|
<field name="date" interval="month" type="row"/>
|
|
<field name="product_id" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
let tooltipContent;
|
|
selectCell(model, "A3");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 3 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("xphone");
|
|
selectCell(model, "A4");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 4 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("October 2016");
|
|
selectCell(model, "A5");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 5 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("xpad");
|
|
selectCell(model, "A6");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 6 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("December 2016");
|
|
selectCell(model, "A7");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 7 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("xpad");
|
|
selectCell(model, "A8");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 8 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("Total");
|
|
selectCell(model, "A9");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 9 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("Probability");
|
|
});
|
|
|
|
test("Can autofill with month string parent group header and value", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="date" interval="month" type="row"/>
|
|
<field name="product_id" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
});
|
|
let tooltipContent;
|
|
setCellContent(model, "A1", '=PIVOT.HEADER(1,"date:month","04/2016","product_id",37)');
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 1 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("October 2016");
|
|
model.dispatch("AUTOFILL");
|
|
expect(getCell(model, "A2").content).toBe('=PIVOT.HEADER(1,"date:month",DATE(2016,10,1))');
|
|
|
|
setCellContent(
|
|
model,
|
|
"A1",
|
|
'=PIVOT.VALUE(1,"probability:avg","date:month","04/2016","product_id",37)'
|
|
);
|
|
selectCell(model, "A1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 1 });
|
|
tooltipContent = model.getters.getAutofillTooltip().props.content;
|
|
expect(tooltipContent[tooltipContent.length - 1].value).toBe("October 2016");
|
|
model.dispatch("AUTOFILL");
|
|
expect(getCell(model, "A2").content).toBe(
|
|
'=PIVOT.VALUE(1,"probability:avg","date:month",DATE(2016,10,1))'
|
|
);
|
|
});
|
|
|
|
test("Cannot autofill with invalid parent group header and value", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="date" interval="month" type="row"/>
|
|
<field name="product_id" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
});
|
|
setCellContent(model, "A1", '=PIVOT.HEADER(1,"date:month",TRUE,"product_id",37)');
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 1 });
|
|
expect(model.getters.getAutofillTooltip()).toBe(undefined);
|
|
model.dispatch("AUTOFILL");
|
|
expect(getCell(model, "A2")).toBe(undefined);
|
|
|
|
setCellContent(
|
|
model,
|
|
"A1",
|
|
'=PIVOT.VALUE(1,"probability:avg","date:month",TRUE,"product_id",37)'
|
|
);
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 1 });
|
|
expect(model.getters.getAutofillTooltip()).toBe(undefined);
|
|
model.dispatch("AUTOFILL");
|
|
expect(getCell(model, "A2")).toBe(undefined);
|
|
});
|
|
|
|
test("Autofill pivot keeps format but neither style nor border", async function () {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="date" type="col"/>
|
|
<field name="product_id" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
|
|
// Change the format, style and borders of E3
|
|
const sheetId = model.getters.getActiveSheetId();
|
|
const { col, row } = toCartesian("E3");
|
|
const border = {
|
|
left: { style: "thin", color: "#000" },
|
|
};
|
|
const style = { textColor: "orange" };
|
|
setCellStyle(model, "E3", style);
|
|
setCellFormat(model, "E3", "#,##0.0");
|
|
model.dispatch("SET_BORDER", { sheetId, col, row, border });
|
|
|
|
// Change the format of E4
|
|
setCellFormat(model, "E4", "#,##0.000");
|
|
|
|
// Check that the format, style and border of E3 have been correctly applied
|
|
autofill(model, "E3", "E4");
|
|
const startingCell = getCell(model, "E3");
|
|
expect(startingCell.style).toEqual(style);
|
|
expect(model.getters.getCellBorder({ sheetId, col, row }).left).toEqual(border.left);
|
|
expect(startingCell.format).toBe("#,##0.0");
|
|
|
|
// Check that the format of E3 has been correctly applied to E4 but not the style nor the border
|
|
const filledCell = getCell(model, "E4");
|
|
expect(filledCell.style).toBe(undefined);
|
|
expect(model.getters.getCellBorder({ sheetId, col, row: row + 1 })).toBe(null);
|
|
expect(filledCell.format).toBe("#,##0.0");
|
|
});
|
|
|
|
test("Can autofill pivot horizontally with column grouped by date", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="date" interval="month" type="col"/>
|
|
<field name="product_id" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
pivotType: "static",
|
|
});
|
|
// Headers
|
|
setCellContent(
|
|
model,
|
|
"B1",
|
|
`=PIVOT.HEADER(1,"date:month",DATE(2016,4,1),"measure","probability:avg")`
|
|
);
|
|
expect(getPivotAutofillValue(model, "B1", { direction: "right", steps: 1 })).toBe(
|
|
`=PIVOT.HEADER(1,"date:month",DATE(2016,5,1),"measure","probability:avg")`
|
|
);
|
|
|
|
setCellContent(model, "B1", `=PIVOT.HEADER(1,"measure","probability:avg")`);
|
|
expect(getPivotAutofillValue(model, "B1", { direction: "right", steps: 1 })).toBe("");
|
|
|
|
// Values
|
|
setCellContent(
|
|
model,
|
|
"B1",
|
|
`=PIVOT.VALUE(1,"probability:avg","product_id",47,"date:month",DATE(2016,4,1))`
|
|
);
|
|
expect(getPivotAutofillValue(model, "B1", { direction: "right", steps: 1 })).toBe(
|
|
`=PIVOT.VALUE(1,"probability:avg","product_id",47,"date:month",DATE(2016,5,1))`
|
|
);
|
|
|
|
setCellContent(model, "B1", `=PIVOT.VALUE(1,"probability:avg","product_id",47)`);
|
|
expect(getPivotAutofillValue(model, "B1", { direction: "right", steps: 1 })).toBe("");
|
|
});
|
|
|
|
test("Can autofill pivot with collapsed dimensions", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="date" interval="year" type="row"/>
|
|
<field name="date" interval="month" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
});
|
|
const pivotId = model.getters.getPivotIds()[0];
|
|
updatePivot(model, pivotId, {
|
|
collapsedDomains: {
|
|
ROW: [[{ field: "date:year", value: 2016, type: "date" }]],
|
|
COL: [],
|
|
},
|
|
});
|
|
|
|
setCellContent(model, "A1", `=PIVOT.HEADER(1,"date:year",2016)`);
|
|
selectCell(model, "A1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 4 });
|
|
model.dispatch("AUTOFILL");
|
|
|
|
expect(getCell(model, "A1").content).toBe(`=PIVOT.HEADER(1,"date:year",2016)`);
|
|
expect(getCell(model, "A2").content).toBe(
|
|
`=PIVOT.HEADER(1,"date:year",2016,"date:month",DATE(2016,4,1))`
|
|
);
|
|
expect(getCell(model, "A3").content).toBe(
|
|
`=PIVOT.HEADER(1,"date:year",2016,"date:month",DATE(2016,10,1))`
|
|
);
|
|
expect(getCell(model, "A4").content).toBe(
|
|
`=PIVOT.HEADER(1,"date:year",2016,"date:month",DATE(2016,12,1))`
|
|
);
|
|
expect(getCell(model, "A5").content).toBe(`=PIVOT.HEADER(1)`);
|
|
});
|
|
|
|
test("Autofill does not crash when autofilling wrong relational id", async () => {
|
|
const { model } = await createSpreadsheetWithPivot({
|
|
arch: /*xml*/ `
|
|
<pivot>
|
|
<field name="product_id" type="col"/>
|
|
<field name="date" interval="month" type="row"/>
|
|
<field name="probability" type="measure"/>
|
|
</pivot>`,
|
|
});
|
|
const formula = `=PIVOT.HEADER(1,"product_id",9999)`;
|
|
expect(model.getters.getTooltipFormula(formula)).toEqual([{ value: "Unknown" }]);
|
|
});
|
|
|
|
test("Can autofill pivot with custom groups", async () => {
|
|
Product._records.push(
|
|
{ id: 200, display_name: "chair", name: "chair" },
|
|
{ id: 201, display_name: "table", name: "table" }
|
|
);
|
|
Partner._records.push(
|
|
{ id: 200, product_id: 200, probability: 100, bar: true },
|
|
{ id: 201, product_id: 201, probability: 50, bar: false },
|
|
{ id: 202, product_id: false, probability: 10, bar: true }
|
|
);
|
|
|
|
const { model } = await createSpreadsheetWithPivot();
|
|
const pivotId = model.getters.getPivotIds()[0];
|
|
updatePivot(model, pivotId, {
|
|
columns: [{ fieldName: "GroupedProducts", order: "asc" }],
|
|
rows: [{ fieldName: "bar" }],
|
|
measures: [{ id: "probability:sum", fieldName: "probability", aggregator: "sum" }],
|
|
customFields: {
|
|
GroupedProducts: {
|
|
parentField: "product_id",
|
|
name: "GroupedProducts",
|
|
groups: [{ name: "xphone,xpad", values: [37, 41] }],
|
|
},
|
|
},
|
|
});
|
|
await waitForDataLoaded(model);
|
|
|
|
// Autofill headers
|
|
setCellContent(model, "E1", `=PIVOT.HEADER(1,"GroupedProducts","xphone,xpad")`);
|
|
selectCell(model, "E1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 5, row: 0 });
|
|
model.dispatch("AUTOFILL");
|
|
|
|
expect(getCell(model, "F1").content).toBe(`=PIVOT.HEADER(1,"GroupedProducts",false)`);
|
|
|
|
selectCell(model, "E1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 2, row: 0 });
|
|
model.dispatch("AUTOFILL");
|
|
expect(getCell(model, "D1").content).toBe(`=PIVOT.HEADER(1,"GroupedProducts",201)`);
|
|
expect(getCell(model, "C1").content).toBe(`=PIVOT.HEADER(1,"GroupedProducts",200)`);
|
|
|
|
// Autofill values
|
|
setCellContent(model, "A1", `=PIVOT.HEADER(1,"GroupedProducts","xphone,xpad")`);
|
|
selectCell(model, "A1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 4 });
|
|
model.dispatch("AUTOFILL");
|
|
|
|
expect(getCell(model, "A2").content).toBe(
|
|
`=PIVOT.HEADER(1,"GroupedProducts","xphone,xpad","measure","probability:sum")`
|
|
);
|
|
expect(getCell(model, "A3").content).toBe(
|
|
`=PIVOT.VALUE(1,"probability:sum","bar",FALSE,"GroupedProducts","xphone,xpad")`
|
|
);
|
|
expect(getCell(model, "A4").content).toBe(
|
|
`=PIVOT.VALUE(1,"probability:sum","bar",TRUE,"GroupedProducts","xphone,xpad")`
|
|
);
|
|
expect(getCell(model, "A5").content).toBe(
|
|
`=PIVOT.VALUE(1,"probability:sum","GroupedProducts","xphone,xpad")`
|
|
);
|
|
|
|
// Autofill from "None" header
|
|
setCellContent(model, "A1", `=PIVOT.HEADER(1, "GroupedProducts",false)`);
|
|
selectCell(model, "A1");
|
|
model.dispatch("AUTOFILL_SELECT", { col: 0, row: 4 });
|
|
model.dispatch("AUTOFILL");
|
|
expect(getCell(model, "A3").content).toBe(
|
|
`=PIVOT.VALUE(1,"probability:sum","bar",FALSE,"GroupedProducts",false)`
|
|
);
|
|
expect(getCell(model, "A4").content).toBe(
|
|
`=PIVOT.VALUE(1,"probability:sum","bar",TRUE,"GroupedProducts",false)`
|
|
);
|
|
});
|