diff --git a/src/features/flights-map/components/FlightsMapStartPage.test.tsx b/src/features/flights-map/components/FlightsMapStartPage.test.tsx index 7715ce05..b395d2d7 100644 --- a/src/features/flights-map/components/FlightsMapStartPage.test.tsx +++ b/src/features/flights-map/components/FlightsMapStartPage.test.tsx @@ -23,8 +23,12 @@ vi.mock("./ClientOnly.js", () => ({ ClientOnly: ({ children }: { children: React.ReactNode }) => <>{children}, })); +let lastMapCanvasProps: Record | null = null; vi.mock("./MapCanvas.js", () => ({ - MapCanvas: () =>
, + MapCanvas: (props: Record) => { + lastMapCanvasProps = props; + return
; + }, })); vi.mock("./FlightsMapFilter.js", () => ({ @@ -43,10 +47,23 @@ vi.mock("../hooks/useFlightsMapCalendar.js", () => ({ useFlightsMapCalendar: () => ({ availableDays: [] }), })); -const dictState = { - dictionaries: null as unknown, +const dictState: { + dictionaries: + | null + | { + cities: Array<{ + code: string; + name: string; + country_code: string; + location: { lat: number; lon: number }; + }>; + }; + loading: boolean; + error: Error | null; +} = { + dictionaries: null, loading: true, - error: null as Error | null, + error: null, }; vi.mock("@/shared/dictionaries/index.js", () => ({ useDictionaries: () => dictState, @@ -74,17 +91,73 @@ describe("FlightsMapStartPage — dictionaries integration", () => { it("does not show the loader once dictionaries resolve", () => { dictState.loading = false; - dictState.dictionaries = { - regions: [], - countries: [], - cities: [], - airports: [], - cityByCode: new Map(), - airportByCode: new Map(), - ruCityCodes: new Set(), - otherCityCodes: new Set(), - }; + dictState.dictionaries = { cities: [] }; render(); expect(screen.queryByTestId("map-loader")).toBeNull(); }); }); + +describe("FlightsMapStartPage — markers from dictionaries", () => { + beforeEach(() => { + lastMapCanvasProps = null; + dictState.dictionaries = null; + dictState.loading = false; + dictState.error = null; + }); + + it("maps cities to IMapMarker[] with zoomLevel and countryType", () => { + dictState.dictionaries = { + cities: [ + { + code: "MOW", + name: "Москва", + country_code: "RU", + location: { lat: 55, lon: 37 }, + }, + { + code: "PAR", + name: "Париж", + country_code: "FR", + location: { lat: 48, lon: 2 }, + }, + ], + }; + + render(); + + const markers = lastMapCanvasProps!["markers"] as Array>; + expect(markers).toHaveLength(2); + + const mow = markers.find((m) => m["id"] === "MOW")!; + expect(mow["countryType"]).toBe("ru"); + expect(mow["zoomLevel"]).toBe(2); + expect(mow["label"]).toBe("Москва"); + + const par = markers.find((m) => m["id"] === "PAR")!; + expect(par["countryType"]).toBe("other"); + expect(par["zoomLevel"]).toBe(6); + }); + + it("drops cities whose location is missing or invalid", () => { + dictState.dictionaries = { + cities: [ + { code: "MOW", name: "Москва", country_code: "RU", location: { lat: 55, lon: 37 } }, + { code: "BAD", name: "Bad", country_code: "RU", location: { lat: Number.NaN, lon: 0 } }, + ], + }; + + render(); + + const markers = lastMapCanvasProps!["markers"] as Array>; + expect(markers.map((m) => m["id"])).toEqual(["MOW"]); + }); + + it("passes domestic/international toggles through to MapCanvas", () => { + dictState.dictionaries = { cities: [] }; + + render(); + + expect(lastMapCanvasProps!["domestic"]).toBe(false); + expect(lastMapCanvasProps!["international"]).toBe(false); + }); +}); diff --git a/src/features/flights-map/components/FlightsMapStartPage.tsx b/src/features/flights-map/components/FlightsMapStartPage.tsx index f21d73d7..c79e04e5 100644 --- a/src/features/flights-map/components/FlightsMapStartPage.tsx +++ b/src/features/flights-map/components/FlightsMapStartPage.tsx @@ -137,7 +137,9 @@ export const FlightsMapStartPage: FC = () => { .filter( (c) => typeof c.location?.lat === "number" && - typeof c.location?.lon === "number", + typeof c.location?.lon === "number" && + Number.isFinite(c.location.lat) && + Number.isFinite(c.location.lon), ) .map((city) => { const isHighlighted =