Test FlightsMapFilter Calendar min/max/disabledDates + snap effect
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* @vitest-environment jsdom
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { render } from "@testing-library/react";
|
||||
import { FlightsMapFilter } from "./FlightsMapFilter.js";
|
||||
import type { IFlightsMapFilterState } from "../types.js";
|
||||
|
||||
// Capture props passed to PrimeReact Calendar.
|
||||
let lastCalendarProps: Record<string, unknown> | null = null;
|
||||
vi.mock("primereact/calendar", () => ({
|
||||
Calendar: (props: Record<string, unknown>) => {
|
||||
lastCalendarProps = props;
|
||||
return <div data-testid="fm-date-input" />;
|
||||
},
|
||||
}));
|
||||
|
||||
// Stub PrimeReact AutoComplete so rendering is cheap.
|
||||
vi.mock("primereact/autocomplete", () => ({
|
||||
AutoComplete: (props: Record<string, unknown>) => (
|
||||
<input data-testid={props["data-testid"] as string} />
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock("@/i18n/provider.js", () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
i18n: { language: "ru" },
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@/shared/hooks/useCitySearch.js", () => ({
|
||||
useCitySearch: () => ({ suggestions: [], search: vi.fn() }),
|
||||
}));
|
||||
|
||||
function filter(
|
||||
overrides: Partial<IFlightsMapFilterState> = {},
|
||||
): IFlightsMapFilterState {
|
||||
return {
|
||||
connections: false,
|
||||
domestic: false,
|
||||
international: false,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function yyyymmdd(d: Date): string {
|
||||
const y = d.getFullYear().toString();
|
||||
const m = (d.getMonth() + 1).toString().padStart(2, "0");
|
||||
const day = d.getDate().toString().padStart(2, "0");
|
||||
return `${y}${m}${day}`;
|
||||
}
|
||||
|
||||
function addDays(base: Date, n: number): Date {
|
||||
const d = new Date(base);
|
||||
d.setDate(d.getDate() + n);
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return d;
|
||||
}
|
||||
|
||||
describe("FlightsMapFilter — Calendar wiring", () => {
|
||||
beforeEach(() => {
|
||||
lastCalendarProps = null;
|
||||
});
|
||||
|
||||
it("passes minDate and maxDate to Calendar", () => {
|
||||
const onChange = vi.fn();
|
||||
render(<FlightsMapFilter value={filter()} onChange={onChange} />);
|
||||
|
||||
const min = lastCalendarProps!["minDate"] as Date;
|
||||
const max = lastCalendarProps!["maxDate"] as Date;
|
||||
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const expectedMin = addDays(today, -1);
|
||||
const expectedMax = new Date(today);
|
||||
expectedMax.setMonth(expectedMax.getMonth() + 6);
|
||||
|
||||
expect(min.getTime()).toBe(expectedMin.getTime());
|
||||
expect(max.getTime()).toBe(expectedMax.getTime());
|
||||
});
|
||||
|
||||
it("disables every date when availableDays is empty", () => {
|
||||
const onChange = vi.fn();
|
||||
render(
|
||||
<FlightsMapFilter value={filter()} availableDays={[]} onChange={onChange} />,
|
||||
);
|
||||
|
||||
const disabled = lastCalendarProps!["disabledDates"] as Date[];
|
||||
expect(disabled.length).toBeGreaterThan(180);
|
||||
});
|
||||
|
||||
it("excludes available days from disabledDates", () => {
|
||||
const onChange = vi.fn();
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const plusTwo = addDays(today, 2);
|
||||
|
||||
render(
|
||||
<FlightsMapFilter
|
||||
value={filter()}
|
||||
availableDays={[yyyymmdd(plusTwo)]}
|
||||
onChange={onChange}
|
||||
/>,
|
||||
);
|
||||
|
||||
const disabled = lastCalendarProps!["disabledDates"] as Date[];
|
||||
const contains = disabled.some((d) => {
|
||||
const x = new Date(d);
|
||||
x.setHours(0, 0, 0, 0);
|
||||
return x.getTime() === plusTwo.getTime();
|
||||
});
|
||||
expect(contains).toBe(false);
|
||||
});
|
||||
|
||||
it("snaps a disabled value.date forward to the next available day", () => {
|
||||
const onChange = vi.fn();
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const plusOne = addDays(today, 1);
|
||||
const plusTwo = addDays(today, 2);
|
||||
|
||||
render(
|
||||
<FlightsMapFilter
|
||||
value={filter({ date: yyyymmdd(plusOne) })}
|
||||
availableDays={[yyyymmdd(plusTwo)]}
|
||||
onChange={onChange}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
const called = onChange.mock.calls[0]![0] as IFlightsMapFilterState;
|
||||
expect(called.date).toBe(yyyymmdd(plusTwo));
|
||||
});
|
||||
|
||||
it("clears value.date when no enabled date exists in the window", () => {
|
||||
const onChange = vi.fn();
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const plusOne = addDays(today, 1);
|
||||
|
||||
render(
|
||||
<FlightsMapFilter
|
||||
value={filter({ date: yyyymmdd(plusOne) })}
|
||||
availableDays={[]}
|
||||
onChange={onChange}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
const called = onChange.mock.calls[0]![0] as IFlightsMapFilterState;
|
||||
expect(called.date).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not snap when the current date is already enabled", () => {
|
||||
const onChange = vi.fn();
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const plusTwo = addDays(today, 2);
|
||||
|
||||
render(
|
||||
<FlightsMapFilter
|
||||
value={filter({ date: yyyymmdd(plusTwo) })}
|
||||
availableDays={[yyyymmdd(plusTwo)]}
|
||||
onChange={onChange}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user