test(notifications): the center re-says its rows after a switch, a repeat coalesces by content; e2e helper fails with a cause
The center's rows (title, message, refusal, live button) were never rendered across a language switch, and nothing held the structural compare that coalescing now needs. The channel-link helper swallowed whatever ended its poll into a bare false: a link that goes away mid-look now counts as not hit, and no hittable link fails with the poll's own message.
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
// @vitest-environment jsdom
|
||||
//
|
||||
// The notification center says this browser's notices in the reader's language of the moment: a
|
||||
// row raised in English reads Hungarian after a switch, its title, its message, a server refusal
|
||||
// and the button of a notice still live. The real i18n, not the key passthrough the other panel
|
||||
// tests use.
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { act, cleanup, render, screen } from "@testing-library/react";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import i18n from "../../i18n";
|
||||
import { api, type AppNotification } from "../../lib/api";
|
||||
import type { Notification as ClientNotif } from "../../lib/notifications";
|
||||
|
||||
const h = vi.hoisted(() => ({ client: [] as unknown[] }));
|
||||
|
||||
vi.mock("../../components/ui/confirmContext", () => ({ useConfirm: () => vi.fn() }));
|
||||
vi.mock("../../lib/notifications", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../../lib/notifications")>()),
|
||||
subscribe: () => () => {},
|
||||
getNotifications: () => h.client,
|
||||
getUnreadCount: () => 0,
|
||||
markAllRead: () => {},
|
||||
}));
|
||||
vi.mock("../../features/navigation/navigationContext", () => ({
|
||||
useNavigationActions: () => ({ setPage: vi.fn() }),
|
||||
}));
|
||||
vi.mock("../files/filesContext", () => ({ useFilesActions: () => ({ openFile: vi.fn() }) }));
|
||||
vi.mock("../channels/channelsContext", () => ({
|
||||
useChannelsActions: () => ({ focusChannel: vi.fn() }),
|
||||
}));
|
||||
vi.mock("../feed/feedFiltersContext", () => ({
|
||||
useFeedFilters: () => ({}),
|
||||
useFeedFiltersActions: () => ({ setFilters: vi.fn() }),
|
||||
}));
|
||||
vi.mock("../../components/ui/PageShell", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../../components/ui/PageShell")>()),
|
||||
PageToolbar: ({ children }: { children: React.ReactNode }) => <>{children}</>,
|
||||
}));
|
||||
|
||||
import NotificationsPanel from "./NotificationsPanel";
|
||||
import { msg } from "../../lib/notifications";
|
||||
|
||||
beforeEach(async () => {
|
||||
await i18n.changeLanguage("en");
|
||||
vi.spyOn(api, "notifications").mockResolvedValue({
|
||||
items: [] as AppNotification[],
|
||||
total: 0,
|
||||
});
|
||||
});
|
||||
afterEach(async () => {
|
||||
cleanup();
|
||||
vi.restoreAllMocks();
|
||||
await i18n.changeLanguage("en");
|
||||
});
|
||||
|
||||
const notice = (id: number, extra: Partial<ClientNotif>) =>
|
||||
({
|
||||
id,
|
||||
level: "info",
|
||||
message: msg("common.copy.done"),
|
||||
requiresInteraction: false,
|
||||
ts: Date.now() - 60_000,
|
||||
read: false,
|
||||
dismissed: false,
|
||||
transient: false,
|
||||
repeat: 1,
|
||||
...extra,
|
||||
}) as unknown as ClientNotif;
|
||||
|
||||
function mount() {
|
||||
render(
|
||||
<QueryClientProvider client={new QueryClient()}>
|
||||
<main>
|
||||
<NotificationsPanel />
|
||||
</main>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
describe("NotificationsPanel · the reader's language", () => {
|
||||
it("says a row's title, message, refusal and live button again after a switch", async () => {
|
||||
h.client = [
|
||||
notice(1, {
|
||||
title: msg("views.actionFailed"),
|
||||
message: { detail: { code: "not_found", reason: "view" } },
|
||||
level: "error",
|
||||
}),
|
||||
notice(2, { action: { label: msg("common.undo"), onClick: () => {} } }),
|
||||
];
|
||||
mount();
|
||||
const en = i18n.getFixedT("en");
|
||||
const hu = i18n.getFixedT("hu");
|
||||
expect(await screen.findByText(en("views.actionFailed"))).toBeTruthy();
|
||||
expect(screen.getByText("This view doesn't exist any more")).toBeTruthy();
|
||||
expect(screen.getByText(en("common.copy.done"))).toBeTruthy();
|
||||
expect(screen.getByRole("button", { name: en("common.undo") })).toBeTruthy();
|
||||
|
||||
await act(async () => void (await i18n.changeLanguage("hu")));
|
||||
|
||||
expect(screen.getByText(hu("views.actionFailed"))).toBeTruthy();
|
||||
expect(screen.getByText("Ez a nézet már nem létezik")).toBeTruthy();
|
||||
expect(screen.getByText(hu("common.copy.done"))).toBeTruthy();
|
||||
expect(screen.getByRole("button", { name: hu("common.undo") })).toBeTruthy();
|
||||
expect(screen.queryByText(en("views.actionFailed"))).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user