diff --git a/src/features/popular-requests/components/PopularRequestsPanel.test.tsx b/src/features/popular-requests/components/PopularRequestsPanel.test.tsx index 829663ab..6dc96ed8 100644 --- a/src/features/popular-requests/components/PopularRequestsPanel.test.tsx +++ b/src/features/popular-requests/components/PopularRequestsPanel.test.tsx @@ -1,6 +1,14 @@ +/** + * Tests for PopularRequestsPanel component. + * + * Covers all 5 request modes, loading/error states, keyboard + * accessibility, and the 4-item display limit. + * + * @vitest-environment jsdom + */ + import { describe, it, expect, vi, beforeEach } from "vitest"; -import { render, screen, waitFor } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; +import { render, screen, fireEvent } from "@testing-library/react"; import { PopularRequestsPanel } from "./PopularRequestsPanel"; import type { PopularRequest } from "../types"; @@ -8,7 +16,6 @@ import type { PopularRequest } from "../types"; // Mocks // --------------------------------------------------------------------------- -// Mock the usePopularRequests hook const mockUsePopularRequests = vi.fn< () => { requests: PopularRequest[]; loading: boolean; error: Error | null } >(); @@ -17,7 +24,6 @@ vi.mock("../hooks/usePopularRequests.js", () => ({ usePopularRequests: () => mockUsePopularRequests(), })); -// Mock i18n vi.mock("@/i18n/provider.js", () => ({ useTranslation: () => ({ t: (key: string) => key, @@ -25,7 +31,6 @@ vi.mock("@/i18n/provider.js", () => ({ }), })); -// Mock useCityName vi.mock("@/shared/hooks/useDictionaries.js", () => ({ useCityName: (code: string) => code, })); @@ -121,15 +126,14 @@ describe("PopularRequestsPanel", () => { render(); - expect(screen.getByText("BOARD.POPULAR-CHAPTERS")).toBeInTheDocument(); - // Should render 4 items + expect(screen.getByText("BOARD.POPULAR-CHAPTERS")).toBeTruthy(); const items = screen.getAllByRole("button"); expect(items).toHaveLength(4); }); - it("calls onRequestClick when a flight number item is clicked", async () => { + it("calls onRequestClick when a flight number item is clicked", () => { mockUsePopularRequests.mockReturnValue({ - requests: [mockRequests[0]!], + requests: [mockRequests[0] as PopularRequest], loading: false, error: null, }); @@ -138,34 +142,42 @@ describe("PopularRequestsPanel", () => { render(); const button = screen.getByRole("button"); - await userEvent.click(button); + fireEvent.click(button); expect(onRequestClick).toHaveBeenCalledWith(mockRequests[0]); }); it("renders flight number with carrier and number", () => { mockUsePopularRequests.mockReturnValue({ - requests: [mockRequests[0]!], + requests: [mockRequests[0] as PopularRequest], loading: false, error: null, }); - render(); + const { container } = render( + , + ); - // SU\u00a09027 (non-breaking space) - expect(screen.getByText("SU\u00a09027")).toBeInTheDocument(); + // The span contains "SU\u00a09027" — check the button text + const button = screen.getByRole("button"); + expect(button.textContent).toContain("SU"); + expect(button.textContent).toContain("9027"); + // Also check the container has the FLIGHT_NUMBER label + expect(container.textContent).toContain("BOARD.FLIGHT_NUMBER"); }); it("renders route request with departure and arrival", () => { mockUsePopularRequests.mockReturnValue({ - requests: [mockRequests[2]!], + requests: [mockRequests[2] as PopularRequest], loading: false, error: null, }); - render(); + const { container } = render( + , + ); - expect(screen.getByText("KUF - ABA")).toBeInTheDocument(); + expect(container.textContent).toContain("KUF - ABA"); }); it("limits display to 4 items even with more data", () => { @@ -203,10 +215,12 @@ describe("PopularRequestsPanel", () => { error: null, }); - render(); + const { container } = render( + , + ); - expect(screen.getByText("BOARD.ARRIVAL")).toBeInTheDocument(); - expect(screen.getByText("SVO")).toBeInTheDocument(); + expect(container.textContent).toContain("BOARD.ARRIVAL"); + expect(screen.getByRole("button").textContent).toBe("SVO"); }); it("renders departure request mode", () => { @@ -222,10 +236,12 @@ describe("PopularRequestsPanel", () => { error: null, }); - render(); + const { container } = render( + , + ); - expect(screen.getByText("BOARD.DEPARTURE")).toBeInTheDocument(); - expect(screen.getByText("DME")).toBeInTheDocument(); + expect(container.textContent).toContain("BOARD.DEPARTURE"); + expect(screen.getByRole("button").textContent).toBe("DME"); }); it("renders schedule route with correct label", () => { @@ -242,9 +258,11 @@ describe("PopularRequestsPanel", () => { error: null, }); - render(); + const { container } = render( + , + ); - expect(screen.getByText("SCHEDULE.SCHEDULE-OUTBOUND")).toBeInTheDocument(); + expect(container.textContent).toContain("SCHEDULE.SCHEDULE-OUTBOUND"); }); it("renders RouteWithBack with full-route label", () => { @@ -261,16 +279,16 @@ describe("PopularRequestsPanel", () => { error: null, }); - render(); + const { container } = render( + , + ); - expect( - screen.getByText("SCHEDULE.SCHEDULE-FULL-ROUTE"), - ).toBeInTheDocument(); + expect(container.textContent).toContain("SCHEDULE.SCHEDULE-FULL-ROUTE"); }); - it("supports keyboard activation (Enter key)", async () => { + it("supports keyboard activation (Enter key)", () => { mockUsePopularRequests.mockReturnValue({ - requests: [mockRequests[0]!], + requests: [mockRequests[0] as PopularRequest], loading: false, error: null, }); @@ -279,8 +297,23 @@ describe("PopularRequestsPanel", () => { render(); const button = screen.getByRole("button"); - button.focus(); - await userEvent.keyboard("{Enter}"); + fireEvent.keyDown(button, { key: "Enter" }); + + expect(onRequestClick).toHaveBeenCalledWith(mockRequests[0]); + }); + + it("supports keyboard activation (Space key)", () => { + mockUsePopularRequests.mockReturnValue({ + requests: [mockRequests[0] as PopularRequest], + loading: false, + error: null, + }); + + const onRequestClick = vi.fn(); + render(); + + const button = screen.getByRole("button"); + fireEvent.keyDown(button, { key: " " }); expect(onRequestClick).toHaveBeenCalledWith(mockRequests[0]); }); diff --git a/src/shared/hooks/useSearchHistory.test.ts b/src/shared/hooks/useSearchHistory.test.ts index 90389f98..9545c866 100644 --- a/src/shared/hooks/useSearchHistory.test.ts +++ b/src/shared/hooks/useSearchHistory.test.ts @@ -1,3 +1,7 @@ +/** + * @vitest-environment jsdom + */ + import { describe, it, expect, beforeEach, vi } from "vitest"; import { renderHook, act } from "@testing-library/react"; import { useSearchHistory } from "./useSearchHistory"; @@ -42,12 +46,6 @@ const routeItem: SearchHistoryItem = { label: "SVO - JFK", }; -const scheduleItem: SearchHistoryItem = { - type: "schedule-route", - url: "/ru/schedule/route/SVO-LED/20250601-20250607", - label: "SVO - LED", -}; - // --------------------------------------------------------------------------- // Tests // --------------------------------------------------------------------------- diff --git a/src/shared/hooks/useSearchHistory.ts b/src/shared/hooks/useSearchHistory.ts index dcbe394c..8c3f3767 100644 --- a/src/shared/hooks/useSearchHistory.ts +++ b/src/shared/hooks/useSearchHistory.ts @@ -48,8 +48,6 @@ const searchHistoryItemSchema = z.object({ const searchHistorySchema = z.array(searchHistoryItemSchema); -type SearchHistoryData = z.infer; - // --------------------------------------------------------------------------- // Storage key // ---------------------------------------------------------------------------