213 lines
6.2 KiB
JavaScript
213 lines
6.2 KiB
JavaScript
import { before, expect } from "@odoo/hoot";
|
|
import { queryAllTexts, queryOne } from "@odoo/hoot-dom";
|
|
import { contains, findComponent, preloadBundle } from "@web/../tests/web_test_helpers";
|
|
|
|
import { ensureArray } from "@web/core/utils/arrays";
|
|
import { patch } from "@web/core/utils/patch";
|
|
import { GraphController } from "@web/views/graph/graph_controller";
|
|
import { GraphRenderer } from "@web/views/graph/graph_renderer";
|
|
|
|
/**
|
|
* @typedef {"bar" | "line" | "pie"} GraphMode
|
|
*
|
|
* @typedef {import("@web/views/view").View} GraphView
|
|
*/
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
* @param {string | Iterable<string>} keys
|
|
* @param {Record<string, any> | Iterable<Record<string, any>>} expectedDatasets
|
|
*/
|
|
export const checkDatasets = (view, keys, expectedDatasets) => {
|
|
keys = ensureArray(keys);
|
|
|
|
const datasets = getChart(view).data.datasets;
|
|
const actualValues = [];
|
|
for (const dataset of datasets) {
|
|
const partialDataset = {};
|
|
for (const key of keys) {
|
|
partialDataset[key] = dataset[key];
|
|
}
|
|
actualValues.push(partialDataset);
|
|
}
|
|
expect(actualValues).toEqual(ensureArray(expectedDatasets));
|
|
};
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
* @param {GraphMode} mode
|
|
*/
|
|
export const checkModeIs = (view, mode) => {
|
|
expect(getGraphModelMetaData(view).mode).toBe(mode);
|
|
expect(getChart(view).config.type).toBe(mode);
|
|
expect(getModeButton(mode)).toHaveClass("active");
|
|
};
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
* @param {{ lines: { label: string, value: string }[], title?: string }} expectedTooltip
|
|
* @param {number} index
|
|
* @param {number} datasetIndex
|
|
*/
|
|
export const checkTooltip = (view, { title, lines }, index, datasetIndex = null) => {
|
|
// If the tooltip options are changed, this helper should change: we construct the dataPoints
|
|
// similarly to Chart.js according to the values set for the tooltips options 'mode' and 'intersect'.
|
|
const chart = getChart(view);
|
|
const { datasets } = chart.data;
|
|
const dataPoints = [];
|
|
for (let i = 0; i < datasets.length; i++) {
|
|
const dataset = datasets[i];
|
|
const raw = dataset.data[index];
|
|
if (raw !== undefined && (datasetIndex === null || datasetIndex === i)) {
|
|
dataPoints.push({
|
|
datasetIndex: i,
|
|
dataIndex: index,
|
|
raw,
|
|
});
|
|
}
|
|
}
|
|
chart.config.options.plugins.tooltip.external({
|
|
tooltip: { opacity: 1, x: 1, y: 1, dataPoints },
|
|
});
|
|
const lineLabels = [];
|
|
const lineValues = [];
|
|
for (const line of lines) {
|
|
lineLabels.push(line.label);
|
|
lineValues.push(String(line.value));
|
|
}
|
|
|
|
expect(`.o_graph_custom_tooltip`).toHaveCount(1);
|
|
expect(`table thead tr th.o_measure`).toHaveText(title || "Count");
|
|
expect(queryAllTexts(`table tbody tr td small.o_label`)).toEqual(lineLabels);
|
|
expect(queryAllTexts(`table tbody tr td.o_value`)).toEqual(lineValues);
|
|
};
|
|
|
|
/**
|
|
* @param {"asc" | "desc"} direction
|
|
*/
|
|
export const clickSort = (direction) => contains(`.fa-sort-amount-${direction}`).click();
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
*/
|
|
export const getChart = (view) => getGraphRenderer(view).chart;
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
*/
|
|
export const getGraphModelMetaData = (view) => getGraphModel(view).metaData;
|
|
|
|
/**
|
|
* @param {GraphMode} mode
|
|
*/
|
|
export const getModeButton = (mode) => queryOne`.o_graph_button[data-mode=${mode}]`;
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
*/
|
|
export const getScaleY = (view) => getChart(view).config.options.scales.y;
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
*/
|
|
export const getYAxisLabel = (view) => getChart(view).config.options.scales.y.title.text;
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
* @param {string | Iterable<string>} expectedLabels
|
|
*/
|
|
export function checkLabels(view, expectedLabels) {
|
|
expect(getChart(view).data.labels.map(String)).toEqual(ensureArray(expectedLabels));
|
|
}
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
* @param {string | Iterable<string>} expectedLabels
|
|
*/
|
|
export function checkYTicks(view, expectedLabels) {
|
|
const labels = getChart(view).scales.y.ticks.map((l) => l.label);
|
|
expect(labels).toEqual(expectedLabels);
|
|
}
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
* @param {string | Iterable<string>} expectedLabels
|
|
*/
|
|
export function checkLegend(view, expectedLabels) {
|
|
const chart = getChart(view);
|
|
const labels = chart.config.options.plugins.legend.labels
|
|
.generateLabels(chart)
|
|
.map((o) => o.text);
|
|
const expectedLabelsList = ensureArray(expectedLabels);
|
|
expect(labels).toEqual(expectedLabelsList, {
|
|
message: `Legend should be matching: ${expectedLabelsList
|
|
.map((label) => `"${label}"`)
|
|
.join(", ")}`,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
*/
|
|
export async function clickOnDataset(view) {
|
|
const chart = getChart(view);
|
|
const point = chart.getDatasetMeta(0).data[0].getCenterPoint();
|
|
return contains(chart.canvas).click({ position: point, relative: true });
|
|
}
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
*/
|
|
export function getGraphController(view) {
|
|
return findComponent(view, (c) => c instanceof GraphController);
|
|
}
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
*/
|
|
export function getGraphModel(view) {
|
|
return getGraphController(view).model;
|
|
}
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
* @returns {GraphRenderer}
|
|
*/
|
|
export function getGraphRenderer(view) {
|
|
return findComponent(view, (c) => c instanceof GraphRenderer);
|
|
}
|
|
|
|
/**
|
|
* @param {GraphMode} mode
|
|
*/
|
|
export function selectMode(mode) {
|
|
return contains(getModeButton(mode)).click();
|
|
}
|
|
|
|
/**
|
|
* @param {GraphView} view
|
|
* @param {string} text
|
|
*/
|
|
export async function clickOnLegend(view, text) {
|
|
const chart = getChart(view);
|
|
const index = chart.legend.legendItems.findIndex((e) => e.text === text);
|
|
const { left, top, width, height } = chart.legend.legendHitBoxes[index];
|
|
const point = {
|
|
x: left + width / 2,
|
|
y: top + height / 2,
|
|
};
|
|
return contains(chart.canvas).click({ position: point, relative: true });
|
|
}
|
|
|
|
/**
|
|
* Helper to call at the start of a test suite using the Chart.js lib.
|
|
*
|
|
* It will:
|
|
* - pre-load the Chart.js lib before tests are run;
|
|
* - disable all animations in the lib.
|
|
*/
|
|
export function setupChartJsForTests() {
|
|
preloadBundle("web.chartjs_lib");
|
|
before(() => patch(Chart.defaults, { animation: false }));
|
|
}
|