feat: add comprehensive tests for UI components, hooks, and API interactions
- Implement tests for Pagination, StatusBadge, ConfirmDialog, and MobileInput components. - Add tests for useSubscription, usePaymentConfig, and usePwaInstall hooks. - Create tests for API requests in the api module, including success and error handling. - Add utility function tests for formatting and validating Iranian mobile numbers. - Implement tests for BlogFormPage and BlogsPage to validate form submissions and data fetching. - Add tests for LoginPage to ensure proper validation and state management. - Create tests for authStore and uiStore to validate state management and functionality. - Set up Vitest configuration and testing utilities for consistent testing environment.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { useAuthStore } from '@/stores/authStore';
|
||||
|
||||
const initial = useAuthStore.getInitialState();
|
||||
|
||||
function jsonRes(body: unknown, ok = true): Response {
|
||||
return { ok, json: () => Promise.resolve(body) } as unknown as Response;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
useAuthStore.setState(initial, true);
|
||||
vi.stubGlobal('fetch', vi.fn().mockResolvedValue(jsonRes({ success: false })));
|
||||
});
|
||||
|
||||
describe('login', () => {
|
||||
it('توکن را ست و isAuthenticated را true میکند', () => {
|
||||
useAuthStore.getState().login('tok', 'refresh');
|
||||
const s = useAuthStore.getState();
|
||||
expect(s.token).toBe('tok');
|
||||
expect(s.refreshToken).toBe('refresh');
|
||||
expect(s.isAuthenticated).toBe(true);
|
||||
});
|
||||
it('fetchMe (userinfo) را صدا میزند', () => {
|
||||
useAuthStore.getState().login('tok');
|
||||
expect(fetch).toHaveBeenCalledWith('/oauth/userinfo', expect.any(Object));
|
||||
});
|
||||
});
|
||||
|
||||
describe('logout', () => {
|
||||
it('state را پاک میکند و وقتی refreshToken هست به /oauth/logout POST میزند', () => {
|
||||
useAuthStore.setState({ token: 'tok', refreshToken: 'rt', isAuthenticated: true });
|
||||
useAuthStore.getState().logout();
|
||||
const s = useAuthStore.getState();
|
||||
expect(s.token).toBeNull();
|
||||
expect(s.isAuthenticated).toBe(false);
|
||||
expect(fetch).toHaveBeenCalledWith('/oauth/logout', expect.objectContaining({ method: 'POST' }));
|
||||
});
|
||||
});
|
||||
|
||||
describe('refresh', () => {
|
||||
it('بدون refreshToken → null و بدون fetch', async () => {
|
||||
const out = await useAuthStore.getState().refresh();
|
||||
expect(out).toBeNull();
|
||||
expect(fetch).not.toHaveBeenCalled();
|
||||
});
|
||||
it('پاسخ موفق → توکن جدید برمیگرداند و state را بهروز میکند', async () => {
|
||||
useAuthStore.setState({ refreshToken: 'rt' });
|
||||
(fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
|
||||
jsonRes({ access_token: 'new-tok', refresh_token: 'new-rt' }),
|
||||
);
|
||||
const out = await useAuthStore.getState().refresh();
|
||||
expect(out).toBe('new-tok');
|
||||
expect(useAuthStore.getState().token).toBe('new-tok');
|
||||
expect(useAuthStore.getState().refreshToken).toBe('new-rt');
|
||||
});
|
||||
it('پاسخ بدون access_token → null', async () => {
|
||||
useAuthStore.setState({ refreshToken: 'rt' });
|
||||
(fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(jsonRes({}, false));
|
||||
expect(await useAuthStore.getState().refresh()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('fetchMe', () => {
|
||||
it('userinfo موفق → فیلدهای کاربر را ست میکند', async () => {
|
||||
(fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
|
||||
jsonRes({
|
||||
success: true,
|
||||
data: {
|
||||
uuid: 'u1',
|
||||
realName: 'دکتر تست',
|
||||
primary_role: 'doctor',
|
||||
available_contexts: [{ type: 'doctor', db_uuid: 'd1', name: 'مطب', role: 'doctor' }],
|
||||
},
|
||||
}),
|
||||
);
|
||||
await useAuthStore.getState().fetchMe();
|
||||
const s = useAuthStore.getState();
|
||||
expect(s.userUuid).toBe('u1');
|
||||
expect(s.userName).toBe('دکتر تست');
|
||||
expect(s.primaryRole).toBe('doctor');
|
||||
expect(s.availableContexts).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('switchContext', () => {
|
||||
it('پاسخ موفق → db و context و primaryRole را ست میکند', async () => {
|
||||
(fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
|
||||
jsonRes({
|
||||
success: true,
|
||||
data: {
|
||||
db_uuid: 'db2',
|
||||
db_key: 'key2',
|
||||
context: { type: 'clinic', db_uuid: 'db2', name: 'کلینیک', role: 'clinic', doctor_uuid: 'doc9' },
|
||||
},
|
||||
}),
|
||||
);
|
||||
await useAuthStore.getState().switchContext('db2');
|
||||
const s = useAuthStore.getState();
|
||||
expect(s.dbUuid).toBe('db2');
|
||||
expect(s.dbKey).toBe('key2');
|
||||
expect(s.primaryRole).toBe('clinic');
|
||||
expect(s.doctorUuid).toBe('doc9');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { useUiStore, HUES } from '@/stores/uiStore';
|
||||
|
||||
const initial = useUiStore.getInitialState();
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
useUiStore.setState(initial, true);
|
||||
document.documentElement.className = '';
|
||||
document.documentElement.removeAttribute('data-theme');
|
||||
document.documentElement.removeAttribute('data-density');
|
||||
});
|
||||
|
||||
describe('sidebar', () => {
|
||||
it('toggleSidebar وضعیت را برعکس میکند', () => {
|
||||
expect(useUiStore.getState().sidebarOpen).toBe(true);
|
||||
useUiStore.getState().toggleSidebar();
|
||||
expect(useUiStore.getState().sidebarOpen).toBe(false);
|
||||
});
|
||||
it('setSidebarOpen مقدار صریح میگذارد', () => {
|
||||
useUiStore.getState().setSidebarOpen(false);
|
||||
expect(useUiStore.getState().sidebarOpen).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('darkMode + applyTheme', () => {
|
||||
it('toggleDarkMode کلاس dark و data-theme را روی root میگذارد', () => {
|
||||
useUiStore.getState().toggleDarkMode();
|
||||
expect(useUiStore.getState().darkMode).toBe(true);
|
||||
expect(document.documentElement.classList.contains('dark')).toBe(true);
|
||||
expect(document.documentElement.getAttribute('data-theme')).toBe('dark');
|
||||
});
|
||||
it('toggle دوباره به light برمیگرداند', () => {
|
||||
useUiStore.getState().toggleDarkMode();
|
||||
useUiStore.getState().toggleDarkMode();
|
||||
expect(useUiStore.getState().darkMode).toBe(false);
|
||||
expect(document.documentElement.classList.contains('dark')).toBe(false);
|
||||
expect(document.documentElement.getAttribute('data-theme')).toBe('light');
|
||||
});
|
||||
});
|
||||
|
||||
describe('density', () => {
|
||||
it('setDensity مقدار و data-density را تنظیم میکند', () => {
|
||||
useUiStore.getState().setDensity('compact');
|
||||
expect(useUiStore.getState().density).toBe('compact');
|
||||
expect(document.documentElement.getAttribute('data-density')).toBe('compact');
|
||||
});
|
||||
});
|
||||
|
||||
describe('brandHue', () => {
|
||||
it('setBrandHue متغیرهای CSS را روی root مینویسد', () => {
|
||||
const hue = HUES[2];
|
||||
useUiStore.getState().setBrandHue(hue);
|
||||
expect(useUiStore.getState().brandHue).toEqual(hue);
|
||||
expect(document.documentElement.style.getPropertyValue('--brand-h')).toBe(String(hue.h));
|
||||
expect(document.documentElement.style.getPropertyValue('--brand-c')).toBe(String(hue.c));
|
||||
});
|
||||
});
|
||||
|
||||
describe('settingsPanel', () => {
|
||||
it('toggleSettingsPanel وضعیت را برعکس میکند', () => {
|
||||
expect(useUiStore.getState().settingsPanelOpen).toBe(false);
|
||||
useUiStore.getState().toggleSettingsPanel();
|
||||
expect(useUiStore.getState().settingsPanelOpen).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user