import { describe, expect, it } from "vitest"; import { groupInvestigationCharts } from "./investigation-chart-groups"; import type { InvestigationChart } from "../hooks/use-investigation-presentation"; const comparison = (id: string, metric = "压力", unit = "m", date = "2026-07-16"): InvestigationChart => ({ action: "open_chart", chart_id: `chart_tc_${id}`, evidence_refs: [`evidence:${id}`], chart: { title: `${id} ${metric}七日同时刻对照(${unit})`, chart_type: "time_comparison", x_axis_name: "时间", y_axis_name: `${metric}(${unit})`, x_data: ["07:45", "08:00"], series: [ { name: `${id} 当前 ${date}`, type: "line", data: [30, 25], sample_times: [`${date}T07:45:00+08:00`, `${date}T08:00:00+08:00`] }, { name: `${id} 2026-07-09`, type: "scatter", data: [null, 32], sample_times: [null, "2026-07-09T08:00:00+08:00"] } ] } }); const legacyComparison = (id: string, metric = "压力", unit = "m", date = "2026-07-16") => { const command = comparison(id, metric, unit, date); command.chart.title = `${id} ${metric}三小时趋势与七天同期对照(${unit})`; command.chart.series[0].name = `${id} ${date.slice(5)}(${unit})`; command.chart.series[1].name = "07-09"; return command; }; describe("investigation comparison groups", () => { it("groups all four bound devices even when titles differ and one device has no observations", () => { const ids = ["486033", "542017", "541061", "524529"]; const charts = ids.map((id, index) => { const command = comparison(id, "流量", "m3/h"); command.chart.title = `不同的标题 ${index}`; command.chart.scada = { role: "comparison", metric: "flow", unit: "m3/h", window_start: "2026-07-16T05:00:00+08:00", window_end: "2026-07-16T08:00:00+08:00" }; command.chart.series.forEach((series, offset) => { series.device_id = id; series.day_offset = offset; series.name = offset ? "历史" : "当前"; if (id === "524529") { series.data = [null, null]; series.sample_times = [null, null]; } }); return command; }); const groups = groupInvestigationCharts(charts); expect(groups).toHaveLength(1); expect(groups[0].items.map((item) => item.label)).toEqual(ids); expect(groups[0].id).toBe(groupInvestigationCharts([charts[3]])[0].id); expect(groups[0].items[3].command).toBe(charts[3]); charts[3].chart.scada!.unit = "m³/h"; charts[3].chart.scada!.window_start = "2026-07-15T21:00:00Z"; charts[3].chart.scada!.window_end = "2026-07-16T00:00:00Z"; expect(groupInvestigationCharts(charts)).toHaveLength(1); }); it("groups pressure objects and pipe flow objects separately without changing data or evidence", () => { const charts = [comparison("170486"), comparison("175618"), comparison("542017", "管流", "m³/h"), comparison("486033", "管流", "m³/h")]; const groups = groupInvestigationCharts(charts); expect(groups).toHaveLength(2); expect(groups[0].items.map((item) => item.label)).toEqual(["170486", "175618"]); expect(groups[1].items.map((item) => item.label)).toEqual(["542017", "486033"]); expect(groups[0].title).toBe("压力七日同时刻对照(m)"); expect(groups[0].items[1].command).toBe(charts[1]); expect(charts[1].chart.series[1].data).toEqual([null, 32]); }); it("groups saved pressure and flow charts whose titles put the metric before the object ID", () => { const charts = [["170486", "压力", "m"], ["175618", "压力", "m"], ["541061", "流量", "m³/h"], ["542017", "流量", "m³/h"]].map(([id, metric, unit]) => { const command = comparison(id, metric, unit); command.chart.title = `${metric}测点 ${id} 当前曲线与前七天同期对比(${unit})`; return command; }); const groups = groupInvestigationCharts(charts); expect(groups.map((group) => ({ title: group.title, objects: group.items.map((item) => item.label) }))).toEqual([ { title: "压力当前曲线与前七天同期对比(m)", objects: ["170486", "175618"] }, { title: "流量当前曲线与前七天同期对比(m³/h)", objects: ["541061", "542017"] } ]); }); it("recognizes the same explicit object comparison in all three saved title formats", () => { const charts = [comparison("170486"), comparison("175618"), comparison("159673")]; charts[0].chart.title = "170486 压力三小时与历史对照(m)"; charts[1].chart.title = "测点 175618 压力三小时与历史对照(m)"; charts[2].chart.title = "压力测点 159673 三小时与历史对照(m)"; const groups = groupInvestigationCharts(charts); expect(groups).toHaveLength(1); expect(groups[0].title).toBe("压力三小时与历史对照(m)"); expect(groups[0].items.map((item) => item.label)).toEqual(["170486", "175618", "159673"]); }); it("groups saved date-only historical labels without rewriting commands, readings or evidence", () => { const charts = [legacyComparison("170486"), legacyComparison("175618")]; charts[1].chart.series[1].data[1] = 0; const original = structuredClone(charts); const groups = groupInvestigationCharts(charts); expect(groups).toHaveLength(1); expect(groups[0].items.map((item) => item.label)).toEqual(["170486", "175618"]); groups[0].items.forEach((item, index) => { expect(item.command).toBe(charts[index]); expect(item.command.chart.series).toBe(charts[index].chart.series); expect(item.command.chart.series[1].sample_times).toBe(charts[index].chart.series[1].sample_times); expect(item.command.evidence_refs).toBe(charts[index].evidence_refs); }); expect(charts).toEqual(original); }); it("keeps legacy comparisons with different units, windows or current dates separate", () => { const shifted = legacyComparison("175618"); shifted.chart.x_data = ["08:00", "08:15"]; shifted.chart.series[0].sample_times = ["2026-07-16T08:00:00+08:00", "2026-07-16T08:15:00+08:00"]; shifted.chart.series[1].sample_times = [null, "2026-07-09T08:15:00+08:00"]; const charts = [legacyComparison("170486"), legacyComparison("P2", "压力", "MPa"), shifted, legacyComparison("P3", "压力", "m", "2026-07-17")]; expect(groupInvestigationCharts(charts)).toHaveLength(charts.length); }); it("leaves ambiguous or mixed-object legacy charts and unproven historical dates separate", () => { const ambiguous = legacyComparison("P2"); ambiguous.chart.title = "压力测点历史对照"; const foreign = legacyComparison("P3"); foreign.chart.series[1].name = "P4 07-09"; const mixed = legacyComparison("P4"); mixed.chart.series.push({ ...mixed.chart.series[0], name: "P5 当前 2026-07-16" }); const missing = legacyComparison("P5"); delete missing.chart.series[1].sample_times; const mismatched = legacyComparison("P6"); mismatched.chart.series[1].sample_times = [null, "2026-07-10T08:00:00+08:00"]; const empty = legacyComparison("P7"); empty.chart.series[1].data = [null, null]; empty.chart.series[1].sample_times = [null, null]; const sameDateInUtc8 = legacyComparison("P8"); sameDateInUtc8.chart.series[1].sample_times = [null, "2026-07-09T00:00:00Z"]; const charts = [legacyComparison("170486"), ambiguous, foreign, mixed, missing, mismatched, empty, sameDateInUtc8]; const groups = groupInvestigationCharts(charts); expect(groups).toHaveLength(charts.length - 1); expect(groups[0].items.map((item) => item.label)).toEqual(["170486", "P8"]); }); it("keeps incompatible units, sampling windows, comparison dates and ordinary trends separate", () => { const base = comparison("170486"); const window = comparison("175618"); window.chart.x_data = ["08:00", "08:15"]; const trend = comparison("159673"); trend.chart.series = [trend.chart.series[0]]; expect(groupInvestigationCharts([base, comparison("P2", "压力", "MPa"), comparison("P3", "压力", "m", "2026-07-17"), window, trend])).toHaveLength(5); const noTimes = [comparison("P4"), comparison("P5", "压力", "m", "2026-07-17")]; for (const command of noTimes) for (const series of command.chart.series) delete series.sample_times; expect(groupInvestigationCharts(noTimes)).toHaveLength(2); }); it("keeps group identity stable as objects arrive or are closed and leaves ambiguous titles alone", () => { const first = comparison("170486"), second = comparison("175618"); expect(groupInvestigationCharts([first])[0].id).toBe(groupInvestigationCharts([second, first])[0].id); const ambiguous = comparison("159673"); ambiguous.chart.title = "压力同期对照"; expect(groupInvestigationCharts([first, ambiguous])).toHaveLength(2); expect(groupInvestigationCharts([])).toEqual([]); }); });