fix(api): align frontend with REST contracts

This commit is contained in:
2026-07-30 20:38:52 +08:00
parent b57e58ff87
commit 782363cfb6
65 changed files with 99362 additions and 318 deletions
@@ -0,0 +1,176 @@
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
import SchemeEditor from "./SchemeEditor";
import type { SensorPlacementScheme } from "./types";
const mockOpen = jest.fn();
let mockSingleClickHandler: ((event: unknown) => void) | undefined;
const mockMap = {
addLayer: jest.fn(),
removeLayer: jest.fn(),
on: jest.fn((eventName: string, handler: (event: unknown) => void) => {
if (eventName === "singleclick") {
mockSingleClickHandler = handler;
}
}),
un: jest.fn(),
forEachFeatureAtPixel: jest.fn(() => undefined),
getView: jest.fn(() => ({
animate: jest.fn(),
getZoom: jest.fn(() => 16),
getResolution: jest.fn(() => 1),
})),
};
jest.mock("@refinedev/core", () => ({
useNotification: () => ({ open: mockOpen }),
}));
jest.mock("@components/olmap/core/MapComponent", () => ({
useMap: () => mockMap,
}));
jest.mock("@mui/x-data-grid", () => ({
DataGrid: () => <div data-testid="scheme-grid" />,
GridToolbar: () => null,
}));
jest.mock("@mui/x-data-grid/locales", () => ({
zhCN: {
components: {
MuiDataGrid: {
defaultProps: {
localeText: {},
},
},
},
},
}));
jest.mock("ol/Feature", () => ({
__esModule: true,
default: class {
private values: Record<string, unknown>;
constructor(values: Record<string, unknown>) {
this.values = values;
}
get(key: string) {
return this.values[key];
}
setId() {}
},
}));
jest.mock("ol/geom/Point", () => ({
__esModule: true,
default: class {
constructor(_coordinates: number[]) {}
},
}));
jest.mock("ol/source/Vector", () => ({
__esModule: true,
default: class {
clear() {}
addFeature() {}
},
}));
jest.mock("ol/layer/Vector", () => ({
__esModule: true,
default: class {
private source: { clear: () => void; addFeature: () => void };
constructor(options: {
source: { clear: () => void; addFeature: () => void };
}) {
this.source = options.source;
}
getSource() {
return this.source;
}
setVisible() {}
},
}));
jest.mock("ol/style", () => ({
Circle: class {},
Fill: class {},
Stroke: class {},
Style: class {},
Text: class {},
}));
jest.mock("ol/proj", () => ({
fromLonLat: (coordinates: number[]) => coordinates,
toLonLat: (coordinates: number[]) => coordinates,
}));
jest.mock("@/utils/mapQueryService", () => ({
handleMapClickSelectFeatures: jest.fn(),
}));
jest.mock("./SchemeDrawingDialog", () => ({
__esModule: true,
default: () => null,
}));
jest.mock("./schemeApi", () => ({
exportSensorPlacementExcel: jest.fn(),
overwriteSensorPlacementScheme: jest.fn(),
}));
const scheme: SensorPlacementScheme = {
id: 1,
scheme_name: "测试方案",
sensor_number: 1,
min_diameter: 300,
username: "operator",
create_time: "2026-07-30T08:00:00+08:00",
sensor_location: ["J1"],
sensor_points: [
{
node_id: "J1",
project_x: 10,
project_y: 20,
map_x: 13500010,
map_y: 3600020,
longitude: 121,
latitude: 31,
elevation: 5,
},
],
can_edit: true,
};
describe("SchemeEditor notifications", () => {
beforeEach(() => {
jest.clearAllMocks();
mockSingleClickHandler = undefined;
});
it("uses the same error notification contract as scheme query when replace starts outside an existing sensor", async () => {
render(<SchemeEditor scheme={scheme} network="fengyang" />);
fireEvent.click(screen.getByRole("button", { name: "替换" }));
await waitFor(() => expect(mockSingleClickHandler).toBeDefined());
act(() => {
mockSingleClickHandler?.({
pixel: [0, 0],
coordinate: [13500000, 3600000],
stopPropagation: jest.fn(),
});
});
expect(mockOpen).toHaveBeenCalledWith({
type: "error",
message: "请先点击要替换的监测点",
});
});
});