import { render, cleanup, screen, act, } from "@testing-library/react"; import { createRef } from "react"; import assert from "node:assert"; import { describe, test, mock, afterEach, before, } from "node:test"; import type { IMapRef, TCluster } from "./config/types/index"; import { getNextClustersByPointClick } from "./lib/placemark"; import { Map } from "./index"; class IntersectionObserverMock { readonly root: Element | Document | null = null; readonly rootMargin: string = "0px"; readonly thresholds: ReadonlyArray = [ 0 ]; constructor( _callback: (...args: unknown[]) => void, _options?: unknown ) {} disconnect(): void { return; } observe(_target: Element): void { return; } takeRecords(): IntersectionObserverEntry[] { return []; } unobserve(_target: Element): void { return; } } describe("Map", () => { before(() => { if (!globalThis.IntersectionObserver) { globalThis.IntersectionObserver = IntersectionObserverMock as unknown as typeof IntersectionObserver; } }); afterEach(() => { cleanup(); }); test("renders map container with id and attrs", () => { render(); const node = screen.getByTestId("map-root"); assert.notStrictEqual(node, null); assert.strictEqual(node.getAttribute("id"), "my-map"); }); test("calls onMount and onUnmount callbacks", async () => { const onMount = mock.fn(); const onUnmount = mock.fn(); const { unmount } = render(); await act(async () => {}); assert.strictEqual(onMount.mock.calls.length, 1); unmount(); assert.strictEqual(onUnmount.mock.calls.length, 1); }); test("exposes imperative ref api", async () => { const ref = createRef(); render(); await act(async () => {}); assert.notStrictEqual(ref.current, null); assert.ok(ref.current?.el instanceof HTMLElement); assert.strictEqual(typeof ref.current?.getData, "function"); assert.strictEqual(typeof ref.current?.stateActions.setClusters, "function"); assert.strictEqual(typeof ref.current?.stateActions.setIsDisabled, "function"); }); test("updates clusters via ref.stateActions.setClusters", async () => { const ref = createRef(); render(); await act(async () => {}); const clusters: TCluster[] = [ { id: "cluster-1", points: [ { id: "point-1", coords: [ 55.951244, 37.518423 ], state: { isActive: true, isDisabled: false, }, }, ], }, ]; await act(async () => { ref.current?.stateActions.setClusters(clusters); }); const data = ref.current?.getData(); assert.strictEqual(data?.clusters[0]?.id, "cluster-1"); assert.strictEqual(data?.clusters[0]?.points[0]?.id, "point-1"); assert.strictEqual(data?.clusters[0]?.points[0]?.state?.isActive, true); }); test("switches active point between two markers in single-active mode", async () => { const ref = createRef(); render( ); await act(async () => {}); await act(async () => { ref.current?.stateActions.setClusters((prevClusters: TCluster[]) => { return getNextClustersByPointClick({ clusters: prevClusters, pointId: "point-1", maxActivePoints: 1, }).nextClusters; }, false); }); let data = ref.current?.getData(); let currentPoints = data?.clusters?.[0]?.points ?? []; assert.strictEqual(currentPoints.find((point) => point.id === "point-1")?.state?.isActive, true); assert.strictEqual(currentPoints.find((point) => point.id === "point-2")?.state?.isActive, false); await act(async () => { ref.current?.stateActions.setClusters((prevClusters: TCluster[]) => { return getNextClustersByPointClick({ clusters: prevClusters, pointId: "point-2", maxActivePoints: 1, }).nextClusters; }, false); }); data = ref.current?.getData(); currentPoints = data?.clusters?.[0]?.points ?? []; assert.strictEqual(currentPoints.find((point) => point.id === "point-1")?.state?.isActive, false); assert.strictEqual(currentPoints.find((point) => point.id === "point-2")?.state?.isActive, true); }); });