Add Phase 5C integration tests for PopularRequestsPanel

Covers all 5 request modes, loading/error states, keyboard
accessibility, and the 4-item display limit.
This commit is contained in:
2026-04-15 10:02:09 +03:00
parent 99af1fe00d
commit 78205c378e
@@ -0,0 +1,287 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { PopularRequestsPanel } from "./PopularRequestsPanel";
import type { PopularRequest } from "../types";
// ---------------------------------------------------------------------------
// Mocks
// ---------------------------------------------------------------------------
// Mock the usePopularRequests hook
const mockUsePopularRequests = vi.fn<
() => { requests: PopularRequest[]; loading: boolean; error: Error | null }
>();
vi.mock("../hooks/usePopularRequests.js", () => ({
usePopularRequests: () => mockUsePopularRequests(),
}));
// Mock i18n
vi.mock("@/i18n/provider.js", () => ({
useTranslation: () => ({
t: (key: string) => key,
i18n: { language: "en" },
}),
}));
// Mock useCityName
vi.mock("@/shared/hooks/useDictionaries.js", () => ({
useCityName: (code: string) => code,
}));
// ---------------------------------------------------------------------------
// Test data
// ---------------------------------------------------------------------------
const mockRequests: PopularRequest[] = [
{
mode: "FlightNumber",
carrier: "SU",
flightNumber: "9027",
type: "Onlineboard",
},
{
mode: "FlightNumber",
carrier: "SU",
flightNumber: "9006",
type: "Onlineboard",
},
{
mode: "Route",
departure: "KUF",
arrival: "ABA",
type: "Onlineboard",
},
{
mode: "Route",
departure: "RTW",
arrival: "ABA",
type: "Onlineboard",
},
];
// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
describe("PopularRequestsPanel", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("renders nothing while loading", () => {
mockUsePopularRequests.mockReturnValue({
requests: [],
loading: true,
error: null,
});
const { container } = render(
<PopularRequestsPanel onRequestClick={vi.fn()} />,
);
expect(container.innerHTML).toBe("");
});
it("renders nothing on error (graceful degradation)", () => {
mockUsePopularRequests.mockReturnValue({
requests: [],
loading: false,
error: new Error("API failure"),
});
const { container } = render(
<PopularRequestsPanel onRequestClick={vi.fn()} />,
);
expect(container.innerHTML).toBe("");
});
it("renders nothing when requests array is empty", () => {
mockUsePopularRequests.mockReturnValue({
requests: [],
loading: false,
error: null,
});
const { container } = render(
<PopularRequestsPanel onRequestClick={vi.fn()} />,
);
expect(container.innerHTML).toBe("");
});
it("renders the title and up to 4 request items", () => {
mockUsePopularRequests.mockReturnValue({
requests: mockRequests,
loading: false,
error: null,
});
render(<PopularRequestsPanel onRequestClick={vi.fn()} />);
expect(screen.getByText("BOARD.POPULAR-CHAPTERS")).toBeInTheDocument();
// Should render 4 items
const items = screen.getAllByRole("button");
expect(items).toHaveLength(4);
});
it("calls onRequestClick when a flight number item is clicked", async () => {
mockUsePopularRequests.mockReturnValue({
requests: [mockRequests[0]!],
loading: false,
error: null,
});
const onRequestClick = vi.fn();
render(<PopularRequestsPanel onRequestClick={onRequestClick} />);
const button = screen.getByRole("button");
await userEvent.click(button);
expect(onRequestClick).toHaveBeenCalledWith(mockRequests[0]);
});
it("renders flight number with carrier and number", () => {
mockUsePopularRequests.mockReturnValue({
requests: [mockRequests[0]!],
loading: false,
error: null,
});
render(<PopularRequestsPanel onRequestClick={vi.fn()} />);
// SU\u00a09027 (non-breaking space)
expect(screen.getByText("SU\u00a09027")).toBeInTheDocument();
});
it("renders route request with departure and arrival", () => {
mockUsePopularRequests.mockReturnValue({
requests: [mockRequests[2]!],
loading: false,
error: null,
});
render(<PopularRequestsPanel onRequestClick={vi.fn()} />);
expect(screen.getByText("KUF - ABA")).toBeInTheDocument();
});
it("limits display to 4 items even with more data", () => {
const manyRequests: PopularRequest[] = [
...mockRequests,
{
mode: "Arrival",
arrival: "SVO",
type: "Onlineboard",
},
];
mockUsePopularRequests.mockReturnValue({
requests: manyRequests,
loading: false,
error: null,
});
render(<PopularRequestsPanel onRequestClick={vi.fn()} />);
const items = screen.getAllByRole("button");
expect(items).toHaveLength(4);
});
it("renders arrival request mode", () => {
mockUsePopularRequests.mockReturnValue({
requests: [
{
mode: "Arrival",
arrival: "SVO",
type: "Onlineboard",
},
],
loading: false,
error: null,
});
render(<PopularRequestsPanel onRequestClick={vi.fn()} />);
expect(screen.getByText("BOARD.ARRIVAL")).toBeInTheDocument();
expect(screen.getByText("SVO")).toBeInTheDocument();
});
it("renders departure request mode", () => {
mockUsePopularRequests.mockReturnValue({
requests: [
{
mode: "Departure",
departure: "DME",
type: "Onlineboard",
},
],
loading: false,
error: null,
});
render(<PopularRequestsPanel onRequestClick={vi.fn()} />);
expect(screen.getByText("BOARD.DEPARTURE")).toBeInTheDocument();
expect(screen.getByText("DME")).toBeInTheDocument();
});
it("renders schedule route with correct label", () => {
mockUsePopularRequests.mockReturnValue({
requests: [
{
mode: "Route",
departure: "SVO",
arrival: "LED",
type: "Schedule",
},
],
loading: false,
error: null,
});
render(<PopularRequestsPanel onRequestClick={vi.fn()} />);
expect(screen.getByText("SCHEDULE.SCHEDULE-OUTBOUND")).toBeInTheDocument();
});
it("renders RouteWithBack with full-route label", () => {
mockUsePopularRequests.mockReturnValue({
requests: [
{
mode: "RouteWithBack",
departure: "SVO",
arrival: "JFK",
type: "Schedule",
},
],
loading: false,
error: null,
});
render(<PopularRequestsPanel onRequestClick={vi.fn()} />);
expect(
screen.getByText("SCHEDULE.SCHEDULE-FULL-ROUTE"),
).toBeInTheDocument();
});
it("supports keyboard activation (Enter key)", async () => {
mockUsePopularRequests.mockReturnValue({
requests: [mockRequests[0]!],
loading: false,
error: null,
});
const onRequestClick = vi.fn();
render(<PopularRequestsPanel onRequestClick={onRequestClick} />);
const button = screen.getByRole("button");
button.focus();
await userEvent.keyboard("{Enter}");
expect(onRequestClick).toHaveBeenCalledWith(mockRequests[0]);
});
});