- Added SecretaryAccessChecker to manage resource access for secretaries. - Integrated permission checks for payments, inventory, and tags in relevant controllers. - Updated PaymentController and PaymentMethodController to enforce secretary permissions. - Enhanced TenantTagController to check permissions for tag management actions. - Introduced tests for secretary resource enforcement, ensuring proper access control. - Updated DoctorSecretary entity to include inventory and tags permissions. - Created a comprehensive audit document for secretary permissions coverage and enforcement. - Fixed potential crashes in SecretaryDashboard when rendering without doctor data.
85 lines
3.2 KiB
TypeScript
85 lines
3.2 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { screen } from '@testing-library/react';
|
|
import { renderWithProviders } from '../test/utils';
|
|
|
|
vi.mock('../lib/api', () => ({
|
|
api: { get: vi.fn(), post: vi.fn(), patch: vi.fn(), put: vi.fn(), delete: vi.fn() },
|
|
ApiError: class extends Error {},
|
|
}));
|
|
|
|
import { api } from '../lib/api';
|
|
import { useAuthStore } from '../stores/authStore';
|
|
import DashboardPage from './DashboardPage';
|
|
|
|
const get = api.get as ReturnType<typeof vi.fn>;
|
|
|
|
const perms = {
|
|
version: 1,
|
|
resources: { appointments: { view: true, create: true, cancel: false, update_status: true } },
|
|
};
|
|
|
|
/** منشیِ scope=clinic: پاسخ کلید `doctor` ندارد — نباید کرش کند. */
|
|
const clinicScope = {
|
|
success: true,
|
|
data: {
|
|
scope: 'clinic',
|
|
clinic: { uuid: 'clinic-1', name: 'کلینیک نمونه' },
|
|
permissions: perms,
|
|
stats: { today_appointments: 3, tomorrow_appointments: 5 },
|
|
today_appointments: [],
|
|
},
|
|
};
|
|
|
|
const doctorScope = {
|
|
success: true,
|
|
data: {
|
|
scope: 'doctor',
|
|
doctor: { uuid: 'doc-1', name: 'دکتر رضایی', degree: 'متخصص قلب' },
|
|
permissions: perms,
|
|
stats: { today_appointments: 1, tomorrow_appointments: 2 },
|
|
today_appointments: [],
|
|
},
|
|
};
|
|
|
|
describe('SecretaryDashboard', () => {
|
|
beforeEach(() => {
|
|
get.mockReset();
|
|
useAuthStore.setState({ primaryRole: 'secretary', dbUuid: 'clinic-1', context: null } as never);
|
|
});
|
|
|
|
it('منشیِ کلینیک را بدون کرش رندر میکند (پاسخ بدون فیلد doctor)', async () => {
|
|
get.mockImplementation((url: string) =>
|
|
url.includes('/dashboard/secretary') ? Promise.resolve(clinicScope) : Promise.resolve({ success: true, data: [] }),
|
|
);
|
|
|
|
renderWithProviders(<DashboardPage />, { route: '/admin/dashboard' });
|
|
|
|
expect(await screen.findByText('داشبورد منشی')).toBeInTheDocument();
|
|
expect(screen.getAllByText(/کلینیک نمونه/).length).toBeGreaterThan(0);
|
|
expect(screen.getAllByText('نوبتهای امروز').length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('منشیِ مطب پزشک را با نام پزشک رندر میکند', async () => {
|
|
get.mockImplementation((url: string) =>
|
|
url.includes('/dashboard/secretary') ? Promise.resolve(doctorScope) : Promise.resolve({ success: true, data: [] }),
|
|
);
|
|
|
|
renderWithProviders(<DashboardPage />, { route: '/admin/dashboard' });
|
|
|
|
expect(await screen.findByText('داشبورد منشی')).toBeInTheDocument();
|
|
expect(screen.getAllByText(/دکتر رضایی/).length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('پاسخ خالی/خطا را بدون کرش با پیام مناسب نشان میدهد', async () => {
|
|
get.mockImplementation((url: string) =>
|
|
url.includes('/dashboard/secretary')
|
|
? Promise.resolve({ success: false, data: null, errors: [{ code: 'X', message: 'x' }] })
|
|
: Promise.resolve({ success: true, data: [] }),
|
|
);
|
|
|
|
renderWithProviders(<DashboardPage />, { route: '/admin/dashboard' });
|
|
|
|
expect(await screen.findByText('در حال حاضر اطلاعات داشبورد در دسترس نیست.')).toBeInTheDocument();
|
|
});
|
|
});
|