Files
kandev/apps/web/components/settings/notification-permission-section.test.tsx
T
João Salavisa e4c4efec18 feat(i18n): localize Settings > General > Notifications
Settings > General > Notifications held all of its copy as literals, so the page
stayed English under a locale switch. Every string now resolves through t() /
<Trans> at render, and the page is on the i18nGuardFiles allowlist so it cannot
drift back.

Event titles, sound preset names and the permission button label resolve from
maps of catalog keys rather than module-scope t(), so they follow a locale
switch. The Apprise install notice is a single <Trans> message so the link stays
inside the sentence. SCREENS in the pseudo-locale oracle gains a per-screen
allow list for text the frontend must not translate (backend-owned provider
names).
2026-08-02 01:49:44 +02:00

109 lines
3.4 KiB
TypeScript

import { cleanup, render, renderHook, screen, waitFor } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
DesktopNotificationsSection,
useNotificationPermission,
} from "./notification-permission-section";
const mocks = vi.hoisted(() => ({
nativeAvailable: vi.fn(),
nativePermissionGet: vi.fn(),
}));
const originalNotification = globalThis.Notification;
vi.mock("@/lib/desktop/native-notification-client", () => ({
nativeNotifications: {
isAvailable: mocks.nativeAvailable,
permission: { get: mocks.nativePermissionGet },
},
}));
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
cleanup();
Object.defineProperty(globalThis, "Notification", {
configurable: true,
value: originalNotification,
});
});
describe("useNotificationPermission", () => {
it("reads native notification permission when Tauri is available", async () => {
mocks.nativeAvailable.mockReturnValue(true);
mocks.nativePermissionGet.mockResolvedValue("granted");
const { result } = renderHook(() => useNotificationPermission());
await waitFor(() => expect(result.current.notificationPermission).toBe("granted"));
expect(mocks.nativePermissionGet).toHaveBeenCalledOnce();
});
it("reads browser notification permission when Tauri is unavailable", async () => {
mocks.nativeAvailable.mockReturnValue(false);
Object.defineProperty(globalThis, "Notification", {
configurable: true,
value: { permission: "denied" },
});
const { result } = renderHook(() => useNotificationPermission());
await waitFor(() => expect(result.current.notificationPermission).toBe("denied"));
});
it("reports unsupported when browser notifications are unavailable", async () => {
mocks.nativeAvailable.mockReturnValue(false);
Object.defineProperty(globalThis, "Notification", {
configurable: true,
value: undefined,
});
const { result } = renderHook(() => useNotificationPermission());
await waitFor(() => expect(result.current.notificationPermission).toBe("unsupported"));
});
it("reports an error when the native permission query rejects", async () => {
mocks.nativeAvailable.mockReturnValue(true);
mocks.nativePermissionGet.mockRejectedValueOnce(new Error("native permission unavailable"));
const { result } = renderHook(() => useNotificationPermission());
await waitFor(() => expect(result.current.notificationPermission).toBe("error"));
});
});
describe("DesktopNotificationsSection", () => {
it("names the permission refresh button", () => {
render(
<DesktopNotificationsSection
notificationPermission="default"
onRequestPermission={vi.fn()}
onRefreshPermission={vi.fn()}
onTestNotification={vi.fn()}
/>,
);
expect(screen.getByRole("button", { name: "Refresh notification permission" })).toBeTruthy();
});
it.each([
["default" as const, "Enable"],
["granted" as const, "Enabled"],
["error" as const, "Retry"],
])("labels the permission button %s as %s", (permission, label) => {
render(
<DesktopNotificationsSection
notificationPermission={permission}
onRequestPermission={vi.fn()}
onRefreshPermission={vi.fn()}
onTestNotification={vi.fn()}
/>,
);
expect(screen.getByRole("button", { name: label })).toBeTruthy();
});
});