Respect schedule flight operating days

This commit is contained in:
2026-05-15 00:15:17 +03:00
parent e0b69bf35f
commit c96912fbb0
4 changed files with 85 additions and 7 deletions
@@ -60,8 +60,14 @@ vi.mock("@/i18n/resolver.js", () => ({
}));
// Mutable for individual test overrides
let mockScheduleDetailsResult: { flights: unknown[]; loading: boolean; error: unknown } = {
let mockScheduleDetailsResult: {
flights: unknown[];
daysOfFlight: string[];
loading: boolean;
error: unknown;
} = {
flights: [],
daysOfFlight: [],
loading: true,
error: null,
};
@@ -145,7 +151,9 @@ vi.mock("@/features/online-board/components/FlightsMiniList/index.js", () => ({
}));
vi.mock("@/features/online-board/components/DayTabs/index.js", () => ({
DayTabs: () => <div data-testid="day-tabs" />,
DayTabs: ({ availableDates }: { availableDates: string[] }) => (
<div data-testid="day-tabs" data-available-dates={availableDates.join(",")} />
),
}));
vi.mock("@/ui/flights/FlightCard.js", () => ({
@@ -187,7 +195,7 @@ const flightId: IScheduleFlightId = {
describe("ScheduleDetailsPage breadcrumbs", () => {
beforeEach(() => {
mockSearchParamsGet = () => null;
mockScheduleDetailsResult = { flights: [], loading: true, error: null };
mockScheduleDetailsResult = { flights: [], daysOfFlight: [], loading: true, error: null };
});
it("shows 1-item trail when no ?request= param (share-link)", () => {
@@ -253,7 +261,7 @@ describe("ScheduleDetailsPage structure (§4.1.16.1 + §4.1.16.2 + §4.1.16.3)",
beforeEach(() => {
mockSearchParamsGet = () => null;
// Reset to loading state (breadcrumb tests rely on this)
mockScheduleDetailsResult = { flights: [], loading: true, error: null };
mockScheduleDetailsResult = { flights: [], daysOfFlight: [], loading: true, error: null };
// The new ScheduleFlightsMiniList scrolls the highlighted row into
// view on mount; JSDOM doesn't ship `scrollIntoView`, so stub it.
Element.prototype.scrollIntoView = vi.fn();
@@ -288,6 +296,7 @@ describe("ScheduleDetailsPage structure (§4.1.16.1 + §4.1.16.2 + §4.1.16.3)",
},
},
],
daysOfFlight: ["20260515", "20260516"],
loading: false,
error: null,
};
@@ -333,6 +342,7 @@ describe("ScheduleDetailsPage structure (§4.1.16.1 + §4.1.16.2 + §4.1.16.3)",
},
},
],
daysOfFlight: ["20260515", "20260516"],
loading: false,
error: null,
};
@@ -345,6 +355,9 @@ describe("ScheduleDetailsPage structure (§4.1.16.1 + §4.1.16.2 + §4.1.16.3)",
);
// Success state renders DayTabs in stickyContent (Schedule window = +330 days)
expect(screen.getByTestId("day-tabs")).toBeTruthy();
expect(screen.getByTestId("day-tabs").getAttribute("data-available-dates")).toBe(
"20260515,20260516",
);
});
it("4.1.16.1-R4: back link navigates to scheduleHref (success state)", () => {
@@ -377,6 +390,7 @@ describe("ScheduleDetailsPage structure (§4.1.16.1 + §4.1.16.2 + §4.1.16.3)",
},
},
],
daysOfFlight: ["20260515", "20260516"],
loading: false,
error: null,
};
@@ -95,7 +95,7 @@ export const ScheduleDetailsPage: FC<ScheduleDetailsPageProps> = ({
arrival: "",
};
const { flights, loading, error } = useScheduleDetails(detailsParams);
const { flights, daysOfFlight, loading, error } = useScheduleDetails(detailsParams);
const scheduleHref = `/${locale}/schedule`;
@@ -382,7 +382,7 @@ export const ScheduleDetailsPage: FC<ScheduleDetailsPageProps> = ({
// TZ §4.1.16.3 R22-R28: day tabs (Schedule window: [-1, +330] from today)
<DayTabs
selectedDate={selectedDate}
availableDates={[]}
availableDates={daysOfFlight}
daysBefore={scheduleSearchFrom}
daysAfter={scheduleSearchTo}
locale={locale}
@@ -21,6 +21,7 @@ export interface UseScheduleDetailsParams {
export interface UseScheduleDetailsResult {
flights: ISimpleFlight[];
daysOfFlight: string[];
loading: boolean;
error: ApiError | null;
}
@@ -34,6 +35,7 @@ export function useScheduleDetails(
): UseScheduleDetailsResult {
const client = useApiClient();
const [flights, setFlights] = useState<ISimpleFlight[]>([]);
const [daysOfFlight, setDaysOfFlight] = useState<string[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<ApiError | null>(null);
@@ -53,6 +55,7 @@ export function useScheduleDetails(
.then((response) => {
if (!cancelled) {
setFlights(response.data.routes);
setDaysOfFlight(response.data.daysOfFlight ?? []);
setLoading(false);
}
})
@@ -68,5 +71,5 @@ export function useScheduleDetails(
};
}, [client, flightsKey, datesKey, params.departure, params.arrival]);
return { flights, loading, error };
return { flights, daysOfFlight, loading, error };
}
@@ -0,0 +1,61 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { test, expect } from "./fixtures/console-gate";
import { routeAppSettingsFixture } from "./helpers/api-fixtures";
const FIXTURE_DIR = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
"../fixtures/api",
);
const URL =
"/ru-ru/schedule/KJA/SU6837-20260519/MJZ?request=schedule-route-KJA-MJZ-20260518-20260524-C0";
test("TIRREDESIGN-26: schedule details day tabs disable non-operating flight dates", async ({
page,
consoleMessages,
}) => {
await routeAppSettingsFixture(page);
await page.route("**/api/flights/v1.1/*/schedule/details?**", async (route) => {
const source = JSON.parse(
fs.readFileSync(path.join(FIXTURE_DIR, "schedule-details-vvo-mjz.json"), "utf8"),
) as {
data: {
routes: Array<{
flightId: { carrier: string; flightNumber: string; date: string };
}>;
partners: string[];
};
};
const su6837 = source.data.routes.find(
(flight) =>
flight.flightId.carrier === "SU" &&
flight.flightId.flightNumber === "6837" &&
flight.flightId.date === "2026-05-19",
);
expect(su6837).toBeTruthy();
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({
data: {
partners: [],
routes: su6837 ? [su6837] : [],
daysOfFlight: ["20260519", "20260523"],
},
}),
});
});
await page.goto(URL);
await expect(page.getByTestId("day-tabs")).toBeVisible({ timeout: 15000 });
await expect(page.getByTestId("day-tab-20260519")).toBeEnabled();
await page.getByTestId("day-tabs-next").click();
const nonOperatingFriday = page.getByTestId("day-tab-20260522");
await expect(nonOperatingFriday).toBeDisabled();
await expect(page.getByTestId("day-tab-20260523")).toBeEnabled();
await expect(page.getByTestId("schedule-details-not-found")).toHaveCount(0);
});