Files
TJWaterFrontend_Refine/src/components/olmap/BurstSimulation/AnalysisReport.test.tsx
T

281 lines
8.0 KiB
TypeScript

import {
fireEvent,
render,
screen,
waitFor,
within,
} from "@testing-library/react";
import { queryFeaturesByIds } from "@/utils/mapQueryService";
import AnalysisReport, {
clearAnalysisReportDiameterCache,
matchesValveAnalysis,
} from "./AnalysisReport";
import { SchemeRecord, ValveIsolationResult } from "./types";
import {
isAllowedAccidentPipe,
normalizeValveIsolationResult,
} from "./valveIsolationScope";
jest.mock("@/utils/mapQueryService", () => ({
queryFeaturesByIds: jest.fn(),
}));
const scheme: SchemeRecord = {
id: "17",
schemeName: "burst-report-demo",
type: "burst_analysis",
username: "operator",
create_time: "2026-07-30T08:00:00+08:00",
startTime: "2026-07-30T09:00:00+08:00",
schemeDetail: {
burst_ID: ["P-1", "P-2"],
burst_size: [120, 80],
modify_total_duration: 5400,
modify_fixed_pump_pattern: null,
modify_valve_opening: null,
modify_variable_pump_pattern: null,
},
};
const valveResult: ValveIsolationResult = {
accident_elements: ["P-1"],
affected_nodes: ["J-1", "J-2"],
must_close_valves: ["V-1"],
optional_valves: ["V-2"],
isolatable: true,
};
const feature = (id: string, diameter: number) => ({
getProperties: () => ({ id, diameter }),
});
describe("AnalysisReport", () => {
beforeEach(() => {
(queryFeaturesByIds as jest.Mock).mockImplementation(
async (ids: string[], layerName: string) =>
layerName === "pipes"
? ids.map((id) =>
id === "P-1" ? feature(id, 315) : feature(id, 800),
)
: [],
);
});
afterEach(() => {
clearAnalysisReportDiameterCache();
jest.clearAllMocks();
document.body.classList.remove("burst-analysis-report-printing");
});
it("guides the user to choose a scheme when no report is active", () => {
render(
<AnalysisReport
scheme={null}
valveResult={null}
disabledValves={[]}
generatedAt={null}
/>,
);
expect(screen.getByText("尚未选择分析方案")).toBeInTheDocument();
expect(
screen.getByText(
"请在“方案查询”中打开一个方案,再查看分析报告。",
),
).toBeInTheDocument();
});
it("renders the selected scheme, pipe data, and matching valve result", async () => {
render(
<AnalysisReport
scheme={scheme}
valveResult={valveResult}
disabledValves={["V-3"]}
generatedAt={new Date("2026-07-30T10:00:00+08:00")}
/>,
);
const preview = within(
screen.getByTestId("burst-analysis-report-preview"),
);
expect(
preview.getByRole("heading", { name: "爆管分析报告" }),
).toBeInTheDocument();
expect(preview.getByText("burst-report-demo")).toBeInTheDocument();
expect(preview.getByText("可隔离")).toBeInTheDocument();
expect(preview.getByText("V-1")).toBeInTheDocument();
expect(preview.getByText("V-3")).toBeInTheDocument();
await waitFor(() => {
expect(preview.getByText("315 mm")).toBeInTheDocument();
expect(preview.getByText("800 mm")).toBeInTheDocument();
});
expect(queryFeaturesByIds).toHaveBeenCalledWith(
["P-1", "P-2"],
"pipes",
);
});
it("does not mix an unrelated valve analysis into the report", async () => {
render(
<AnalysisReport
scheme={scheme}
valveResult={{ ...valveResult, accident_elements: ["P-99"] }}
disabledValves={[]}
generatedAt={new Date("2026-07-30T10:00:00+08:00")}
/>,
);
const preview = within(
screen.getByTestId("burst-analysis-report-preview"),
);
expect(
preview.getByText(/尚未对本方案执行匹配的关阀分析/),
).toBeInTheDocument();
expect(preview.queryByText("V-1")).not.toBeInTheDocument();
expect(
matchesValveAnalysis(scheme, {
...valveResult,
accident_elements: ["P-99"],
}),
).toBe(false);
await waitFor(() =>
expect(preview.getByText("315 mm")).toBeInTheDocument(),
);
});
it("shows only the affected count for a non-isolatable result", async () => {
const legacyAffectedNodes = Array.from(
{ length: 100 },
(_, index) => `legacy-node-${index}`,
);
const nonIsolatableResult = {
...valveResult,
affected_nodes: legacyAffectedNodes,
affected_node_count: 85747,
must_close_valves: [],
isolatable: false,
};
render(
<AnalysisReport
scheme={scheme}
valveResult={nonIsolatableResult}
disabledValves={[]}
generatedAt={new Date("2026-07-30T10:00:00+08:00")}
/>,
);
const preview = within(
screen.getByTestId("burst-analysis-report-preview"),
);
expect(preview.getByText("85747 个")).toBeInTheDocument();
expect(
preview.getByText("不可隔离,未生成受影响节点清单。"),
).toBeInTheDocument();
expect(preview.queryByText("legacy-node-0")).not.toBeInTheDocument();
expect(preview.queryByText("legacy-node-99")).not.toBeInTheDocument();
await waitFor(() =>
expect(preview.getByText("315 mm")).toBeInTheDocument(),
);
});
it("limits scheme-bound valve analysis to the scheme accident pipes", () => {
expect(isAllowedAccidentPipe("P-1", ["P-1", "P-2"])).toBe(true);
expect(isAllowedAccidentPipe("P-99", ["P-1", "P-2"])).toBe(false);
expect(isAllowedAccidentPipe("P-99", undefined)).toBe(true);
});
it("normalizes legacy valve results without changing isolatable lists", () => {
expect(
normalizeValveIsolationResult({
...valveResult,
affected_nodes: ["J-1", "J-2", "J-3"],
must_close_valves: [],
isolatable: false,
}),
).toMatchObject({
affected_nodes: [],
affected_node_count: 3,
isolatable: false,
});
expect(normalizeValveIsolationResult(valveResult)).toMatchObject({
affected_nodes: ["J-1", "J-2"],
affected_node_count: 2,
isolatable: true,
});
});
it("prints only after assigning the report print state", async () => {
const originalTitle = document.title;
const print = jest
.spyOn(window, "print")
.mockImplementation(() => undefined);
render(
<AnalysisReport
scheme={scheme}
valveResult={null}
disabledValves={[]}
generatedAt={new Date("2026-07-30T10:00:00+08:00")}
/>,
);
const preview = within(
screen.getByTestId("burst-analysis-report-preview"),
);
await waitFor(() =>
expect(preview.getByText("315 mm")).toBeInTheDocument(),
);
expect(
document.querySelector(".burst-analysis-report-print-root"),
).not.toBeInTheDocument();
fireEvent.click(
screen.getByRole("button", { name: "打印/保存 PDF" }),
);
expect(print).toHaveBeenCalledTimes(1);
expect(
document.querySelector(".burst-analysis-report-print-root"),
).toBeInTheDocument();
expect(document.body).toHaveClass("burst-analysis-report-printing");
expect(document.title).toBe("爆管分析报告-burst-report-demo");
fireEvent(window, new Event("afterprint"));
expect(document.body).not.toHaveClass(
"burst-analysis-report-printing",
);
expect(document.title).toBe(originalTitle);
print.mockRestore();
});
it("reuses pipe diameters after the report is remounted", async () => {
const props = {
scheme,
valveResult: null,
disabledValves: [],
generatedAt: new Date("2026-07-30T10:00:00+08:00"),
};
const firstRender = render(<AnalysisReport {...props} />);
await waitFor(() =>
expect(
within(screen.getByTestId("burst-analysis-report-preview")).getByText(
"800 mm",
),
).toBeInTheDocument(),
);
expect(queryFeaturesByIds).toHaveBeenCalledTimes(1);
firstRender.unmount();
render(<AnalysisReport {...props} />);
expect(
within(screen.getByTestId("burst-analysis-report-preview")).getByText(
"800 mm",
),
).toBeInTheDocument();
expect(queryFeaturesByIds).toHaveBeenCalledTimes(1);
});
});