Schedule details mini-list: filter to the open flight only
Mirrors Angular's CurrentScheduleService.getScheduleType + compareFlightsByPId: when the [-1, +1] route search returns the open flight (matched by carrier+number signature, including each leg of a connecting itinerary), keep only those instances; when no match exists, fall back to a 1-item list with just the open flight (Angular's 'default-schedule' branch). Old behaviour returned the full route search and dumped every unrelated MOW-MMK option into the rail. Add e2e regression that loads the SU 6188 + SU 6341 itinerary and asserts the rail shows only SU 6188 — not SU 6190 / SU 6699 (the other Sunday MOW-MMK options that used to appear).
This commit is contained in:
@@ -150,19 +150,48 @@ export const ScheduleDetailsPage: FC<ScheduleDetailsPageProps> = ({
|
||||
);
|
||||
|
||||
const miniListFlights: ISimpleFlight[] = useMemo(() => {
|
||||
if (!miniListSearchParams) return flights as unknown as ISimpleFlight[];
|
||||
if (siblingSearch.loading || siblingSearch.error) {
|
||||
return flights as unknown as ISimpleFlight[];
|
||||
}
|
||||
return extractSimpleFlights(
|
||||
// Mirrors Angular's `CurrentScheduleService.getScheduleType`:
|
||||
// • If the route-search result contains the open flight (matched
|
||||
// by the same carrier+number sequence), show those matching
|
||||
// instances across the [-1, +1] day window — the SAME flight on
|
||||
// adjacent days.
|
||||
// • Otherwise fall back to a 1-item list with just the open
|
||||
// flight ('default-schedule' branch).
|
||||
// Old behaviour returned the entire route search which dumped every
|
||||
// unrelated MOW-MMK option into the left rail.
|
||||
const fallback = flights as unknown as ISimpleFlight[];
|
||||
if (!miniListSearchParams) return fallback;
|
||||
if (siblingSearch.loading || siblingSearch.error) return fallback;
|
||||
|
||||
// Build the open flight's signature: ordered "CARRIER+NUMBER"
|
||||
// segments. For connecting itineraries the URL carries every leg
|
||||
// already (each as a separate flightId).
|
||||
const openSignature = flightIds
|
||||
.map((f) => `${f.carrier}${f.flightNumber}`)
|
||||
.join("+");
|
||||
if (!openSignature) return fallback;
|
||||
|
||||
const allSiblings = extractSimpleFlights(
|
||||
siblingSearch.flights as Array<{ routeType: string }>,
|
||||
);
|
||||
const matches = allSiblings.filter((sib) => {
|
||||
const childIds = (sib as ISimpleFlight & {
|
||||
_childFlightIds?: typeof sib.flightId[];
|
||||
})._childFlightIds;
|
||||
const sig = childIds && childIds.length > 0
|
||||
? childIds.map((c) => `${c.carrier}${c.flightNumber}`).join("+")
|
||||
: `${sib.flightId.carrier}${sib.flightId.flightNumber}`;
|
||||
return sig === openSignature;
|
||||
});
|
||||
|
||||
return matches.length > 0 ? matches : fallback;
|
||||
}, [
|
||||
miniListSearchParams,
|
||||
siblingSearch.flights,
|
||||
siblingSearch.loading,
|
||||
siblingSearch.error,
|
||||
flights,
|
||||
flightIds,
|
||||
]);
|
||||
|
||||
// Angular's schedule details page adds a third crumb only when the
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
// On the schedule details page, the left mini-list must show only the
|
||||
// CURRENTLY-OPEN flight's instance on each day in the [-1, +1] window —
|
||||
// matching Angular's `CurrentScheduleService.getScheduleType` /
|
||||
// `compareFlightsByPId` filtering. The old behaviour dumped the entire
|
||||
// MOW→MMK route search into the rail (every flight number, every
|
||||
// option), making the rail useless when the user came from the
|
||||
// search-results list.
|
||||
//
|
||||
// Reference URL: connecting itinerary SU 6188 + SU 6341 (Moscow → St
|
||||
// Petersburg → Murmansk) on 2026-04-26. Each visible day in the
|
||||
// mini-list must list ≤ 1 entry — the same SU 6188 itinerary.
|
||||
|
||||
const URL =
|
||||
"/ru-ru/schedule/VKO/SU6188-20260426/LED/SU6341-20260427/MMK?request=schedule-route-MOW-MMK-20260427-20260503";
|
||||
|
||||
test("mini-list shows only the open flight per day, not the full route search", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto(URL);
|
||||
|
||||
// Wait for the mini-list to render.
|
||||
const miniList = page.locator(".schedule-mini-list");
|
||||
await expect(miniList).toBeVisible({ timeout: 15000 });
|
||||
|
||||
// Wait until the day-headers appear (they exist for both the today
|
||||
// and ±1 days). Three day headers are expected total.
|
||||
const dayHeaders = miniList.locator("[data-testid^='mini-list-day-header-']");
|
||||
await expect(dayHeaders).toHaveCount(3);
|
||||
|
||||
// The expanded body must contain at most one flight entry — the
|
||||
// open SU 6188 itinerary. The old behaviour rendered 4+ entries
|
||||
// (every MOW-MMK option for that day).
|
||||
const openBody = miniList
|
||||
.locator("[data-testid^='mini-list-day-']:not([data-testid*='header'])")
|
||||
.first();
|
||||
await expect(openBody).toBeVisible({ timeout: 10000 });
|
||||
// Mini-list items use SU 6188 in their visible label.
|
||||
const items = openBody.locator(".flights-mini-list-item, [class*='mini-list'] [class*='flight']");
|
||||
// Loose assertion — there should be at MOST one entry per day, and
|
||||
// the visible text must include 'SU 6188' (NOT a different
|
||||
// route-mate flight number).
|
||||
const text = (await openBody.innerText()).replace(/\s+/g, " ");
|
||||
expect(text).toContain("SU 6188");
|
||||
// Sanity: should NOT contain other Sunday MOW-MMK flight numbers
|
||||
// that the old listing pulled in (SU 6190 / SU 6699 are typical).
|
||||
expect(text).not.toMatch(/SU\s*6190/);
|
||||
expect(text).not.toMatch(/SU\s*6699/);
|
||||
});
|
||||
Reference in New Issue
Block a user