WFDASH-WEBAPP/src/components/sidebar.test.tsx
SJCoetz e9cf8aaf04 feat(stock): implement stock management workflow
This commit adds the complete v2/v3 stock management functionality:
- add new stock-specific item statuses and update the status visual map
- implement full stock purchase API suite (create, list, retrieve, send, receive)
- reorganize sidebar navigation to group stock-related pages together
- add stock item CRUD APIs, status utilities, low stock filtering, and surplus booking logic
- add database migration for the `stock_items.target_qty` field
- update type definitions and add comprehensive tests for all new stock components
2026-07-15 21:53:20 +02:00

97 lines
3.2 KiB
TypeScript

import { fireEvent, render, screen, within } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { Sidebar } from "./sidebar";
vi.mock("next/link", () => ({
default: ({ href, children, ...props }: { href: string; children: React.ReactNode }) => (
<a href={href} {...props}>
{children}
</a>
),
}));
vi.mock("next/navigation", () => ({
usePathname: () => "/suppliers",
}));
vi.mock("./auth-provider", () => ({
useAuth: () => ({
user: { name: "Test User", email: "test@example.com" },
logout: vi.fn(),
}),
}));
vi.mock("next-themes", () => ({
useTheme: () => ({
theme: "light",
setTheme: vi.fn(),
}),
}));
describe("Sidebar", () => {
it("does not show a separate supplier map navigation item", () => {
render(<Sidebar />);
expect(screen.getByText("Suppliers")).toBeInTheDocument();
expect(screen.queryByText("Supplier Map")).not.toBeInTheDocument();
});
it("shows pricelist under the Stock section", () => {
render(<Sidebar />);
// Scope to the desktop sidebar (the first <aside>). The mobile
// Sheet renders a duplicate nav tree that's hidden via Tailwind
// `lg:hidden` but still in the DOM, so unscoped role queries
// return two of every button.
const desktop = screen.getAllByRole("complementary")[0];
// The toggle is a `<button>` with text "Stock" (the nav link
// is an `<a>` so role=button scopes us to the toggle only,
// and exact match stops it from matching "Stock Orders" link).
const stockToggle = within(desktop).getByRole("button", {
name: "Stock",
});
fireEvent.click(stockToggle);
const stockSection = stockToggle.parentElement;
expect(stockSection).not.toBeNull();
// The Stock group should contain Stock, Stock Orders, and Pricelist.
// Use role=link to scope to the nav items (not the toggle
// button, which also says "Stock" and would create an
// ambiguous match).
const stock = within(stockSection as HTMLElement);
expect(stock.getByRole("link", { name: "Stock" })).toBeInTheDocument();
expect(stock.getByRole("link", { name: "Stock Orders" })).toBeInTheDocument();
expect(stock.getByRole("link", { name: "Pricelist" })).toBeInTheDocument();
});
it("shows Stock under the Stock section, not Operations", () => {
render(<Sidebar />);
const desktop = screen.getAllByRole("complementary")[0];
const stockToggle = within(desktop).getByRole("button", {
name: "Stock",
});
const operationsToggle = within(desktop).getByRole("button", {
name: "Operations",
});
fireEvent.click(stockToggle);
fireEvent.click(operationsToggle);
const stockSection = stockToggle.parentElement;
const operationsSection = operationsToggle.parentElement;
expect(stockSection).not.toBeNull();
expect(operationsSection).not.toBeNull();
const ops = within(operationsSection as HTMLElement);
// Operations should NOT contain Stock anymore — that's the whole
// point of the reorg.
expect(ops.queryByText("Stock", { exact: true })).not.toBeInTheDocument();
expect(ops.queryByText("Stock Orders")).not.toBeInTheDocument();
expect(ops.queryByText("Pricelist")).not.toBeInTheDocument();
});
});