- Implemented BlogBodySanitizer to clean HTML content before saving articles, ensuring security against XSS attacks. - Added tests for BlogBodySanitizer to verify that unsafe tags and attributes are stripped from the content. - Introduced ApiLeastPrivilegeTest to ensure that unauthorized users cannot access sensitive API routes, maintaining strict access control.
125 lines
4.9 KiB
TypeScript
125 lines
4.9 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { screen, fireEvent } from '@testing-library/react';
|
|
import { renderWithProviders } from '../../test/utils';
|
|
|
|
const navigateMock = vi.fn();
|
|
vi.mock('react-router', async () => {
|
|
const actual = await vi.importActual<typeof import('react-router')>('react-router');
|
|
return { ...actual, useNavigate: () => navigateMock };
|
|
});
|
|
|
|
import ProfileMenu, { settingsPath } from './ProfileMenu';
|
|
import { useAuthStore } from '../../stores/authStore';
|
|
import { useUiStore } from '../../stores/uiStore';
|
|
|
|
const logoutMock = vi.fn();
|
|
const togglePanelMock = vi.fn();
|
|
|
|
function setAuth(partial: Record<string, unknown>) {
|
|
useAuthStore.setState({
|
|
userName: 'دکتر رضایی',
|
|
primaryRole: 'doctor',
|
|
context: { name: 'کلینیک نور' },
|
|
logout: logoutMock,
|
|
...partial,
|
|
} as any);
|
|
}
|
|
|
|
beforeEach(() => {
|
|
navigateMock.mockClear();
|
|
logoutMock.mockClear();
|
|
togglePanelMock.mockClear();
|
|
useUiStore.setState({ toggleSettingsPanel: togglePanelMock } as any);
|
|
setAuth({});
|
|
});
|
|
|
|
describe('ProfileMenu — نمایش نام و تخصص', () => {
|
|
it('نام کاربر و نام محیط کاری (context) را نشان میدهد', () => {
|
|
renderWithProviders(<ProfileMenu />);
|
|
expect(screen.getByText('دکتر رضایی')).toBeInTheDocument();
|
|
expect(screen.getByText('کلینیک نور')).toBeInTheDocument();
|
|
});
|
|
|
|
it('وقتی context نیست، برچسب نقش را جایگزین میکند', () => {
|
|
setAuth({ context: null });
|
|
renderWithProviders(<ProfileMenu />);
|
|
expect(screen.getByText('پزشک')).toBeInTheDocument();
|
|
});
|
|
|
|
it('حالت خالی: نام پیشفرض «کاربر» و حرف اول «ک»', () => {
|
|
setAuth({ userName: null, context: null, primaryRole: null });
|
|
renderWithProviders(<ProfileMenu />);
|
|
expect(screen.getByText('کاربر')).toBeInTheDocument();
|
|
// حرف اولِ آواتار
|
|
expect(screen.getByTitle('کاربر').textContent).toContain('ک');
|
|
});
|
|
});
|
|
|
|
describe('ProfileMenu — باز/بستن و آیتمها', () => {
|
|
it('منو ابتدا بسته است و با کلیک باز میشود', () => {
|
|
renderWithProviders(<ProfileMenu />);
|
|
expect(screen.queryByText('خروج')).toBeNull();
|
|
|
|
fireEvent.click(screen.getByTitle('دکتر رضایی'));
|
|
|
|
['پروفایل من', 'پرداختها', 'تنظیمات', 'شخصیسازی', 'خروج'].forEach((label) => {
|
|
expect(screen.getByText(label)).toBeInTheDocument();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('ProfileMenu — لینکهای نقشمحور', () => {
|
|
it('پزشک: پروفایل → /admin/profile، پرداختها → /admin/my-payments', () => {
|
|
setAuth({ primaryRole: 'doctor' });
|
|
renderWithProviders(<ProfileMenu />);
|
|
fireEvent.click(screen.getByTitle('دکتر رضایی'));
|
|
|
|
fireEvent.click(screen.getByText('پرداختها'));
|
|
expect(navigateMock).toHaveBeenCalledWith('/admin/my-payments');
|
|
|
|
fireEvent.click(screen.getByTitle('دکتر رضایی'));
|
|
fireEvent.click(screen.getByText('پروفایل من'));
|
|
expect(navigateMock).toHaveBeenCalledWith('/admin/profile');
|
|
});
|
|
|
|
it('مدیر: پرداختها → /admin/payments، تنظیمات → /admin/settings', () => {
|
|
setAuth({ primaryRole: 'admin', userName: 'ادمین' });
|
|
renderWithProviders(<ProfileMenu />);
|
|
fireEvent.click(screen.getByTitle('ادمین'));
|
|
|
|
fireEvent.click(screen.getByText('پرداختها'));
|
|
expect(navigateMock).toHaveBeenCalledWith('/admin/payments');
|
|
|
|
fireEvent.click(screen.getByTitle('ادمین'));
|
|
fireEvent.click(screen.getByText('تنظیمات'));
|
|
expect(navigateMock).toHaveBeenCalledWith('/admin/settings');
|
|
});
|
|
});
|
|
|
|
describe('ProfileMenu — اکشنها', () => {
|
|
it('شخصیسازی پنل تنظیمات را باز میکند', () => {
|
|
renderWithProviders(<ProfileMenu />);
|
|
fireEvent.click(screen.getByTitle('دکتر رضایی'));
|
|
fireEvent.click(screen.getByText('شخصیسازی'));
|
|
expect(togglePanelMock).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('خروج، logout را صدا میزند و به صفحه ورود میرود', () => {
|
|
renderWithProviders(<ProfileMenu />);
|
|
fireEvent.click(screen.getByTitle('دکتر رضایی'));
|
|
fireEvent.click(screen.getByText('خروج'));
|
|
expect(logoutMock).toHaveBeenCalledTimes(1);
|
|
expect(navigateMock).toHaveBeenCalledWith('/admin/login');
|
|
});
|
|
});
|
|
|
|
describe('settingsPath — نگاشت نقش', () => {
|
|
it('نقشها را به مسیر درست نگاشت میکند', () => {
|
|
expect(settingsPath('admin')).toBe('/admin/settings');
|
|
expect(settingsPath('doctor')).toBe('/admin/settings-menu');
|
|
expect(settingsPath('clinic')).toBe('/admin/settings-menu');
|
|
expect(settingsPath('secretary')).toBe('/admin/account-settings');
|
|
expect(settingsPath(null)).toBe('/admin/account-settings');
|
|
});
|
|
});
|