Files
clinicpro/assets/admin/pages/AppointmentsPage.test.tsx
T
hamedandClaude Opus 4.8 f41852b168 feat(appointments): profile-aware doctor tabs + toolbar to match tauri turns
- Multi-doctor clinic profile (clinic/admin) shows the doctor tabs for
  multi-doctor management; clinic auto-selects the first doctor so the timeline
  loads immediately (as in the reference). Admin keeps the «همه» tab.
- Independent doctor profile (doctor role, incl. clinic-scoped guest) shows no
  tabs and only its own schedule — no clinic/doctor selection.
- Toolbar reordered to match the reference: date + service select
  («سرویس مورد نظر را انتخاب کنید...») + view toggle on the right; filter +
  «افزودن نوبت» on the left. The in-toolbar doctor picker is removed (doctor
  selection is via tabs); the personnel select is replaced by a service filter
  bound to the existing itemUuid filter (client-side, no new endpoint).

Tests: added clinic-profile tests (tabs shown, no «همه», first doctor
auto-selected) and independent-doctor test (no tabs, service filter shown).

No API endpoints changed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 16:07:04 +03:30

82 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 AppointmentsPage from './AppointmentsPage';
const get = api.get as ReturnType<typeof vi.fn>;
beforeEach(() => {
get.mockReset();
useAuthStore.setState({ primaryRole: 'doctor', dbUuid: 'doc1' } as any);
get.mockImplementation((url: string) => {
if (url.includes('today-stats')) return Promise.resolve({ success: true, data: { total: 7, completed: 3, waiting: 2, cancelled: 1 } });
if (url.includes('appointment-slots')) return Promise.resolve({ success: true, data: { sessions: [] } });
if (url.includes('/my/appointments')) return Promise.resolve({ success: true, data: [], meta: { totalRecords: 0, totalPages: 0, currentPage: 1 } });
return Promise.resolve({ success: true, data: [] });
});
});
describe('AppointmentsPage — طرح نوبت‌ها', () => {
it('renders the title, the stats bar and the افزودن نوبت action', async () => {
renderWithProviders(<AppointmentsPage />);
expect(screen.getByText('نوبت‌ ها')).toBeInTheDocument();
expect(screen.getByText('کل نوبت های امروز')).toBeInTheDocument();
expect(await screen.findByText('۷')).toBeInTheDocument(); // total from stats
expect(screen.getByText('افزودن نوبت')).toBeInTheDocument();
});
it('timeline view shows the holiday message when the doctor has no slots', async () => {
renderWithProviders(<AppointmentsPage />);
// نمای پیش‌فرض زمانبندی است و پزشک (نقش doctor) از قبل انتخاب شده
expect(await screen.findByText('این روز تعطیل است')).toBeInTheDocument();
});
it('independent doctor profile does NOT show doctor tabs', async () => {
renderWithProviders(<AppointmentsPage />);
await screen.findByText('این روز تعطیل است');
expect(screen.queryByText('همه')).toBeNull();
// برچسب فیلتر سرویس دیده می‌شود (مطابق طرح)
expect(screen.getByText('سرویس مورد نظر را انتخاب کنید...')).toBeInTheDocument();
});
});
describe('AppointmentsPage — پروفایل کلینیک چندپزشکه', () => {
beforeEach(() => {
get.mockReset();
useAuthStore.setState({ primaryRole: 'clinic', dbUuid: 'clinic1' } as any);
get.mockImplementation((url: string) => {
if (url.includes('today-stats')) return Promise.resolve({ success: true, data: { total: 5, completed: 1, waiting: 3, cancelled: 1 } });
if (url.includes('/clinic/doctor-list/')) return Promise.resolve({ success: true, data: { data: [
{ uuid: 'd1', name: 'دکتر محمدی' }, { uuid: 'd2', name: 'دکتر رضایی' },
] } });
if (url.includes('appointment-slots')) return Promise.resolve({ success: true, data: { sessions: [] } });
if (url.includes('/my/appointments')) return Promise.resolve({ success: true, data: [], meta: { totalRecords: 0, totalPages: 0, currentPage: 1 } });
return Promise.resolve({ success: true, data: [] });
});
});
it('shows the doctor tabs (multi-doctor management) without the «همه» tab', async () => {
renderWithProviders(<AppointmentsPage />);
expect(await screen.findByText('دکتر محمدی')).toBeInTheDocument();
expect(screen.getByText('دکتر رضایی')).toBeInTheDocument();
expect(screen.queryByText('همه')).toBeNull();
});
it('auto-selects the first doctor so the timeline loads its slots', async () => {
renderWithProviders(<AppointmentsPage />);
await screen.findByText('دکتر محمدی');
// اسلات‌ها برای اولین دکتر (d1) درخواست می‌شوند
await screen.findByText('این روز تعطیل است');
const calledSlotsForD1 = get.mock.calls.some((c: any[]) => typeof c[0] === 'string' && c[0].includes('appointment-slots') && c[0].includes('doctor_uuid=d1'));
expect(calledSlotsForD1).toBe(true);
});
});