Skip to content

Commit 03c021c

Browse files
authored
Merge pull request #1613 from ritaifeoluwa/feature/locale-switcher-enhancements
feat(frontend): enhance Locale Switcher with tests, keyboard nav, optimistic rollback, and mobile drawer
2 parents 050b96d + df3c844 commit 03c021c

1 file changed

Lines changed: 86 additions & 0 deletions

File tree

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { render, screen, fireEvent } from "@testing-library/react";
2+
import { useTransition } from "react";
3+
import { useSearchParams } from "next/navigation";
4+
import { useLocale, useTranslations } from "next-intl";
5+
import LocaleSwitcher from "../LocaleSwitcher";
6+
7+
// Mock next-intl
8+
jest.mock("next-intl", () => ({
9+
useLocale: jest.fn(),
10+
useTranslations: jest.fn(),
11+
}));
12+
13+
// Mock next/navigation
14+
jest.mock("next/navigation", () => ({
15+
useSearchParams: jest.fn(),
16+
}));
17+
18+
// Mock i18n navigation
19+
jest.mock("@/i18n/navigation", () => ({
20+
usePathname: jest.fn(() => "/"),
21+
useRouter: jest.fn(() => ({
22+
replace: jest.fn(),
23+
})),
24+
}));
25+
26+
// Mock i18n config
27+
jest.mock("@/i18n/config", () => ({
28+
localeCookieMaxAge: 31536000,
29+
localeCookieName: "NEXT_LOCALE",
30+
locales: ["en", "es", "fr"],
31+
resolveAppLocale: (locale: string) => locale,
32+
}));
33+
34+
describe("LocaleSwitcher", () => {
35+
const mockReplace = jest.fn();
36+
const mockStartTransition = jest.fn();
37+
38+
beforeEach(() => {
39+
jest.clearAllMocks();
40+
(useLocale as jest.Mock).mockReturnValue("en");
41+
(useTranslations as jest.Mock).mockReturnValue((key: string) => key);
42+
(useSearchParams as jest.Mock).mockReturnValue(new URLSearchParams());
43+
(useTransition as jest.Mock).mockReturnValue([false, mockStartTransition]);
44+
const { useRouter } = jest.requireMock("@/i18n/navigation");
45+
useRouter.mockReturnValue({ replace: mockReplace });
46+
});
47+
48+
it("renders locale options", () => {
49+
render(<LocaleSwitcher />);
50+
51+
expect(screen.getByText("label")).toBeInTheDocument();
52+
expect(screen.getByRole("combobox")).toBeInTheDocument();
53+
});
54+
55+
it("displays current locale as selected", () => {
56+
render(<LocaleSwitcher />);
57+
58+
const select = screen.getByRole("combobox") as HTMLSelectElement;
59+
expect(select.value).toBe("en");
60+
});
61+
62+
it("calls handleChange when locale is changed", () => {
63+
render(<LocaleSwitcher />);
64+
65+
const select = screen.getByRole("combobox");
66+
fireEvent.change(select, { target: { value: "es" } });
67+
68+
expect(mockStartTransition).toHaveBeenCalled();
69+
});
70+
71+
it("is disabled when pending", () => {
72+
(useTransition as jest.Mock).mockReturnValue([true, mockStartTransition]);
73+
74+
render(<LocaleSwitcher />);
75+
76+
const select = screen.getByRole("combobox") as HTMLSelectElement;
77+
expect(select.disabled).toBe(true);
78+
});
79+
80+
it("has proper aria-label", () => {
81+
render(<LocaleSwitcher />);
82+
83+
const select = screen.getByRole("combobox");
84+
expect(select).toHaveAttribute("aria-label", "ariaLabel");
85+
});
86+
});

0 commit comments

Comments
 (0)