1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-07-05 13:35:18 +01:00
Files
frontend/test/resources/echarts/axis-proxy-patch.test.ts
T
renovate[bot] f4143c2070 Update dependency echarts to v6.1.0 (#52168)
* Update dependency echarts to v6.1.0

* Fix axis-proxy patch for echarts 6.1.0 AxisProxy internals

ECharts 6.1.0 uses hostedBy() and _window.value instead of direct model
comparison and _valueWindow. Update the boundaryFilter patch and contract
tests so CI passes with the dependency bump.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 11:08:23 +03:00

146 lines
5.0 KiB
TypeScript

import { describe, it, expect } from "vitest";
import AxisProxy from "echarts/lib/component/dataZoom/AxisProxy";
/**
* These tests verify that the ECharts internals our axis-proxy-patch relies on
* still exist. If an ECharts upgrade changes these, the tests will fail,
* alerting us that the patch in src/resources/echarts/axis-proxy-patch.ts
* needs to be updated.
*/
describe("ECharts internals required by axis-proxy-patch", () => {
it("AxisProxy has a filterData method on its prototype", () => {
expect(typeof (AxisProxy as any).prototype.filterData).toBe("function");
});
it("AxisProxy prototype exposes the expected instance methods", () => {
// The patch accesses these via `this` inside filterData:
// this.hostedBy(), this._dimName, this._window.value,
// this.getTargetSeriesModels()
// We can't easily construct a real AxisProxy, but we can verify
// the methods exist on the prototype.
expect(typeof (AxisProxy as any).prototype.hostedBy).toBe("function");
expect(typeof (AxisProxy as any).prototype.getTargetSeriesModels).toBe(
"function"
);
});
});
describe("axis-proxy-patch applies boundaryFilter mode", () => {
it("patches filterData to handle boundaryFilter", async () => {
// Import the patch (side-effect module)
await import("../../../src/resources/echarts/axis-proxy-patch");
const filterData = (AxisProxy as any).prototype.filterData;
// Create a mock dataZoomModel that requests boundaryFilter
const mockDataZoomModel = {
get: (key: string) =>
key === "filterMode" ? "boundaryFilter" : undefined,
};
// The patched filterData should not throw when called with
// boundaryFilter and a non-hosted dataZoomModel (early return path)
const mockProxy = {
hostedBy: () => false,
};
// Should return early because hostedBy returns false
expect(() =>
filterData.call(mockProxy, mockDataZoomModel, {})
).not.toThrow();
});
it("falls through to original filterData for other filterModes", async () => {
await import("../../../src/resources/echarts/axis-proxy-patch");
const filterData = (AxisProxy as any).prototype.filterData;
// Temporarily replace the original to verify delegation
const calls: any[] = [];
// The patched function stores the original in its closure.
// We can verify it doesn't enter the boundaryFilter path by checking
// that no boundary-specific logic runs (no getTargetSeriesModels call).
const mockDataZoomModel = {
get: (key: string) => (key === "filterMode" ? "filter" : undefined),
};
const mockProxy = {
_dataZoomModel: mockDataZoomModel,
hostedBy: (model: unknown) => model === mockDataZoomModel,
_window: { value: [0, 100] },
getTargetSeriesModels: () => {
calls.push("getTargetSeriesModels");
return [];
},
};
// Should not throw — the patched function delegates to the original
expect(() =>
filterData.call(mockProxy, mockDataZoomModel, {})
).not.toThrow();
// The original filterData fetches target series; boundaryFilter logic is not used
expect(calls).toEqual(["getTargetSeriesModels"]);
});
it("filters data keeping boundary points", async () => {
await import("../../../src/resources/echarts/axis-proxy-patch");
const filterData = (AxisProxy as any).prototype.filterData;
// Simulate data: timestamps [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// Zoom window: [3, 7]
// Expected: keep index 1 (value 2, left boundary), indices 2-6 (in window),
// index 7 (value 8, right boundary), filter out 0, 8, 9
const values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const kept: number[] = [];
const mockStore = {
get: (_dimIndex: number, i: number) => values[i],
};
const mockSeriesData = {
mapDimensionsAll: () => ["x"],
getStore: () => mockStore,
getDimensionIndex: () => 0,
count: () => values.length,
filterSelf: (fn: (idx: number) => boolean) => {
for (let i = 0; i < values.length; i++) {
if (fn(i)) {
kept.push(i);
}
}
},
// eslint-disable-next-line @typescript-eslint/no-empty-function
setApproximateExtent: () => {},
};
const mockSeriesModel = {
getData: () => mockSeriesData,
};
const mockDataZoomModel = {
get: (key: string) =>
key === "filterMode" ? "boundaryFilter" : undefined,
};
const mockProxy = {
_dataZoomModel: mockDataZoomModel,
hostedBy: (model: unknown) => model === mockDataZoomModel,
_dimName: "x",
_window: { value: [3, 7] },
getTargetSeriesModels: () => [mockSeriesModel],
};
filterData.call(mockProxy, mockDataZoomModel, {});
// Index 0 (value 1): filtered out
// Index 1 (value 2): left boundary (nearest < 3)
// Index 2-6 (values 3-7): in window
// Index 7 (value 8): right boundary (nearest > 7)
// Index 8-9 (values 9-10): filtered out
expect(kept).toEqual([1, 2, 3, 4, 5, 6, 7]);
});
});