Files
salona/tests/PersonnelCard.test.tsx
farnoosh-krm ed3906fad6 add tests and UI modified
(fix): add appointment code in requests and profile completion reward
(test): add test coverage for multiple pages and components

(fix) - Added appointment code to the Requests section
(fix) - Added "Claim Gift" feature for completing the profile

(test) Added tests for the following pages/components:
1- Active Devices
2- Add Service
3- Appointment Request (cards display section)
4- Create Gift Card
5- Customer List component (used in Quick Booking, Advanced Booking, etc.)
6- Customer List in Customer Club
7- Delete and Edit buttons (used across the entire app)
8- Invoice
9- Create Individual Schedule Table
10- Notification SMS in SMS Center
11- Loyalty Card List
12- Loyal Customers in ResAssistant
13- Map component
14- Staff List in Staff Management
15- Services List (used in General Link, Custom Link, Advanced Booking, etc.)
16- Services List (used in Quick Booking, Gift Card, Discount Center, etc.)
2026-04-13 16:32:38 +03:30

247 lines
7.4 KiB
TypeScript

import { render, screen, fireEvent } from "@testing-library/react";
import PersonnelCard, {
PersonnelSimple,
} from "@/apps/new-ui/pages/Personnel/+components/PersonnelCard";
import {
useDeletePersonel,
useGetPersonelExtraInformation,
} from "@/apps/new-ui/services/PersonnelServices";
import { showWarningAlert } from "@/apps/new-ui/components/CustomAlert";
import { notifyOnce } from "@/lib/toastManager-2";
import { useNavigate } from "react-router-dom";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
window.scrollTo = jest.fn();
jest.mock("../src/apps/new-ui/Utils/env.ts", () => ({
ENV: {
API_URL: "https://api.test",
},
}));
jest.mock("@/utils/axios-interceptor", () => ({
appointmentClient: {
get: jest.fn(),
post: jest.fn(),
put: jest.fn(),
delete: jest.fn(),
},
}));
// ------------------ Mock فایل‌ها و کتابخانه‌ها ------------------
jest.mock("@/apps/new-ui/assets/profilePhoto.svg", () => "mock-avatar");
jest.mock("@/apps/new-ui/services/PersonnelServices", () => ({
useDeletePersonel: jest.fn(),
useGetPersonelExtraInformation: jest.fn(),
useGetPersonel: jest.fn(() => ({
data: {
services: [],
duration_days: 20,
appointments_count: 5,
remaind_fee: 800000,
},
refetch: jest.fn(),
})),
}));
jest.mock("@/apps/new-ui/services/PersonnelServices", () => ({
useDeletePersonel: jest.fn(() => ({ mutate: jest.fn() })),
useGetPersonelExtraInformation: jest.fn(() => ({
data: { duration_days: 20, appointments_count: 5, remaind_fee: 800000 },
})),
useGetPersonel: jest.fn(() => ({
data: {
services: [],
duration_days: 20,
appointments_count: 5,
remaind_fee: 800000,
},
refetch: jest.fn(),
})),
useAddServiceToPersonel: jest.fn(() => ({ mutate: jest.fn() })),
useDeletePersonelService: jest.fn(() => ({ mutate: jest.fn() })),
}));
jest.mock(
"@/apps/new-ui/pages/Personnel/+components/ManageServicesModal",
() => () => <div>ManageServicesModal</div>,
);
jest.mock("@/apps/new-ui/components/CustomAlert", () => ({
showWarningAlert: jest.fn(),
}));
jest.mock("@/lib/toastManager-2", () => ({
notifyOnce: jest.fn(),
}));
jest.mock("react-router-dom", () => ({
...jest.requireActual("react-router-dom"),
useNavigate: jest.fn(),
useLocation: jest.fn(() => ({ pathname: "/" })),
}));
// mock محیط VITE (import.meta.env)
(global as any).import = {
meta: {
env: {
VITE_APP_API_URL: "http://localhost:3000",
},
},
};
// ------------------ داده پیش‌فرض ------------------
const mockPersonel: PersonnelSimple = {
personel_id: 10,
first_name: "امیر",
last_name: "عباسی",
score: 4.5,
total_appointments: 5,
services: [{ service_name: "اصلاح", type_of_service: "hair", price: 120000 }],
};
// ------------------ mocks ------------------
const mockNavigate = jest.fn();
const mockDeleteMutate = jest.fn();
describe("PersonnelCard Component", () => {
beforeEach(() => {
jest.clearAllMocks();
(useNavigate as jest.Mock).mockReturnValue(mockNavigate);
(useDeletePersonel as jest.Mock).mockReturnValue({
mutate: mockDeleteMutate,
});
(useGetPersonelExtraInformation as jest.Mock).mockReturnValue({
data: {
duration_days: 20,
appointments_count: 5,
remaind_fee: 800000,
},
});
});
const renderCard = () =>
render(
<QueryClientProvider client={queryClient}>
<PersonnelCard personel={mockPersonel} onClick={jest.fn()} />
</QueryClientProvider>,
);
// -------------------------------------------------------------
test("کارت پرسنل به‌درستی رندر می‌شود", () => {
renderCard();
expect(screen.getByText("امیر عباسی")).toBeInTheDocument();
screen.getAllByText("4.5").forEach((el) => {
expect(el).toBeInTheDocument();
});
expect(screen.getByText("مدیریت خدمات")).toBeInTheDocument();
});
// -------------------------------------------------------------
test("باز و بسته شدن آکاردئون کار می‌کند", () => {
renderCard();
const trigger = screen.getByText("امیر عباسی").closest("[role='button']")!;
// پیدا کردن کانتینر آکاردئون (نه کارت)
const accordion = document.querySelector(
"div.w-full.mx-auto.transition-all.overflow-hidden",
) as HTMLElement;
expect(accordion).toHaveClass("h-0");
fireEvent.click(trigger);
expect(accordion).not.toHaveClass("h-0");
fireEvent.click(trigger);
expect(accordion).toHaveClass("h-0");
});
// -------------------------------------------------------------
test("باز شدن مودال مدیریت خدمات", () => {
renderCard();
fireEvent.click(screen.getByText("مدیریت خدمات"));
expect(screen.getByText("ManageServicesModal")).toBeInTheDocument();
});
// -------------------------------------------------------------
test("باز شدن منوی سه‌نقطه (portal) و اجرای گزینه‌های آن", () => {
const mockOnClick = jest.fn();
render(<PersonnelCard personel={mockPersonel} onClick={mockOnClick} />);
const menuBtn = screen.getByRole("button", { name: "" });
fireEvent.click(menuBtn);
// گزینه‌های منو ظاهر شوند
expect(screen.getByText("تنظیمات")).toBeInTheDocument();
expect(screen.getByText("ویرایش")).toBeInTheDocument();
expect(screen.getByText("حذف")).toBeInTheDocument();
expect(screen.getByText("تماس")).toBeInTheDocument();
// تست تنظیمات
fireEvent.click(screen.getByText("تنظیمات"));
expect(mockOnClick).toHaveBeenCalledWith(10);
});
// -------------------------------------------------------------
test("دکمه ویرایش باید به /personnel/add?id=ID ناوبری کند", () => {
renderCard();
fireEvent.click(screen.getByRole("button", { name: "" })); // سه‌نقطه
fireEvent.click(screen.getByText("ویرایش"));
expect(mockNavigate).toHaveBeenCalledWith("/personnel/add?id=10");
});
// -------------------------------------------------------------
test("دکمه حذف alert را نمایش می‌دهد و سپس mutation اجرا می‌شود", () => {
renderCard();
fireEvent.click(screen.getByRole("button", { name: "" }));
fireEvent.click(screen.getByText("حذف"));
expect(showWarningAlert).toHaveBeenCalled();
// اجرای callback حذف
const approveCallback = (showWarningAlert as jest.Mock).mock.calls[0][1];
approveCallback();
expect(mockDeleteMutate).toHaveBeenCalledWith(10);
});
// -------------------------------------------------------------
test("در صورت نبود شماره تماس، notifyOnce اجرا می‌شود", () => {
const personelWithoutPhone = { ...mockPersonel, phone_number: undefined };
render(
<PersonnelCard personel={personelWithoutPhone} onClick={jest.fn()} />,
);
fireEvent.click(screen.getByRole("button", { name: "" }));
fireEvent.click(screen.getByText("تماس"));
expect(notifyOnce).toHaveBeenCalled();
});
// -------------------------------------------------------------
test("باز شدن مودال مدیریت خدمات", () => {
renderCard();
fireEvent.click(screen.getByText("مدیریت خدمات"));
expect(screen.getByText(/ManageServicesModal/i)).toBeInTheDocument();
});
});