import { describe, it, expect, beforeEach, vi } from "vitest"; import { screen, fireEvent, waitFor, within } from "@testing-library/react"; import { renderWithProviders } from "../test/utils"; vi.mock("sonner", () => ({ toast: { success: vi.fn(), error: vi.fn(), warning: vi.fn() } })); vi.mock("../lib/api", () => ({ api: { get: vi.fn(), post: vi.fn(), patch: vi.fn(), put: vi.fn(), delete: vi.fn() }, ApiError: class extends Error {}, })); vi.mock("../stores/authStore", () => ({ useAuthStore: () => ({ doctorUuid: null, dbUuid: "clinic-1", primaryRole: "clinic" }), })); vi.mock("../hooks/useSubscription", () => ({ useSubscription: () => ({ maxSecretaries: 5 }), })); import { api } from "../lib/api"; import MySecretariesPage from "./MySecretariesPage"; const get = api.get as ReturnType; const patch = api.patch as ReturnType; const put = api.put as ReturnType; /** یک منشیِ مشترک بین دو پزشک = دو ردیف لینک با secretary_uuid یکسان */ const sharedSecretaryRows = [ { uuid: "link-a", secretary_uuid: "sec-1", user_name: "ساسان عطایی", mobile_number: "09120671732", doctor_name: "دکتر الف", doctor_uuid: "doc-a", is_active: true, national_code: "1212121212", address: null, permissions: {}, created_at: "1750000000", }, { uuid: "link-b", secretary_uuid: "sec-1", user_name: "ساسان عطایی", mobile_number: "09120671732", doctor_name: "دکتر ب", doctor_uuid: "doc-b", is_active: true, national_code: "1212121212", address: null, permissions: {}, created_at: "1750000000", }, ]; beforeEach(() => { get.mockReset(); patch.mockReset(); put.mockReset(); patch.mockResolvedValue({ success: true, data: {} }); put.mockResolvedValue({ success: true, data: {} }); get.mockImplementation((url: string) => { if (url.includes("/clinic/doctor-list/")) return Promise.resolve({ success: true, data: { data: [ { uuid: "doc-a", name: "دکتر الف" }, { uuid: "doc-b", name: "دکتر ب" }, ] } }); if (url.includes("/secretaries/clinic/")) return Promise.resolve({ success: true, data: [] }); return Promise.resolve({ success: true, data: [] }); }); }); describe("MySecretariesPage — clinic multi-doctor", () => { it("shows the doctor multi-select inside the add modal", async () => { renderWithProviders(, { route: "/admin/my-secretaries" }); // پیکر روی صفحه نیست تا وقتی مودال باز شود expect(screen.queryByText("پزشکانِ این منشی")).not.toBeInTheDocument(); fireEvent.click(await screen.findByText("اضافه کردن منشی")); expect(await screen.findByText("پزشکانِ این منشی")).toBeInTheDocument(); expect(screen.getByText("دکتر الف")).toBeInTheDocument(); expect(screen.getByText("دکتر ب")).toBeInTheDocument(); expect(screen.getByText("انتخاب همه")).toBeInTheDocument(); }); it("selecting all picks every clinic doctor", async () => { renderWithProviders(, { route: "/admin/my-secretaries" }); fireEvent.click(await screen.findByText("اضافه کردن منشی")); await screen.findByText("پزشکانِ این منشی"); fireEvent.click(screen.getByText("انتخاب همه")); expect(screen.getByText(/[۲2] انتخاب‌شده/)).toBeInTheDocument(); expect(screen.getByText("لغو همه")).toBeInTheDocument(); }); }); describe("MySecretariesPage — one row per secretary", () => { beforeEach(() => { get.mockImplementation((url: string) => { if (url.includes("/clinic/doctor-list/")) return Promise.resolve({ success: true, data: { data: [ { uuid: "doc-a", name: "دکتر الف" }, { uuid: "doc-b", name: "دکتر ب" }, ] } }); if (url.includes("/secretaries/clinic/")) return Promise.resolve({ success: true, data: sharedSecretaryRows }); return Promise.resolve({ success: true, data: [] }); }); }); it("renders a secretary shared by two doctors as a single row", async () => { renderWithProviders(, { route: "/admin/my-secretaries" }); const table = within(await screen.findByRole("table")); expect(table.getAllByText("ساسان عطایی")).toHaveLength(1); expect(table.getByText("دکتر الف، دکتر ب")).toBeInTheDocument(); }); it("cancelling collaboration deactivates every link row", async () => { renderWithProviders(, { route: "/admin/my-secretaries" }); const table = within(await screen.findByRole("table")); // اولین «لغو همکاری» عنوان ستون است؛ دکمه‌ی ردیف مورد نظر است fireEvent.click(table.getByRole("button", { name: "لغو همکاری" })); // متن تأیید باید تعداد پزشکان را نشان دهد expect(await screen.findByText(/برای همه‌ی .* پزشک/)).toBeInTheDocument(); fireEvent.click(screen.getAllByText("لغو همکاری").pop()!); await waitFor(() => expect(patch).toHaveBeenCalledTimes(2)); expect(patch).toHaveBeenCalledWith("/api/v1/secretary/link-a", { active: false }); expect(patch).toHaveBeenCalledWith("/api/v1/secretary/link-b", { active: false }); }); it("editing patches every link row and syncs the doctor set", async () => { renderWithProviders(, { route: "/admin/my-secretaries" }); fireEvent.click((await screen.findAllByTitle("ویرایش"))[0]); // مجموعه‌ی پزشکانِ فعلی باید از قبل انتخاب شده باشد expect(await screen.findByText("پزشکانِ این منشی")).toBeInTheDocument(); expect(screen.getByText(/[۲2] انتخاب‌شده/)).toBeInTheDocument(); // حذف یکی از پزشکان (آخرین مورد = ردیف لیست، نه چیپ انتخاب‌شده) fireEvent.click(screen.getAllByText("دکتر ب").pop()!); fireEvent.click(screen.getByText("ذخیره")); await waitFor(() => expect(put).toHaveBeenCalledTimes(1)); expect(patch).toHaveBeenCalledTimes(2); expect(put).toHaveBeenCalledWith("/api/v1/secretaries/clinic/clinic-1/doctors", { secretary_uuid: "sec-1", doctor_uuids: ["doc-a"], }); }); });