diff --git a/tests/e2e/onlineboard-time-filter.spec.ts b/tests/e2e/onlineboard-time-filter.spec.ts new file mode 100644 index 00000000..c142943c --- /dev/null +++ b/tests/e2e/onlineboard-time-filter.spec.ts @@ -0,0 +1,82 @@ +import { test, expect } from "@playwright/test"; + +// TIRREDESIGN-11 — "Время рейса" slider must filter results. +// +// We exercise the full slider→submit→URL→filtered-list pipeline: +// 1. Drag the start thumb of the time-range slider +// 2. Click "Найти" +// 3. Assert URL gained the `-{timeFrom}{timeTo}` suffix +// 4. Assert the rendered list shrank to flights inside the new window + +const ROUTE_URL = "/ru-ru/onlineboard/route/MOW-LED-20260423"; + +test.describe("Onlineboard time-range filter (TIRREDESIGN-11)", () => { + test("URL with time-range suffix filters the list (URL → state path)", async ({ + page, + }) => { + // Baseline: no filter + await page.goto(ROUTE_URL); + await expect(page.locator(".flight-card").first()).toBeVisible({ + timeout: 15000, + }); + const baseline = await page.locator(".flight-card").count(); + expect(baseline).toBeGreaterThan(15); + + // Filtered: 14:00–18:00 + await page.goto(`${ROUTE_URL}-14001800`); + await expect(page.locator(".flight-card").first()).toBeVisible({ + timeout: 15000, + }); + const filtered = await page.locator(".flight-card").count(); + expect(filtered).toBeLessThan(baseline); + + // Slider label reflects the URL bounds + await expect(page.locator(".time-selector__value").first()).toHaveText( + "14:00 — 18:00", + ); + }); + + test("dragging the slider + clicking Найти persists time range to URL", async ({ + page, + }) => { + await page.goto(ROUTE_URL); + await expect(page.locator(".flight-card").first()).toBeVisible({ + timeout: 15000, + }); + + // Drag the start thumb roughly to the 50 % mark (= 12:00). + const slider = page.locator(".p-slider").first(); + const startThumb = page.locator(".p-slider-handle-start").first(); + const sliderBox = await slider.boundingBox(); + const thumbBox = await startThumb.boundingBox(); + expect(sliderBox && thumbBox).toBeTruthy(); + if (!sliderBox || !thumbBox) return; + + const fromX = thumbBox.x + thumbBox.width / 2; + const fromY = thumbBox.y + thumbBox.height / 2; + // 50 % position along the track + const targetX = sliderBox.x + sliderBox.width * 0.5; + + await page.mouse.move(fromX, fromY); + await page.mouse.down(); + // Step the move a few times so PrimeReact's mousemove handler picks it up. + for (let i = 1; i <= 10; i++) { + const x = fromX + ((targetX - fromX) * i) / 10; + await page.mouse.move(x, fromY); + } + await page.mouse.up(); + + // The thumb should have left 0 — exact value depends on snap-to-step. + const labelAfterDrag = await page + .locator(".time-selector__value") + .first() + .textContent(); + expect(labelAfterDrag).not.toBe("00:00 — 24:00"); + + // Submit. + await page.locator('[data-testid="search-submit"]').click(); + + // URL must have grown a time suffix. + await expect(page).toHaveURL(/\/onlineboard\/route\/MOW-LED-20260423-\d{8}/); + }); +});