91 lines
3.6 KiB
TypeScript
91 lines
3.6 KiB
TypeScript
import { renderHook } from "@testing-library/react";
|
|
import type { Map as MapLibreMap } from "maplibre-gl";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
import {
|
|
useMapInteractions,
|
|
clearMapFeatureInteractionState,
|
|
isPointOccludedByCityBuilding,
|
|
setMapFeatureInteractionState,
|
|
toMapFeatureReference
|
|
} from "./use-map-interactions";
|
|
import { INTERACTIVE_HIT_LAYER_IDS } from "../map/layers";
|
|
|
|
describe("map feature interaction state", () => {
|
|
const feature = { source: "junctions", sourceLayer: "junctions", id: "junction-7" } as const;
|
|
type CityOcclusionMap = Parameters<typeof isPointOccludedByCityBuilding>[0];
|
|
|
|
it("maps selected business features to promoted vector feature references", () => {
|
|
expect(toMapFeatureReference({ id: "junction-7", layer: "junctions" })).toEqual(feature);
|
|
expect(toMapFeatureReference(null)).toBeNull();
|
|
});
|
|
|
|
it("sets hover and selected through feature-state", () => {
|
|
const map = { setFeatureState: vi.fn(), removeFeatureState: vi.fn() };
|
|
setMapFeatureInteractionState(map, feature, { selected: true, hovered: false });
|
|
expect(map.setFeatureState).toHaveBeenCalledWith(
|
|
{ source: "junctions", sourceLayer: "junctions", id: "junction-7" },
|
|
{ selected: true, hovered: false }
|
|
);
|
|
});
|
|
|
|
it("clears only the requested state key", () => {
|
|
const map = { setFeatureState: vi.fn(), removeFeatureState: vi.fn() };
|
|
clearMapFeatureInteractionState(map, feature, "selected");
|
|
expect(map.removeFeatureState).toHaveBeenCalledWith(
|
|
{ source: "junctions", sourceLayer: "junctions", id: "junction-7" },
|
|
"selected"
|
|
);
|
|
});
|
|
|
|
it("uses transparent hit layers for pointer interactions", () => {
|
|
expect(INTERACTIVE_HIT_LAYER_IDS).toEqual(expect.arrayContaining([
|
|
"pipes-hit",
|
|
"junctions-hit",
|
|
"scada-pressure-hit",
|
|
"scada-flow-hit",
|
|
"water_quality_monitoring_points-hit",
|
|
"fx_20200423_pipes-hit"
|
|
]));
|
|
});
|
|
|
|
it("blocks pointer interactions where a 3D building is rendered", () => {
|
|
const queryRenderedFeatures = vi.fn(() => [{ id: "building-1" }]);
|
|
const map = {
|
|
getLayer: vi.fn(() => ({ id: "fengxian-city-buildings" })),
|
|
getPitch: vi.fn(() => 55),
|
|
queryRenderedFeatures
|
|
};
|
|
|
|
expect(isPointOccludedByCityBuilding(map as unknown as CityOcclusionMap, [120, 80])).toBe(true);
|
|
expect(queryRenderedFeatures).toHaveBeenCalledWith([120, 80], {
|
|
layers: ["fengxian-city-buildings"]
|
|
});
|
|
});
|
|
|
|
it("keeps 2D pointer interactions independent of the optional city scene", () => {
|
|
const queryRenderedFeatures = vi.fn();
|
|
const map = {
|
|
getLayer: vi.fn(() => ({ id: "fengxian-city-buildings" })),
|
|
getPitch: vi.fn(() => 0),
|
|
queryRenderedFeatures
|
|
};
|
|
|
|
expect(isPointOccludedByCityBuilding(map as unknown as CityOcclusionMap, [120, 80])).toBe(false);
|
|
expect(queryRenderedFeatures).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
|
|
it("suspends feature picking while the map is used to look up a place", () => {
|
|
const canvas = document.createElement("canvas");
|
|
const map = { on: vi.fn(), off: vi.fn(), getLayer: vi.fn(() => ({})), getCanvas: () => canvas };
|
|
const props = { enabled: false, mapRef: { current: map as unknown as MapLibreMap },
|
|
availableSourceIds: ["pipes"] as const, mapReady: true, onSelectFeature: vi.fn(), selectedFeature: null };
|
|
const { rerender } = renderHook(useMapInteractions, { initialProps: props });
|
|
expect(map.on).not.toHaveBeenCalled();
|
|
rerender({ ...props, enabled: true });
|
|
expect(map.on).toHaveBeenCalledWith("click", expect.any(Array), expect.any(Function));
|
|
rerender(props);
|
|
expect(map.off).toHaveBeenCalledWith("click", expect.any(Array), expect.any(Function));
|
|
});
|