314 lines
9.5 KiB
TypeScript
314 lines
9.5 KiB
TypeScript
import { test, expect } from "./fixtures/console-gate";
|
|
import {
|
|
routeAppSettingsFixture,
|
|
routeDictionaryFixtures,
|
|
} from "./helpers/api-fixtures";
|
|
|
|
async function routeFlightsMapTransferOnlyFixtures(
|
|
page: import("@playwright/test").Page,
|
|
): Promise<void> {
|
|
await routeAppSettingsFixture(page);
|
|
await routeDictionaryFixtures(page);
|
|
|
|
await page.route("**/api/flights/1/*/destinations?**", async (route) => {
|
|
const url = new URL(route.request().url());
|
|
const departure = url.searchParams.get("departure");
|
|
const arrival = url.searchParams.get("arrival");
|
|
const connections = url.searchParams.get("connections");
|
|
|
|
const hasTransferRoute =
|
|
departure === "LED" && arrival === "MLE" && connections === "1";
|
|
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
data: {
|
|
routes: hasTransferRoute
|
|
? [{ route: ["LED", "SVO", "MLE"], isDirect: false }]
|
|
: [],
|
|
},
|
|
}),
|
|
});
|
|
});
|
|
|
|
await page.route("**/api/flights/v1/*/days/**/flights-map/", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({ days: "1".repeat(200) }),
|
|
}),
|
|
);
|
|
|
|
await page.route("**/map/api/tile/**", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "image/gif",
|
|
body: Buffer.from("R0lGODlhAQABAAAAACw=", "base64"),
|
|
}),
|
|
);
|
|
}
|
|
|
|
async function routeFlightsMapDirectRouteFixtures(
|
|
page: import("@playwright/test").Page,
|
|
): Promise<string[]> {
|
|
await routeAppSettingsFixture(page);
|
|
await routeDictionaryFixtures(page);
|
|
|
|
const destinationRequests: string[] = [];
|
|
|
|
await page.route("**/api/flights/1/*/destinations?**", async (route) => {
|
|
const url = new URL(route.request().url());
|
|
destinationRequests.push(url.toString());
|
|
const departure = url.searchParams.get("departure");
|
|
const arrival = url.searchParams.get("arrival");
|
|
const connections = url.searchParams.get("connections");
|
|
|
|
const isSelectedRoute = departure === "LED" && arrival === "MLE";
|
|
const routes =
|
|
isSelectedRoute && connections === "0"
|
|
? [{ route: ["LED", "MLE"], isDirect: true }]
|
|
: isSelectedRoute && connections === "1"
|
|
? [{ route: ["LED", "SVO", "MLE"], isDirect: false }]
|
|
: [];
|
|
|
|
if (isSelectedRoute && connections === "0") {
|
|
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
}
|
|
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({ data: { routes } }),
|
|
});
|
|
});
|
|
|
|
await page.route("**/api/flights/v1/*/days/**/flights-map/", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({ days: "1".repeat(200) }),
|
|
}),
|
|
);
|
|
|
|
await page.route("**/map/api/tile/**", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "image/gif",
|
|
body: Buffer.from("R0lGODlhAQABAAAAACw=", "base64"),
|
|
}),
|
|
);
|
|
|
|
return destinationRequests;
|
|
}
|
|
|
|
async function routeFlightsMapMoscowSpiderFixtures(
|
|
page: import("@playwright/test").Page,
|
|
): Promise<string[]> {
|
|
await routeAppSettingsFixture(page);
|
|
await routeDictionaryFixtures(page);
|
|
|
|
const destinationRequests: string[] = [];
|
|
|
|
await page.route("**/api/flights/1/*/destinations?**", async (route) => {
|
|
const url = new URL(route.request().url());
|
|
destinationRequests.push(url.toString());
|
|
const departure = url.searchParams.get("departure");
|
|
const arrival = url.searchParams.get("arrival");
|
|
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
data: {
|
|
routes:
|
|
departure === "MOW" && !arrival
|
|
? [
|
|
{ route: ["SVO", "LED"], isDirect: true },
|
|
{ route: ["SVO", "MLE"], isDirect: true },
|
|
]
|
|
: [],
|
|
},
|
|
}),
|
|
});
|
|
});
|
|
|
|
await page.route("**/api/flights/v1/*/days/**/flights-map/", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({ days: "1".repeat(200) }),
|
|
}),
|
|
);
|
|
|
|
await page.route("**/map/api/tile/**", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "image/gif",
|
|
body: Buffer.from("R0lGODlhAQABAAAAACw=", "base64"),
|
|
}),
|
|
);
|
|
|
|
return destinationRequests;
|
|
}
|
|
|
|
async function selectCity(
|
|
page: import("@playwright/test").Page,
|
|
inputTestId: string,
|
|
query: string,
|
|
optionTestId: string,
|
|
): Promise<void> {
|
|
const input = page.getByTestId(inputTestId).locator("input");
|
|
await input.click();
|
|
await input.fill(query);
|
|
await expect(page.getByTestId(optionTestId)).toBeVisible({ timeout: 10000 });
|
|
await page.getByTestId(optionTestId).click();
|
|
}
|
|
|
|
test.describe("Flights Map", () => {
|
|
test("/ru/flights-map renders or shows feature-flag disabled message", async ({
|
|
page,
|
|
consoleMessages,
|
|
}) => {
|
|
await page.goto("/ru-ru/flights-map");
|
|
await page.waitForLoadState("domcontentloaded");
|
|
|
|
// Either the map page renders or the feature-flag-disabled fallback shows
|
|
const mapStart = page.locator('[data-testid="flights-map-start"]');
|
|
const mapDisabled = page.locator('[data-testid="flights-map-disabled"]');
|
|
|
|
await expect(mapStart.or(mapDisabled)).toBeVisible({ timeout: 10000 });
|
|
});
|
|
|
|
test("transfer-only checkbox can be switched off after auto-fallback", async ({
|
|
page,
|
|
consoleMessages,
|
|
}) => {
|
|
await routeFlightsMapTransferOnlyFixtures(page);
|
|
|
|
await page.goto("/ru-ru/flights-map");
|
|
await expect(page.getByTestId("flights-map-start")).toBeVisible();
|
|
|
|
await selectCity(page, "fm-departure-input", "Санкт", "city-suggestion-LED");
|
|
await selectCity(page, "fm-arrival-input", "Мале", "city-suggestion-MLE");
|
|
|
|
const transferToggle = page.getByTestId("fm-connections-toggle");
|
|
const transferLabel = page.getByText("Показать только рейсы с пересадкой", {
|
|
exact: true,
|
|
});
|
|
await expect(transferToggle).toBeEnabled();
|
|
await expect(transferToggle).toBeChecked({ timeout: 10000 });
|
|
|
|
await transferLabel.click();
|
|
await expect(transferToggle).not.toBeChecked();
|
|
await page.waitForLoadState("networkidle", { timeout: 5000 }).catch(() => {});
|
|
await expect(transferToggle).not.toBeChecked();
|
|
|
|
expect(consoleMessages).toEqual([]);
|
|
});
|
|
|
|
test("first click on a city label selects the city and draws spider routes", async ({
|
|
page,
|
|
consoleMessages,
|
|
}) => {
|
|
const destinationRequests = await routeFlightsMapMoscowSpiderFixtures(page);
|
|
|
|
await page.goto("/ru-ru/flights-map");
|
|
await expect(page.getByTestId("flights-map-start")).toBeVisible();
|
|
|
|
const moscowLabel = page.locator(".leaflet-tooltip.city-label", {
|
|
hasText: "Москва",
|
|
});
|
|
await expect(moscowLabel).toHaveCount(1, { timeout: 10000 });
|
|
|
|
await moscowLabel.click();
|
|
|
|
await expect(page.getByTestId("fm-departure-input").locator("input")).toHaveValue(
|
|
"Москва",
|
|
);
|
|
await expect(page.getByTestId("fm-arrival-input").locator("input")).toHaveValue("");
|
|
await expect
|
|
.poll(() =>
|
|
destinationRequests.some(
|
|
(url) =>
|
|
url.includes("departure=MOW") &&
|
|
!url.includes("arrival="),
|
|
),
|
|
)
|
|
.toBe(true);
|
|
await expect(page.locator("path.leaflet-interactive")).not.toHaveCount(0);
|
|
|
|
expect(consoleMessages).toEqual([]);
|
|
});
|
|
|
|
test("first click on a city marker selects the city", async ({
|
|
page,
|
|
consoleMessages,
|
|
}) => {
|
|
const destinationRequests = await routeFlightsMapMoscowSpiderFixtures(page);
|
|
|
|
await page.goto("/ru-ru/flights-map");
|
|
await expect(page.getByTestId("flights-map-start")).toBeVisible();
|
|
|
|
const moscowMarker = page.locator('img.leaflet-marker-icon[title="MOW"]');
|
|
await expect(moscowMarker).toHaveCount(1, { timeout: 10000 });
|
|
|
|
await moscowMarker.click();
|
|
|
|
await expect(page.getByTestId("fm-departure-input").locator("input")).toHaveValue(
|
|
"Москва",
|
|
);
|
|
await expect
|
|
.poll(() =>
|
|
destinationRequests.some(
|
|
(url) =>
|
|
url.includes("departure=MOW") &&
|
|
!url.includes("arrival="),
|
|
),
|
|
)
|
|
.toBe(true);
|
|
|
|
expect(consoleMessages).toEqual([]);
|
|
});
|
|
|
|
test("transfer-only checkbox stays off while a direct route search is still loading", async ({
|
|
page,
|
|
consoleMessages,
|
|
}) => {
|
|
const destinationRequests = await routeFlightsMapDirectRouteFixtures(page);
|
|
|
|
await page.goto("/ru-ru/flights-map");
|
|
await expect(page.getByTestId("flights-map-start")).toBeVisible();
|
|
|
|
await selectCity(page, "fm-departure-input", "Санкт", "city-suggestion-LED");
|
|
await selectCity(page, "fm-arrival-input", "Мале", "city-suggestion-MLE");
|
|
|
|
const transferToggle = page.getByTestId("fm-connections-toggle");
|
|
await expect(transferToggle).toBeEnabled();
|
|
await expect(transferToggle).not.toBeChecked();
|
|
|
|
await expect
|
|
.poll(() =>
|
|
destinationRequests.some(
|
|
(url) =>
|
|
url.includes("departure=LED") &&
|
|
url.includes("arrival=MLE") &&
|
|
url.includes("connections=0"),
|
|
),
|
|
)
|
|
.toBe(true);
|
|
await expect(transferToggle).not.toBeChecked();
|
|
await page.waitForTimeout(500);
|
|
expect(
|
|
destinationRequests.some(
|
|
(url) =>
|
|
url.includes("departure=LED") &&
|
|
url.includes("arrival=MLE") &&
|
|
url.includes("connections=1"),
|
|
),
|
|
).toBe(false);
|
|
|
|
expect(consoleMessages).toEqual([]);
|
|
});
|
|
});
|