import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { useUpdateUser } from '@/apps/new-ui/services/User';
import { useGetAllSpecialties } from '@/apps/new-ui/services/Specialty';
import toast from 'react-hot-toast';
import EditInformation from '@/apps/new-ui/pages/Profile/+components/EditInformation';
// Mock کردن ماژولها
jest.mock('@/apps/new-ui/services/User');
jest.mock('@/apps/new-ui/services/Specialty');
jest.mock('react-hot-toast');
jest.mock("react-dom", () => ({
...jest.requireActual("react-dom"),
createPortal: (node: any) => node,
}));
jest.mock("@/utils/axios-interceptor", () => ({
appointmentClient: {
get: jest.fn(),
post: jest.fn(),
put: jest.fn(),
delete: jest.fn(),
},
}));
jest.mock("../src/apps/new-ui/Utils/env.ts", () => ({
ENV: {
API_URL: "https://api.test",
},
}));
jest.mock('@/apps/new-ui/components/MobilePicker/MobileScrollDatePicker', () => ({
__esModule: true,
default: ({ value, onChange }: any) => (
onChange(e.target.value)}
data-testid="date-input"
/>
),
}));
jest.mock('@/apps/new-ui/components/Inputs/NumericInput', () => ({
__esModule: true,
default: ({ value, onChange, placeholder, className, ...props }: any) => (
onChange(e.target.value)}
placeholder={placeholder}
className={className}
data-testid="numeric-input"
{...props}
/>
),
}));
jest.mock('@/apps/new-ui/components/CustomeComponents/MapPicker', () => ({
__esModule: true,
default: ({ latitude, longitude, onChange }: any) => (
Lat: {latitude}, Lng: {longitude}
),
}));
// مسیرهای اصلاح شده
jest.mock('@/apps/new-ui/pages/Profile/+components/EditPhoto', () => ({
__esModule: true,
default: ({ onClose }: any) => (
),
}));
jest.mock('@/apps/new-ui/pages/Profile/+components/SelectSpecialization', () => ({
__esModule: true,
default: ({ selectedSpecialization, onSpecializationChange, specializations }: any) => (
),
}));
jest.mock('@/apps/new-ui/pages/Profile/+components/SelectProvinceCity', () => ({
__esModule: true,
default: ({ selectedProvince, selectedCity, onProvinceChange, onCityChange }: any) => (
onProvinceChange(e.target.value)}
placeholder="استان"
/>
onCityChange(e.target.value)}
placeholder="شهر"
/>
),
}));
// Mock createPortal
jest.mock('react-dom', () => ({
...jest.requireActual('react-dom'),
createPortal: (node: React.ReactNode) => node,
}));
describe('EditInformation', () => {
const mockOnClick = jest.fn();
const mockUpdateUser = jest.fn();
const mockUserInfo = {
name: 'علی رضایی',
phone_number: '09123456789',
profile_picture: 'profile.jpg',
city: 'تهران',
date_of_birth: '1990-01-01',
province: 'تهران',
specialty: 'قلب',
address: 'خیابان ولیعصر، پلاک ۱۲۳',
latitude: 35.6892,
longitude: 51.3890,
};
const mockSpecialties = {
specialties: [
{ id: 1, name: 'قلب' },
{ id: 2, name: 'مغز و اعصاب' },
{ id: 3, name: 'ارتوپدی' },
],
};
beforeEach(() => {
jest.clearAllMocks();
(useUpdateUser as jest.Mock).mockReturnValue({
mutate: mockUpdateUser,
isPending: false
});
(useGetAllSpecialties as jest.Mock).mockReturnValue({
data: mockSpecialties
});
(toast.error as jest.Mock).mockImplementation(() => {});
});
const renderComponent = (props = {}) => {
return render(
);
};
it('should render correctly with user info', () => {
renderComponent();
expect(screen.getByText('ویرایش اطلاعات')).toBeInTheDocument();
expect(screen.getByDisplayValue('علی رضایی')).toBeInTheDocument();
expect(screen.getByDisplayValue('09123456789')).toBeInTheDocument();
});
it('should render with default values when no userInfo provided', () => {
render();
const nameInput = screen.getByPlaceholderText('نام و نام خانوادگی');
expect(nameInput).toHaveValue('');
const phoneInput = screen.getByPlaceholderText('شماره موبایل');
expect(phoneInput).toHaveValue('');
});
it('should update name input value', async () => {
renderComponent();
const nameInput = screen.getByDisplayValue('علی رضایی');
fireEvent.change(nameInput, { target: { value: 'احمد محمدی' } });
expect(nameInput).toHaveValue('احمد محمدی');
});
it('should update phone number', async () => {
renderComponent();
const phoneInput = screen.getByDisplayValue('09123456789');
fireEvent.change(phoneInput, { target: { value: '09987654321' } });
expect(phoneInput).toHaveValue('09987654321');
});
it('should call updateUser with correct data on save', async () => {
mockUpdateUser.mockImplementation((_data: any, { onSuccess }: any) => {
onSuccess();
});
renderComponent();
const saveButton = screen.getByText('ذخیره');
fireEvent.click(saveButton);
await waitFor(() => {
expect(mockUpdateUser).toHaveBeenCalledWith(
expect.objectContaining({
name: 'علی رضایی',
phone_number: '09123456789',
specialty: 'قلب',
province: 'تهران',
city: 'تهران',
}),
expect.any(Object)
);
});
});
it('should show error toast on update failure', async () => {
mockUpdateUser.mockImplementation((_data: any, { onError }: any) => {
onError(new Error('Update failed'));
});
renderComponent();
const saveButton = screen.getByText('ذخیره');
fireEvent.click(saveButton);
await waitFor(() => {
expect(toast.error).toHaveBeenCalledWith('خطا در به روز رسانی اطلاعات');
});
});
it('should call onclick after successful save', async () => {
mockUpdateUser.mockImplementation((_data: any, { onSuccess }: any) => {
onSuccess();
});
renderComponent();
const saveButton = screen.getByText('ذخیره');
fireEvent.click(saveButton);
await waitFor(() => {
expect(mockOnClick).toHaveBeenCalled();
});
});
it('should open and close edit photo modal', async () => {
renderComponent();
const profilePhoto = screen.getByAltText('profile');
fireEvent.click(profilePhoto);
expect(screen.getByTestId('edit-photo-modal')).toBeInTheDocument();
const closeButton = screen.getByTestId('close-photo-modal');
fireEvent.click(closeButton);
await waitFor(() => {
expect(screen.queryByTestId('edit-photo-modal')).not.toBeInTheDocument();
});
});
it('should show hover effect on profile photo', async () => {
renderComponent();
const profileDiv = screen.getByAltText('profile').parentElement!;
fireEvent.mouseEnter(profileDiv);
expect(screen.getByAltText('editIcon')).toBeInTheDocument();
fireEvent.mouseLeave(profileDiv);
await waitFor(() => {
expect(screen.queryByAltText('editIcon')).not.toBeInTheDocument();
});
});
it('should disable save button while updating', async () => {
(useUpdateUser as jest.Mock).mockReturnValue({
mutate: mockUpdateUser,
isPending: true
});
renderComponent();
const saveButton = screen.getByText('در حال ذخیره...');
expect(saveButton).toBeDisabled();
});
it('should call onCancel when cancel button is clicked', () => {
renderComponent();
const cancelButton = screen.getByText('انصراف');
fireEvent.click(cancelButton);
expect(mockOnClick).toHaveBeenCalled();
});
it('should enforce maxLength on name input', () => {
renderComponent();
const nameInput = screen.getByDisplayValue('علی رضایی');
expect(nameInput).toHaveAttribute('maxLength', '30');
});
});