import { render, screen, fireEvent, act } from "@testing-library/react";
import { useGetUserInfo } from "@/apps/new-ui/services/User";
import Services from "@/apps/new-ui/components/AppointmentComponents/Services";
// ---- MOCKS ----
// mock Swiper to avoid DOM errors
jest.mock("swiper/react", () => ({
Swiper: ({ children }: any) =>
{children}
,
SwiperSlide: ({ children }: any) => {children}
,
}));
jest.mock("swiper/modules", () => ({
Navigation: {},
Autoplay: {},
}));
// mock VoiceSearchInput
jest.mock("@/apps/new-ui/components/VoiceSearchInput", () => {
return function MockVoiceInput(props: any) {
return (
props.onChange(e.target.value)}
/>
);
};
});
// mock AddService modal
jest.mock("@/apps/new-ui/pages/AddService/AddService", () => () => (
AddService Component
));
// mock useGetUserInfo
jest.mock("@/apps/new-ui/services/User", () => ({
useGetUserInfo: jest.fn(),
}));
// Helper localStorage mock
const localStore: Record = {};
beforeEach(() => {
localStorage.clear();
Object.keys(localStore).forEach((k) => delete localStore[k]);
jest.spyOn(window.localStorage.__proto__, "getItem").mockImplementation(
(...args: any[]) => {
const key = args[0];
return localStore[key] || null;
}
);
jest.spyOn(window.localStorage.__proto__, "setItem").mockImplementation(
(...args: any[]) => {
const [key, value] = args;
localStore[key] = value;
}
);
jest.spyOn(window.localStorage.__proto__, "removeItem").mockImplementation(
(...args: any[]) => {
const key = args[0];
delete localStore[key];
}
);
});
// test data
const mockServices = [
{ emoji: "💆♀️", name: "ماساژ", price: 200 },
{ emoji: "💅", name: "مانیکور", price: 150 },
{ emoji: "💇♀️", name: "اصلاح", price: 100 },
];
describe("Services Component", () => {
beforeEach(() => {
(useGetUserInfo as jest.Mock).mockReturnValue({
data: {
current_user: {
services: mockServices,
},
},
});
});
test("renders services from API", () => {
render();
expect(screen.getByTestId("swiper")).toBeInTheDocument();
expect(screen.getAllByTestId("slide").length).toBe(3);
expect(screen.getByText("ماساژ")).toBeInTheDocument();
expect(screen.getByText("مانیکور")).toBeInTheDocument();
});
test("filters services when search input changes", () => {
render();
const input = screen.getByTestId("voice-input");
fireEvent.change(input, { target: { value: "اص" } });
expect(screen.getByText("اصلاح")).toBeInTheDocument();
expect(screen.queryByText("مانیکور")).toBeNull();
expect(screen.queryByText("ماساژ")).toBeNull();
});
beforeEach(() => {
localStorage.clear();
jest.spyOn(localStorage.__proto__, "setItem");
});
afterEach(() => {
jest.restoreAllMocks();
});
test("selecting a service updates localStorage and dispatches event", async () => {
const eventSpy = jest.fn();
window.addEventListener("serviceSelected", eventSpy);
render();
await act(async () => {
await new Promise((r) => setTimeout(r, 0));
});
eventSpy.mockClear();
const manicureItem = screen.getByText("مانیکور");
await act(async () => {
fireEvent.click(manicureItem);
});
expect(eventSpy).toHaveBeenCalled();
expect(localStorage.setItem).toHaveBeenCalledWith("serviceTitle", "مانیکور");
});
test("opens AddService modal when add button clicked", () => {
const dispatchSpy = jest.fn();
render();
const addButton = screen.getByAltText("add service");
expect(addButton).toBeInTheDocument();
act(() => {
fireEvent.click(addButton);
});
expect(dispatchSpy).toHaveBeenCalledWith("OPEN");
expect(screen.getByTestId("add-service")).toBeInTheDocument();
});
});