142 lines
4.7 KiB
TypeScript
142 lines
4.7 KiB
TypeScript
// @vitest-environment jsdom
|
|
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
|
|
import { renderHook } from "@testing-library/react";
|
|
import { useGeoCityDefault } from "./useGeoCityDefault.js";
|
|
import type { IDictionaries } from "@/shared/dictionaries/index.js";
|
|
|
|
const mockDictionaries: IDictionaries = {
|
|
cities: [
|
|
{
|
|
code: "MOW",
|
|
name: "Москва",
|
|
location: { lat: 55.7558, lon: 37.6173 },
|
|
country_code: "RU",
|
|
countryName: "Russia",
|
|
has_afl_flights: true,
|
|
airports: [],
|
|
},
|
|
{
|
|
code: "LED",
|
|
name: "Санкт-Петербург",
|
|
location: { lat: 59.9311, lon: 30.3609 },
|
|
country_code: "RU",
|
|
countryName: "Russia",
|
|
has_afl_flights: true,
|
|
airports: [],
|
|
},
|
|
],
|
|
airports: [],
|
|
regions: [],
|
|
countries: [],
|
|
cityByCode: new Map([
|
|
[
|
|
"MOW",
|
|
{
|
|
code: "MOW",
|
|
name: "Москва",
|
|
location: { lat: 55.7558, lon: 37.6173 },
|
|
country_code: "RU",
|
|
countryName: "Russia",
|
|
has_afl_flights: true,
|
|
airports: [],
|
|
},
|
|
],
|
|
[
|
|
"LED",
|
|
{
|
|
code: "LED",
|
|
name: "Санкт-Петербург",
|
|
location: { lat: 59.9311, lon: 30.3609 },
|
|
country_code: "RU",
|
|
countryName: "Russia",
|
|
has_afl_flights: true,
|
|
airports: [],
|
|
},
|
|
],
|
|
]),
|
|
airportByCode: new Map(),
|
|
ruCityCodes: new Set(["MOW", "LED"]),
|
|
otherCityCodes: new Set(),
|
|
} as unknown as IDictionaries;
|
|
|
|
describe("useGeoCityDefault", () => {
|
|
let getCurrentPositionMock: ReturnType<typeof vi.fn>;
|
|
|
|
beforeEach(() => {
|
|
getCurrentPositionMock = vi.fn();
|
|
Object.defineProperty(navigator, "geolocation", {
|
|
value: { getCurrentPosition: getCurrentPositionMock },
|
|
configurable: true,
|
|
});
|
|
});
|
|
|
|
afterEach(() => { vi.restoreAllMocks(); });
|
|
|
|
it("calls onCity with nearest city code when geolocation succeeds and shouldApply returns true", () => {
|
|
getCurrentPositionMock.mockImplementation((onSuccess: (pos: GeolocationPosition) => void) => {
|
|
onSuccess({ coords: { latitude: 55.75, longitude: 37.61 } } as GeolocationPosition);
|
|
});
|
|
const onCity = vi.fn();
|
|
renderHook(() =>
|
|
useGeoCityDefault({ dictionaries: mockDictionaries, shouldApply: () => true, onCity }),
|
|
);
|
|
expect(onCity).toHaveBeenCalledWith("MOW");
|
|
});
|
|
|
|
it("does not call onCity when shouldApply returns false", () => {
|
|
getCurrentPositionMock.mockImplementation((onSuccess: (pos: GeolocationPosition) => void) => {
|
|
onSuccess({ coords: { latitude: 55.75, longitude: 37.61 } } as GeolocationPosition);
|
|
});
|
|
const onCity = vi.fn();
|
|
renderHook(() =>
|
|
useGeoCityDefault({ dictionaries: mockDictionaries, shouldApply: () => false, onCity }),
|
|
);
|
|
expect(onCity).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("is silent when geolocation permission is denied", () => {
|
|
getCurrentPositionMock.mockImplementation((_s: unknown, onErr: (err: GeolocationPositionError) => void) => {
|
|
onErr({ code: 1, message: "denied" } as GeolocationPositionError);
|
|
});
|
|
const onCity = vi.fn();
|
|
renderHook(() =>
|
|
useGeoCityDefault({ dictionaries: mockDictionaries, shouldApply: () => true, onCity }),
|
|
);
|
|
expect(onCity).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("is silent when navigator.geolocation is undefined", () => {
|
|
Object.defineProperty(navigator, "geolocation", { value: undefined, configurable: true });
|
|
const onCity = vi.fn();
|
|
renderHook(() =>
|
|
useGeoCityDefault({ dictionaries: mockDictionaries, shouldApply: () => true, onCity }),
|
|
);
|
|
expect(onCity).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("fires only once per mount even if dictionaries change", () => {
|
|
getCurrentPositionMock.mockImplementation((onSuccess: (pos: GeolocationPosition) => void) => {
|
|
onSuccess({ coords: { latitude: 55.75, longitude: 37.61 } } as GeolocationPosition);
|
|
});
|
|
const onCity = vi.fn();
|
|
const { rerender } = renderHook(
|
|
({ dict }: { dict: IDictionaries }) =>
|
|
useGeoCityDefault({ dictionaries: dict, shouldApply: () => true, onCity }),
|
|
{ initialProps: { dict: mockDictionaries } },
|
|
);
|
|
rerender({ dict: { ...mockDictionaries } as IDictionaries });
|
|
expect(onCity).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("waits for dictionaries to be non-null before computing city", () => {
|
|
getCurrentPositionMock.mockImplementation((onSuccess: (pos: GeolocationPosition) => void) => {
|
|
onSuccess({ coords: { latitude: 55.75, longitude: 37.61 } } as GeolocationPosition);
|
|
});
|
|
const onCity = vi.fn();
|
|
renderHook(() =>
|
|
useGeoCityDefault({ dictionaries: null, shouldApply: () => true, onCity }),
|
|
);
|
|
expect(onCity).not.toHaveBeenCalled();
|
|
});
|
|
});
|