// @vitest-environment nuxt import { describe, it, expect, beforeEach, vi } from 'vitest'; import { useClientCountry } from '../use-client-country'; const getCountries = vi.fn(); vi.mock('../../services/api/dictionaries.service', () => ({ DictionariesApiService: { getCountries: () => getCountries() }, })); const setCode = (code: string) => useState('clientCountryCode', () => '').value = code; const setResolvedName = (name: string) => useState('clientCountryName', () => '').value = name; describe('useClientCountry', () => { beforeEach(() => { useNuxtApp().payload.state = {}; getCountries.mockReset(); }); it('без кода не отдаёт ни флаг, ни имя', () => { const { icon, name, flagSrc } = useClientCountry(); expect(icon.value).toBe(''); expect(name.value).toBe(''); expect(flagSrc.value).toBe(''); }); it('строит иконку и путь к флагу из кода', () => { setCode('ad'); setResolvedName('Andorra'); const { icon, flagSrc } = useClientCountry(); expect(icon.value).toBe('ad'); expect(flagSrc.value).toBe('/icons/flags/ad.svg'); }); it('нормализует код: регистр и пробелы', () => { setCode(' AD '); setResolvedName('Andorra'); const { icon, flagSrc } = useClientCountry(); expect(icon.value).toBe('ad'); expect(flagSrc.value).toBe('/icons/flags/ad.svg'); }); it('учитывает страны, где код флага отличается от ISO-кода', () => { setCode('cn'); setResolvedName('China'); const { icon, flagSrc } = useClientCountry(); expect(icon.value).toBe('zh'); expect(flagSrc.value).toBe('/icons/flags/zh.svg'); }); it('не показывает флаг для служебного кода, которого нет в словаре', () => { // Cloudflare отдаёт XX для неизвестного IP и T1 для Tor — файла такого флага нет setCode('xx'); const { icon, name, flagSrc } = useClientCountry(); expect(icon.value).toBe('xx'); expect(name.value).toBe(''); expect(flagSrc.value).toBe(''); }); it('имя следует за кодом и не может остаться от другой страны', async () => { setCode('ad'); // имя, доставшееся от предыдущей страны — именно этот рассинхрон ловим setResolvedName('USA'); getCountries.mockResolvedValue({ countries: [ { title: 'Andorra', isoCodes: ['AD', 'AND'] }, { title: 'USA', isoCodes: ['US', 'USA'] }, ], }); const { name, flagSrc, loadCountries } = useClientCountry(); await loadCountries(); expect(name.value).toBe('Andorra'); expect(flagSrc.value).toBe('/icons/flags/ad.svg'); }); it('до загрузки списка берёт имя, отрезолвленное на сервере', () => { setCode('ad'); setResolvedName('Andorra'); const { name } = useClientCountry(); expect(name.value).toBe('Andorra'); }); it('выбор страны меняет и код, и имя', () => { setCode('ad'); setResolvedName('Andorra'); const { code, name, flagSrc, setCountry } = useClientCountry(); setCountry({ title: 'USA', value: 'USA', icon: 'us', key: 'us' }); expect(code.value).toBe('us'); expect(name.value).toBe('USA'); expect(flagSrc.value).toBe('/icons/flags/us.svg'); }); it('не перезапрашивает список, если он уже загружен', async () => { getCountries.mockResolvedValue({ countries: [{ title: 'Andorra', isoCodes: ['AD'] }] }); const { loadCountries } = useClientCountry(); await loadCountries(); await loadCountries(); expect(getCountries).toHaveBeenCalledTimes(1); }); it('падение запроса оставляет список пустым — следующее открытие попробует снова', async () => { getCountries.mockRejectedValue(new Error('500')); const { countriesItems, loadCountries } = useClientCountry(); await loadCountries(); expect(countriesItems.value).toEqual([]); }); });