Files
clinicpro/assets/admin/lib/utils.test.ts
T
hamed 42d9ad26c5 Add tests and implementation for ServiceDetailPage and PriceInput components
- Implement PriceInput component tests to validate Persian and Arabic numeral handling, input formatting, and controlled behavior.
- Create ServiceDetailPage component with detailed service information, including pricing, insurance coverage, and editing capabilities.
- Add API tests for service item detail retrieval and coverage synchronization with insurance contracts.
- Ensure proper error handling and user feedback for service item retrieval and coverage management.
2026-07-18 12:10:49 +03:30

287 lines
10 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 } from 'vitest';
import { z } from 'zod';
import {
digitsOnly,
formatYear,
parseUserNumber,
parseUserNumberClamped,
persianSafeNumber,
iranNationalCodeSchema,
iranNationalCodeOptionalSchema,
formatRial,
rialToToman,
tomanToRial,
formatNumber,
toDate,
formatDate,
formatDateTime,
toGregorianDate,
maskMobile,
cn,
toEnglishDigits,
sanitizeMobileInput,
isValidIranMobile,
IRAN_MOBILE_RE,
iranMobileSchema,
iranMobileOptionalSchema,
} from '@/lib/utils';
const PERSIAN_DIGITS = /[۰-۹]/;
describe('formatRial', () => {
it('مقدار ریال را ÷۱۰ به تومان تبدیل و با پسوند تومان برمی‌گرداند', () => {
const out = formatRial(150000); // ۱۵۰٬۰۰۰ ریال = ۱۵٬۰۰۰ تومان
expect(out).toContain('تومان');
expect(out).toMatch(PERSIAN_DIGITS);
expect(out).toContain(new Intl.NumberFormat('fa-IR').format(15000));
});
it('صفر را هم فرمت می‌کند', () => {
expect(formatRial(0)).toContain('تومان');
});
});
describe('rialToToman / tomanToRial', () => {
it('ریال↔تومان با ضریب ۱۰', () => {
expect(rialToToman(150000)).toBe(15000);
expect(tomanToRial(15000)).toBe(150000);
expect(tomanToRial(rialToToman(500))).toBe(500);
});
});
describe('formatNumber', () => {
it('رقم فارسی برمی‌گرداند', () => {
expect(formatNumber(1234)).toMatch(PERSIAN_DIGITS);
});
});
describe('toDate', () => {
it('null و رشته خالی → null', () => {
expect(toDate(null)).toBeNull();
expect(toDate(undefined)).toBeNull();
expect(toDate('')).toBeNull();
});
it('عدد را به‌عنوان ثانیه (×۱۰۰۰) تفسیر می‌کند', () => {
const d = toDate(1_700_000_000);
expect(d).toBeInstanceOf(Date);
expect(d!.getTime()).toBe(1_700_000_000 * 1000);
});
it('Y-m-d را ظهر محلی می‌گیرد (نه نیمه‌شب UTC)', () => {
const d = toDate('2024-03-21');
expect(d!.getHours()).toBe(12);
expect(d!.getFullYear()).toBe(2024);
});
it('رشته ISO کامل را پارس می‌کند', () => {
const d = toDate('2024-03-21T08:30:00Z');
expect(d).toBeInstanceOf(Date);
expect(isNaN(d!.getTime())).toBe(false);
});
});
describe('formatDate', () => {
it('ورودی نامعتبر → "—"', () => {
expect(formatDate(null)).toBe('—');
expect(formatDate('not-a-date')).toBe('—');
});
it('timestamp ثانیه‌ای معتبر → رشته شمسی با رقم فارسی', () => {
const out = formatDate(1_700_000_000);
expect(out).not.toBe('—');
expect(out).toMatch(PERSIAN_DIGITS);
});
});
describe('formatDateTime', () => {
it('ورودی نامعتبر → "—"', () => {
expect(formatDateTime(undefined)).toBe('—');
});
it('معتبر → شامل ساعت و رقم فارسی', () => {
const out = formatDateTime(1_700_000_000);
expect(out).not.toBe('—');
expect(out).toMatch(PERSIAN_DIGITS);
});
});
describe('toGregorianDate', () => {
it('YYYY-MM-DD با صفر پیش‌رو', () => {
expect(toGregorianDate(new Date(2024, 0, 5))).toBe('2024-01-05');
expect(toGregorianDate(new Date(2024, 11, 31))).toBe('2024-12-31');
});
});
describe('maskMobile', () => {
it('شماره ۱۱ رقمی را ماسک می‌کند', () => {
expect(maskMobile('09123456789')).toBe('0912***789');
});
it('شماره کوتاه‌تر از ۷ رقم بدون تغییر', () => {
expect(maskMobile('123')).toBe('123');
});
});
describe('cn', () => {
it('مقادیر falsy را حذف و بقیه را با فاصله می‌چسباند', () => {
expect(cn('a', false, null, undefined, 'b')).toBe('a b');
expect(cn()).toBe('');
});
});
describe('toEnglishDigits', () => {
it('رقم فارسی به انگلیسی', () => {
expect(toEnglishDigits('۰۹۱۲۳۴۵۶۷۸۹')).toBe('09123456789');
});
it('رقم عربی به انگلیسی', () => {
expect(toEnglishDigits('٠٩١٢')).toBe('0912');
});
it('ورودی خالی → رشته خالی', () => {
expect(toEnglishDigits('')).toBe('');
});
it('کاراکترهای غیررقمی را دست‌نخورده نگه می‌دارد', () => {
expect(toEnglishDigits('شماره ۰۹')).toBe('شماره 09');
});
});
describe('digitsOnly', () => {
it('رقم فارسی و عربی مخلوط را نرمال و غیررقم را حذف می‌کند', () => {
expect(digitsOnly('۱۲٣٤-56 ب')).toBe('123456');
});
it('با maxLen برش می‌زند', () => {
expect(digitsOnly('۱۲۳۴۵۶۷۸۹۰۱۲', 10)).toBe('1234567890');
});
it('ورودی خالی → رشته خالی', () => {
expect(digitsOnly('')).toBe('');
});
it('فقط حروف → خالی', () => {
expect(digitsOnly('کد ملی')).toBe('');
});
});
describe('formatYear', () => {
it('سال شمسی را بدون جداکننده‌ی هزارگان می‌دهد', () => {
expect(formatYear(1404)).toBe('۱۴۰۴');
});
it('برخلاف formatNumber جداکننده نمی‌گذارد', () => {
expect(formatNumber(1404)).not.toBe(formatYear(1404));
});
});
describe('parseUserNumber', () => {
it('رقم فارسی را به عدد تبدیل می‌کند', () => {
expect(parseUserNumber('۲۵')).toBe(25);
});
it('رقم عربی را به عدد تبدیل می‌کند', () => {
expect(parseUserNumber('٢٥')).toBe(25);
});
it('جداکننده هزارگان و فاصله را نادیده می‌گیرد', () => {
expect(parseUserNumber('1,200')).toBe(1200);
expect(parseUserNumber('۸۵٬۰۰۰')).toBe(85000);
expect(parseUserNumber(' ۹۰ ')).toBe(90);
});
it('اعشار فارسی را می‌پذیرد', () => {
expect(parseUserNumber('۱۲.۵')).toBe(12.5);
});
it('عدد منفی را می‌پذیرد', () => {
expect(parseUserNumber('-۳')).toBe(-3);
});
it('عدد را دست‌نخورده رد می‌کند', () => {
expect(parseUserNumber(42)).toBe(42);
});
it('خالی و null → null', () => {
expect(parseUserNumber('')).toBeNull();
expect(parseUserNumber(null)).toBeNull();
expect(parseUserNumber(undefined)).toBeNull();
});
it('ورودی نامعتبر → null و هرگز NaN', () => {
expect(parseUserNumber('abc')).toBeNull();
expect(parseUserNumber('۱۲ب۳')).toBeNull();
expect(parseUserNumber('.')).toBeNull();
});
});
describe('parseUserNumberClamped', () => {
it('مقدار داخل بازه را دست‌نخورده برمی‌گرداند', () => {
expect(parseUserNumberClamped('۲۵', 0, 100)).toBe(25);
});
it('بیشتر از سقف را به سقف می‌برد', () => {
expect(parseUserNumberClamped('۱۵۰', 0, 100)).toBe(100);
});
it('کمتر از کف را به کف می‌برد', () => {
expect(parseUserNumberClamped('-۵', 0, 100)).toBe(0);
});
it('ورودی نامعتبر → null (نه کف)', () => {
expect(parseUserNumberClamped('abc', 0, 100)).toBeNull();
expect(parseUserNumberClamped('', 0, 100)).toBeNull();
});
});
describe('persianSafeNumber', () => {
it('رشته‌ی فارسی را قبل از عدد شدن نرمال می‌کند', () => {
const schema = persianSafeNumber(z.coerce.number());
expect(schema.parse('۱۲۳')).toBe(123);
});
it('عدد را دست‌نخورده رد می‌کند', () => {
const schema = persianSafeNumber(z.coerce.number());
expect(schema.parse(42)).toBe(42);
});
});
describe('iranNationalCodeSchema', () => {
it('کد ملی فارسی را می‌پذیرد و لاتین برمی‌گرداند', () => {
expect(iranNationalCodeSchema.parse('۰۰۱۲۳۴۵۶۷۸')).toBe('0012345678');
});
it('کمتر از ۱۰ رقم رد می‌شود', () => {
expect(() => iranNationalCodeSchema.parse('12345')).toThrow();
});
it('نسخه‌ی اختیاری خالی را می‌پذیرد', () => {
expect(iranNationalCodeOptionalSchema.parse('')).toBe('');
expect(() => iranNationalCodeOptionalSchema.parse('123')).toThrow();
});
});
describe('sanitizeMobileInput', () => {
it('غیررقم حذف، رقم فارسی نرمال، حداکثر ۱۱ رقم', () => {
expect(sanitizeMobileInput('۰۹۱۲-۳۴۵ ۶۷۸۹۰۱۲')).toBe('09123456789');
});
it('فقط حروف → خالی', () => {
expect(sanitizeMobileInput('abc')).toBe('');
});
});
describe('isValidIranMobile / IRAN_MOBILE_RE', () => {
it.each([
['09123456789', true],
['۰۹۱۲۳۴۵۶۷۸۹', true],
['9123456789', false],
['08123456789', false],
['0912345678', false],
['091234567890', false],
])('%s → %s', (input, expected) => {
expect(isValidIranMobile(input as string)).toBe(expected);
});
it('regex مستقیم روی ارقام انگلیسی', () => {
expect(IRAN_MOBILE_RE.test('09120000000')).toBe(true);
});
});
describe('iranMobileSchema', () => {
it('رقم فارسی را پذیرفته و نرمال می‌کند', () => {
expect(iranMobileSchema.parse('۰۹۱۲۳۴۵۶۷۸۹')).toBe('09123456789');
});
it('جداکننده‌ها را حذف می‌کند', () => {
expect(iranMobileSchema.parse('0912-345-6789')).toBe('09123456789');
});
it('شماره نامعتبر → ناموفق', () => {
const r = iranMobileSchema.safeParse('12345');
expect(r.success).toBe(false);
});
});
describe('iranMobileOptionalSchema', () => {
it('رشته خالی مجاز است', () => {
expect(iranMobileOptionalSchema.parse('')).toBe('');
});
it('شماره معتبر نرمال می‌شود', () => {
expect(iranMobileOptionalSchema.parse('۰۹۱۲۳۴۵۶۷۸۹')).toBe('09123456789');
});
it('شماره نیمه‌کاره → ناموفق', () => {
expect(iranMobileOptionalSchema.safeParse('0912').success).toBe(false);
});
});