Fixes: 1. media.ts: wrap placeholder generation in try-catch 2. toolbar.ts: check r.ok, display error message in popover
145 lines
4.4 KiB
TypeScript
145 lines
4.4 KiB
TypeScript
import { Toasty } from "@cloudflare/kumo";
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
import * as React from "react";
|
|
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
|
|
import { MenuList } from "../../src/components/MenuList";
|
|
import { render } from "../utils/render.tsx";
|
|
|
|
vi.mock("@tanstack/react-router", async () => {
|
|
const actual = await vi.importActual("@tanstack/react-router");
|
|
return {
|
|
...actual,
|
|
Link: ({
|
|
children,
|
|
to,
|
|
...props
|
|
}: {
|
|
children: React.ReactNode;
|
|
to?: string;
|
|
[key: string]: unknown;
|
|
}) => (
|
|
<a href={typeof to === "string" ? to : "#"} {...props}>
|
|
{children}
|
|
</a>
|
|
),
|
|
useNavigate: () => vi.fn(),
|
|
};
|
|
});
|
|
|
|
vi.mock("../../src/lib/api", async () => {
|
|
const actual = await vi.importActual("../../src/lib/api");
|
|
return {
|
|
...actual,
|
|
fetchMenus: vi.fn(),
|
|
createMenu: vi.fn().mockResolvedValue({ name: "new-menu", label: "New Menu" }),
|
|
deleteMenu: vi.fn().mockResolvedValue(undefined),
|
|
};
|
|
});
|
|
|
|
import * as api from "../../src/lib/api";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Constants
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const MAIN_MENU_ITEMS_REGEX = /main.*3 items/;
|
|
const FOOTER_MENU_ITEMS_REGEX = /footer.*1 items/;
|
|
const DELETE_MENU_CONFIRMATION_REGEX = /Are you sure you want to delete this menu/;
|
|
const CREATE_MENU_REGEX = /Create Menu/;
|
|
|
|
function mockMenus() {
|
|
vi.mocked(api.fetchMenus).mockResolvedValue([
|
|
{
|
|
id: "m1",
|
|
name: "main",
|
|
label: "Main Menu",
|
|
itemCount: 3,
|
|
created_at: "",
|
|
updated_at: "",
|
|
},
|
|
{
|
|
id: "m2",
|
|
name: "footer",
|
|
label: "Footer Menu",
|
|
itemCount: 1,
|
|
created_at: "",
|
|
updated_at: "",
|
|
},
|
|
]);
|
|
}
|
|
|
|
function Wrapper({ children }: { children: React.ReactNode }) {
|
|
const qc = new QueryClient({
|
|
defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
|
|
});
|
|
return (
|
|
<Toasty>
|
|
<QueryClientProvider client={qc}>{children}</QueryClientProvider>
|
|
</Toasty>
|
|
);
|
|
}
|
|
|
|
describe("MenuList", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
mockMenus();
|
|
});
|
|
|
|
it("displays list of menus with labels and item counts", async () => {
|
|
const screen = await render(<MenuList />, { wrapper: Wrapper });
|
|
|
|
await expect.element(screen.getByRole("heading", { name: "Main Menu" })).toBeInTheDocument();
|
|
await expect.element(screen.getByText(MAIN_MENU_ITEMS_REGEX)).toBeInTheDocument();
|
|
await expect.element(screen.getByRole("heading", { name: "Footer Menu" })).toBeInTheDocument();
|
|
await expect.element(screen.getByText(FOOTER_MENU_ITEMS_REGEX)).toBeInTheDocument();
|
|
});
|
|
|
|
it("Create Menu button opens dialog", async () => {
|
|
const screen = await render(<MenuList />, { wrapper: Wrapper });
|
|
|
|
await screen.getByRole("button", { name: CREATE_MENU_REGEX }).click();
|
|
await expect.element(screen.getByText("Create New Menu")).toBeInTheDocument();
|
|
});
|
|
|
|
it("create dialog has name and label inputs", async () => {
|
|
const screen = await render(<MenuList />, { wrapper: Wrapper });
|
|
|
|
await screen.getByRole("button", { name: CREATE_MENU_REGEX }).click();
|
|
|
|
await expect.element(screen.getByLabelText("Name")).toBeInTheDocument();
|
|
await expect.element(screen.getByLabelText("Label")).toBeInTheDocument();
|
|
});
|
|
|
|
it("delete button opens confirmation dialog", async () => {
|
|
const screen = await render(<MenuList />, { wrapper: Wrapper });
|
|
|
|
await expect.element(screen.getByRole("heading", { name: "Main Menu" })).toBeInTheDocument();
|
|
|
|
await screen.getByRole("button", { name: "Delete main menu" }).click();
|
|
|
|
await expect.element(screen.getByRole("heading", { name: "Delete Menu" })).toBeInTheDocument();
|
|
await expect.element(screen.getByText(DELETE_MENU_CONFIRMATION_REGEX)).toBeInTheDocument();
|
|
});
|
|
|
|
it("shows empty state when no menus", async () => {
|
|
vi.mocked(api.fetchMenus).mockResolvedValue([]);
|
|
|
|
const screen = await render(<MenuList />, { wrapper: Wrapper });
|
|
|
|
await expect.element(screen.getByText("No menus yet")).toBeInTheDocument();
|
|
await expect
|
|
.element(screen.getByText("Create your first navigation menu to get started"))
|
|
.toBeInTheDocument();
|
|
});
|
|
|
|
it("each menu has an Edit link", async () => {
|
|
const screen = await render(<MenuList />, { wrapper: Wrapper });
|
|
|
|
await expect.element(screen.getByRole("heading", { name: "Main Menu" })).toBeInTheDocument();
|
|
|
|
const editLinks = screen.getByText("Edit");
|
|
await expect.element(editLinks.first()).toBeInTheDocument();
|
|
});
|
|
});
|