feat: implement OTP login flow and enhance role-based access control
- Added OTP login functionality in driver.mjs to handle user authentication with a fixed code in dev environment. - Enhanced RoleRoute component in App.tsx to support clinic-scoped doctor roles and permissions. - Updated ClinicDoctorsManager component to include pagination and search functionality for better user experience. - Refactored tests for ClinicDoctorsManager to cover new features and ensure proper API mocking. - Adjusted permissions in settingsMenu.ts and PracticeDomainSettingsPage.tsx to align with updated backend requirements. - Created RoleRoute.test.tsx to validate role-based access logic for different user scenarios.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { screen } from '@testing-library/react';
|
||||
import { Routes, Route } from 'react-router';
|
||||
import { renderWithProviders } from './test/utils';
|
||||
import { useAuthStore } from './stores/authStore';
|
||||
import { RoleRoute } from './App';
|
||||
|
||||
/**
|
||||
* گِیتِ نقشیِ صفحات پنل — با تمرکز روی پزشکِ عضو در محیط کلینیک.
|
||||
*
|
||||
* پیش از این `settingsMenu` و `RoleRoute` دو قاعدهٔ متفاوت داشتند: منو واریانتِ
|
||||
* `clinic` را به پزشکِ scope=clinic نشان میداد و route با `primaryRole === 'doctor'`
|
||||
* ردش میکرد. نتیجه یک آیتم منوی مرده بود که به داشبورد میپرید.
|
||||
*/
|
||||
function renderGate(node: React.ReactNode) {
|
||||
return renderWithProviders(
|
||||
<Routes>
|
||||
<Route path="/admin/dashboard" element={<div>داشبورد</div>} />
|
||||
<Route path="/admin/page" element={node} />
|
||||
</Routes>,
|
||||
{ route: '/admin/page' },
|
||||
);
|
||||
}
|
||||
|
||||
function setUser(opts: {
|
||||
role: string;
|
||||
scope?: string | null;
|
||||
permissions?: Record<string, Record<string, boolean>>;
|
||||
}) {
|
||||
useAuthStore.setState({
|
||||
primaryRole: opts.role,
|
||||
context: {
|
||||
type: opts.scope === 'clinic' ? 'clinic' : 'doctor',
|
||||
db_uuid: 'x',
|
||||
name: 'محیط',
|
||||
scope: opts.scope ?? null,
|
||||
permissions: opts.permissions ? { resources: opts.permissions } : null,
|
||||
},
|
||||
} as any);
|
||||
}
|
||||
|
||||
describe('RoleRoute', () => {
|
||||
beforeEach(() => useAuthStore.setState({ primaryRole: null, context: null } as any));
|
||||
|
||||
it('نقشِ مجاز عبور میکند', () => {
|
||||
setUser({ role: 'clinic' });
|
||||
renderGate(<RoleRoute roles={['clinic']}><div>محتوا</div></RoleRoute>);
|
||||
|
||||
expect(screen.getByText('محتوا')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('نقشِ غیرمجاز به داشبورد میرود', () => {
|
||||
setUser({ role: 'doctor' });
|
||||
renderGate(<RoleRoute roles={['clinic']}><div>محتوا</div></RoleRoute>);
|
||||
|
||||
expect(screen.getByText('داشبورد')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('پزشکِ عضو با مجوزِ همان صفحه، به واریانتِ clinic راه دارد', () => {
|
||||
setUser({ role: 'doctor', scope: 'clinic', permissions: { clinic_info: { view: true } } });
|
||||
renderGate(
|
||||
<RoleRoute roles={['clinic']} permission={['clinic_info', 'view']}><div>محتوا</div></RoleRoute>,
|
||||
);
|
||||
|
||||
expect(screen.getByText('محتوا')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('پزشکِ عضو بدون آن مجوز، راه ندارد', () => {
|
||||
setUser({ role: 'doctor', scope: 'clinic', permissions: { clinic_info: { view: false } } });
|
||||
renderGate(
|
||||
<RoleRoute roles={['clinic']} permission={['clinic_info', 'view']}><div>محتوا</div></RoleRoute>,
|
||||
);
|
||||
|
||||
expect(screen.getByText('داشبورد')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('صفحهٔ بدون اعلامِ مجوز برای پزشکِ عضو باز نمیشود', () => {
|
||||
// وگرنه هر صفحهٔ مخصوصِ مالک برای هر پزشکِ عضو باز میشد.
|
||||
setUser({ role: 'doctor', scope: 'clinic', permissions: { clinic_info: { view: true } } });
|
||||
renderGate(<RoleRoute roles={['clinic']}><div>محتوا</div></RoleRoute>);
|
||||
|
||||
expect(screen.getByText('داشبورد')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('پزشکِ مطب شخصی از واریانتِ clinic رد میشود، حتی با مجوزِ باز', () => {
|
||||
// محیط شخصی permissions ندارد و `can` آزاد برمیگردد؛ scope باید جلویش را بگیرد.
|
||||
setUser({ role: 'doctor', scope: null });
|
||||
renderGate(
|
||||
<RoleRoute roles={['clinic']} permission={['clinic_info', 'view']}><div>محتوا</div></RoleRoute>,
|
||||
);
|
||||
|
||||
expect(screen.getByText('داشبورد')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user