94 lines
3.6 KiB
TypeScript
94 lines
3.6 KiB
TypeScript
import "@testing-library/jest-dom";
|
|
import { fireEvent, render, screen } from "@testing-library/react";
|
|
import { MemoryRouter } from "react-router";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { UI_ACTION_IDS } from "~/application/ui/uiRegistry";
|
|
import NotificationsButton from "./NotificationsButton";
|
|
import ProfileButton from "./ProfileButton";
|
|
import SearchButton from "./SearchButton";
|
|
|
|
vi.mock("react-i18next", () => ({
|
|
useTranslation: () => ({ t: (value: string) => value }),
|
|
}));
|
|
|
|
vi.mock("react-router", async () => {
|
|
const actual = await vi.importActual<typeof import("react-router")>("react-router");
|
|
return {
|
|
...actual,
|
|
Form: ({ children, ...props }: React.ComponentProps<"form">) => <form {...props}>{children}</form>,
|
|
};
|
|
});
|
|
|
|
vi.mock("~/utils/data/useRootData", () => ({
|
|
useRootData: () => (globalThis as any).__layoutButtonsRootData,
|
|
}));
|
|
|
|
vi.mock("~/utils/data/useAppOrAdminData", () => ({
|
|
useAppOrAdminData: () => ({ permissions: [] }),
|
|
}));
|
|
|
|
describe("layout button UI IDs", () => {
|
|
beforeEach(() => {
|
|
(globalThis as any).__layoutButtonsRootData = { appConfiguration: { app: { features: { tenantApiKeys: false } } } };
|
|
});
|
|
|
|
it("renders SearchButton with a stable action ID", () => {
|
|
render(<SearchButton onClick={vi.fn()} />);
|
|
|
|
expect(document.querySelector(`[data-ui-id="${UI_ACTION_IDS.search}"]`)).toBeInTheDocument();
|
|
});
|
|
|
|
it("renders NotificationsButton with a stable action ID", () => {
|
|
render(
|
|
<MemoryRouter>
|
|
<NotificationsButton unseenCount={2} to="/acme/notifications" />
|
|
</MemoryRouter>
|
|
);
|
|
|
|
expect(screen.getByLabelText("shell.notifications.ariaLabel")).toHaveAttribute("data-ui-id", UI_ACTION_IDS.notifications);
|
|
expect(screen.getByLabelText("shell.notifications.ariaLabel")).toHaveAttribute("href", "/acme/notifications");
|
|
});
|
|
|
|
it("renders ProfileButton with stable action and menu IDs", () => {
|
|
render(
|
|
<MemoryRouter>
|
|
<ProfileButton user={{ email: "user@example.com", firstName: "Ada", lastName: "Lovelace", avatar: null }} layout="admin" />
|
|
</MemoryRouter>
|
|
);
|
|
|
|
expect(document.querySelector(`[data-ui-id="${UI_ACTION_IDS.profile}.menu"]`)).toBeInTheDocument();
|
|
expect(screen.getByLabelText("shell.profile.userMenu")).toHaveAttribute("data-ui-id", UI_ACTION_IDS.profile);
|
|
});
|
|
|
|
it("uses default tenant settings links in the public profile menu when available", () => {
|
|
(globalThis as any).__layoutButtonsRootData = {
|
|
...(globalThis as any).__layoutButtonsRootData,
|
|
currentTenant: { id: "tenant_1", slug: "acme" },
|
|
};
|
|
|
|
render(
|
|
<MemoryRouter>
|
|
<ProfileButton user={{ email: "user@example.com", firstName: "Ada", lastName: "Lovelace", avatar: null }} layout="/" />
|
|
</MemoryRouter>
|
|
);
|
|
|
|
fireEvent.click(screen.getByLabelText("shell.profile.userMenu"));
|
|
|
|
expect(screen.getByRole("menuitem", { name: "app.navbar.profile" })).toHaveAttribute("href", "/acme/settings/profile");
|
|
expect(screen.getByRole("menuitem", { name: "app.navbar.subscription" })).toHaveAttribute("href", "/acme/settings/subscription");
|
|
});
|
|
|
|
it("localizes the public admin menu link", () => {
|
|
render(
|
|
<MemoryRouter>
|
|
<ProfileButton user={{ email: "admin@example.com", firstName: "Ada", lastName: "Lovelace", avatar: null, admin: { userId: "user_1" } }} layout="/" />
|
|
</MemoryRouter>
|
|
);
|
|
|
|
fireEvent.click(screen.getByLabelText("shell.profile.userMenu"));
|
|
|
|
expect(screen.getByRole("menuitem", { name: "shared.admin" })).toHaveAttribute("href", "/dashboard");
|
|
expect(screen.queryByRole("menuitem", { name: "Admin" })).not.toBeInTheDocument();
|
|
});
|
|
});
|