- Changed the default language in `index.html` from Russian to English, updating the title and button aria-labels for improved accessibility. - Refactored the `buildFetchOptions` function in `api.js` to include an optional external abort signal, enhancing request management. - Updated `fetchDuties` and `fetchCalendarEvents` to support request cancellation using the new abort signal, improving error handling. - Added unit tests for the API functions to ensure proper functionality, including handling of 403 errors and request cancellations. - Enhanced CSS styles for duty markers to improve visual consistency. - Removed unused code and improved the overall structure of the JavaScript files for better maintainability.
88 lines
2.6 KiB
JavaScript
88 lines
2.6 KiB
JavaScript
/**
|
|
* Unit tests for i18n: getLang, t (fallback, params), monthName.
|
|
*/
|
|
|
|
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
|
|
const mockGetInitData = vi.fn();
|
|
vi.mock("./auth.js", () => ({ getInitData: () => mockGetInitData() }));
|
|
|
|
import { getLang, t, monthName, MESSAGES } from "./i18n.js";
|
|
|
|
describe("getLang", () => {
|
|
const origNavigator = globalThis.navigator;
|
|
|
|
beforeEach(() => {
|
|
mockGetInitData.mockReset();
|
|
});
|
|
|
|
it("returns lang from initData user when present", () => {
|
|
mockGetInitData.mockReturnValue(
|
|
"user=" + encodeURIComponent(JSON.stringify({ language_code: "en" }))
|
|
);
|
|
expect(getLang()).toBe("en");
|
|
});
|
|
|
|
it("normalizes ru from initData", () => {
|
|
mockGetInitData.mockReturnValue(
|
|
"user=" + encodeURIComponent(JSON.stringify({ language_code: "ru" }))
|
|
);
|
|
expect(getLang()).toBe("ru");
|
|
});
|
|
|
|
it("falls back to navigator.language when initData empty", () => {
|
|
mockGetInitData.mockReturnValue("");
|
|
Object.defineProperty(globalThis, "navigator", {
|
|
value: { ...origNavigator, language: "en-US", languages: ["en-US", "en"] },
|
|
configurable: true,
|
|
});
|
|
expect(getLang()).toBe("en");
|
|
});
|
|
|
|
it("normalizes to en for unknown language code", () => {
|
|
mockGetInitData.mockReturnValue(
|
|
"user=" + encodeURIComponent(JSON.stringify({ language_code: "uk" }))
|
|
);
|
|
expect(getLang()).toBe("en");
|
|
});
|
|
});
|
|
|
|
describe("t", () => {
|
|
it("returns translation for existing key", () => {
|
|
expect(t("en", "app.title")).toBe("Duty Calendar");
|
|
expect(t("ru", "app.title")).toBe("Календарь дежурств");
|
|
});
|
|
|
|
it("falls back to en when key missing in lang", () => {
|
|
expect(t("ru", "app.title")).toBe("Календарь дежурств");
|
|
expect(t("en", "loading")).toBe("Loading…");
|
|
});
|
|
|
|
it("returns key when key missing in both", () => {
|
|
expect(t("en", "missing.key")).toBe("missing.key");
|
|
expect(t("ru", "unknown")).toBe("unknown");
|
|
});
|
|
|
|
it("replaces params placeholder", () => {
|
|
expect(t("en", "duty.until", { time: "14:00" })).toBe("until 14:00");
|
|
expect(t("ru", "duty.until", { time: "09:30" })).toBe("до 09:30");
|
|
});
|
|
|
|
it("handles empty params", () => {
|
|
expect(t("en", "loading", {})).toBe("Loading…");
|
|
});
|
|
});
|
|
|
|
describe("monthName", () => {
|
|
it("returns month name for 0-based index", () => {
|
|
expect(monthName("en", 0)).toBe("January");
|
|
expect(monthName("en", 11)).toBe("December");
|
|
expect(monthName("ru", 0)).toBe("Январь");
|
|
});
|
|
|
|
it("returns empty string for out-of-range", () => {
|
|
expect(monthName("en", 12)).toBe("");
|
|
expect(monthName("en", -1)).toBe("");
|
|
});
|
|
});
|