import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { mount, flushPromises } from '@vue/test-utils'; import { createVuetify } from 'vuetify'; import ImpersonationBanner from '../../resources/js/components/admin/ImpersonationBanner.vue'; import type { ImpersonationActiveSession } from '../../resources/js/api/admin'; vi.mock('../../resources/js/api/admin', async (importOriginal) => { const orig = await importOriginal(); return { ...orig, impersonationActive: vi.fn() }; }); const adminApi = await import('../../resources/js/api/admin'); function makeSession(overrides: Partial = {}): ImpersonationActiveSession { return { token_id: 1, tenant_id: 10, tenant_name: 'ООО Ромашка', requested_by: 7, reason: 'Диагностика проблемы с балансом по обращению клиента', sent_to_email: 'client@romashka.ru', used_at: '2026-05-16T08:00:00Z', expires_at: '2026-05-16T08:15:00Z', ...overrides, }; } const mountBanner = () => mount(ImpersonationBanner, { global: { plugins: [createVuetify()], stubs: { RouterLink: { props: ['to'], inheritAttrs: false, template: '', }, }, }, }); beforeEach(() => vi.clearAllMocks()); afterEach(() => vi.useRealTimers()); describe('ImpersonationBanner', () => { it('вызывает impersonationActive на mount', async () => { vi.mocked(adminApi.impersonationActive).mockResolvedValueOnce([]); const wrapper = mountBanner(); await flushPromises(); expect(adminApi.impersonationActive).toHaveBeenCalledTimes(1); wrapper.unmount(); }); it('0 активных сессий — баннер не рендерится', async () => { vi.mocked(adminApi.impersonationActive).mockResolvedValueOnce([]); const wrapper = mountBanner(); await flushPromises(); expect(wrapper.find('[data-testid="impersonation-banner"]').exists()).toBe(false); wrapper.unmount(); }); it('1 активная сессия — баннер с именем тенанта + ссылка на /admin/impersonation', async () => { vi.mocked(adminApi.impersonationActive).mockResolvedValueOnce([makeSession({ tenant_name: 'ООО Ромашка' })]); const wrapper = mountBanner(); await flushPromises(); const banner = wrapper.find('[data-testid="impersonation-banner"]'); expect(banner.exists()).toBe(true); expect(banner.text()).toContain('Активна impersonation-сессия'); expect(banner.text()).toContain('ООО Ромашка'); expect(wrapper.find('[data-testid="impersonation-banner-link"]').attributes('href')).toBe( '/admin/impersonation', ); wrapper.unmount(); }); it('несколько активных сессий — баннер показывает счётчик', async () => { vi.mocked(adminApi.impersonationActive).mockResolvedValueOnce([ makeSession({ token_id: 1 }), makeSession({ token_id: 2 }), makeSession({ token_id: 3 }), ]); const wrapper = mountBanner(); await flushPromises(); expect(wrapper.find('[data-testid="impersonation-banner"]').text()).toContain( 'Активны impersonation-сессии: 3', ); wrapper.unmount(); }); it('tenant_name=null — fallback на «тенант #id»', async () => { vi.mocked(adminApi.impersonationActive).mockResolvedValueOnce([ makeSession({ tenant_name: null, tenant_id: 42 }), ]); const wrapper = mountBanner(); await flushPromises(); expect(wrapper.find('[data-testid="impersonation-banner"]').text()).toContain('тенант #42'); wrapper.unmount(); }); it('ошибка impersonationActive — баннер не падает и остаётся скрыт', async () => { vi.mocked(adminApi.impersonationActive).mockRejectedValueOnce(new Error('500')); const wrapper = mountBanner(); await flushPromises(); expect(wrapper.find('[data-testid="impersonation-banner"]').exists()).toBe(false); wrapper.unmount(); }); it('polling — impersonationActive вызывается повторно через 30 с', async () => { vi.useFakeTimers(); vi.mocked(adminApi.impersonationActive).mockResolvedValue([]); const wrapper = mountBanner(); await vi.advanceTimersByTimeAsync(0); expect(adminApi.impersonationActive).toHaveBeenCalledTimes(1); await vi.advanceTimersByTimeAsync(30_000); expect(adminApi.impersonationActive).toHaveBeenCalledTimes(2); wrapper.unmount(); }); it('polling — данные второго опроса обновляют баннер', async () => { vi.useFakeTimers(); vi.mocked(adminApi.impersonationActive) .mockResolvedValueOnce([]) .mockResolvedValue([makeSession({ tenant_name: 'ООО Ромашка' })]); const wrapper = mountBanner(); await vi.advanceTimersByTimeAsync(0); expect(wrapper.find('[data-testid="impersonation-banner"]').exists()).toBe(false); await vi.advanceTimersByTimeAsync(30_000); await wrapper.vm.$nextTick(); const banner = wrapper.find('[data-testid="impersonation-banner"]'); expect(banner.exists()).toBe(true); expect(banner.text()).toContain('ООО Ромашка'); wrapper.unmount(); }); });