import { describe, it, expect, beforeEach, vi } from 'vitest'; import { mount, flushPromises } from '@vue/test-utils'; import { createVuetify } from 'vuetify'; import { createRouter, createMemoryHistory } from 'vue-router'; vi.mock('../../resources/js/api/admin', () => ({ impersonationActive: vi.fn(), impersonationRecent: vi.fn(), impersonationEnd: vi.fn(), })); vi.mock('../../resources/js/api/client', () => ({ extractErrorMessage: vi.fn((_e, fb?: string) => fb ?? 'err'), apiClient: {}, ensureCsrfCookie: vi.fn(), })); import * as adminApi from '../../resources/js/api/admin'; import AdminImpersonationView from '../../resources/js/views/admin/AdminImpersonationView.vue'; const mountView = async () => { const router = createRouter({ history: createMemoryHistory(), routes: [{ path: '/admin/impersonation', component: AdminImpersonationView }], }); await router.push('/admin/impersonation'); await router.isReady(); const wrapper = mount(AdminImpersonationView, { global: { plugins: [createVuetify(), router] }, }); await flushPromises(); return wrapper; }; describe('AdminImpersonationView.vue', () => { beforeEach(() => { vi.clearAllMocks(); vi.mocked(adminApi.impersonationActive).mockResolvedValue([]); vi.mocked(adminApi.impersonationRecent).mockResolvedValue([]); }); it('загружает active + recent на mount', async () => { await mountView(); expect(adminApi.impersonationActive).toHaveBeenCalledTimes(1); expect(adminApi.impersonationRecent).toHaveBeenCalledTimes(1); }); it('показывает empty-state когда обе secции пустые', async () => { const wrapper = await mountView(); expect(wrapper.find('[data-testid="active-empty"]').exists()).toBe(true); expect(wrapper.find('[data-testid="recent-empty"]').exists()).toBe(true); }); it('рендерит active-row для каждой активной сессии', async () => { vi.mocked(adminApi.impersonationActive).mockResolvedValue([ { token_id: 42, tenant_id: 1, tenant_name: 'Окна Москва ООО', requested_by: 1, reason: 'Тикет SUP-12345 — клиент сообщил…', sent_to_email: 'admin@okna.ru', used_at: '2026-05-09T11:00:00', expires_at: '2026-05-09T11:15:00', }, ]); const wrapper = await mountView(); const rows = wrapper.findAll('[data-testid="active-row"]'); expect(rows).toHaveLength(1); expect(rows[0].text()).toContain('Окна Москва ООО'); expect(rows[0].text()).toContain('Тикет SUP-12345'); expect(wrapper.find('[data-testid="end-btn-42"]').exists()).toBe(true); }); it('click на «Завершить» вызывает API + перезагружает оба списка', async () => { vi.mocked(adminApi.impersonationActive).mockResolvedValue([ { token_id: 42, tenant_id: 1, tenant_name: 'Окна Москва ООО', requested_by: 1, reason: 'reason ' + 'x'.repeat(30), sent_to_email: 'a@b.ru', used_at: '2026-05-09T11:00:00', expires_at: '2026-05-09T11:15:00', }, ]); vi.mocked(adminApi.impersonationEnd).mockResolvedValue({ token_id: 42, session_ended_at: '2026-05-09T11:30:00', message: 'OK', }); const wrapper = await mountView(); // Сбрасываем счётчики после initial mount-loadOnMount vi.mocked(adminApi.impersonationActive).mockClear(); vi.mocked(adminApi.impersonationRecent).mockClear(); await wrapper.find('[data-testid="end-btn-42"]').trigger('click'); await flushPromises(); expect(adminApi.impersonationEnd).toHaveBeenCalledWith(42); // Обе функции перезагружаются после end expect(adminApi.impersonationActive).toHaveBeenCalledTimes(1); expect(adminApi.impersonationRecent).toHaveBeenCalledTimes(1); }); it('показывает error-alert если loadActive падает', async () => { vi.mocked(adminApi.impersonationActive).mockRejectedValueOnce(new Error('Network down')); const wrapper = await mountView(); expect(wrapper.find('[data-testid="error-alert"]').exists()).toBe(true); }); it('рендерит recent-row с длительностью', async () => { vi.mocked(adminApi.impersonationRecent).mockResolvedValue([ { token_id: 100, tenant_id: 5, tenant_name: 'Двери Премиум', requested_by: 1, reason: 'historical reason ' + 'y'.repeat(30), used_at: '2026-05-08T10:00:00', session_ended_at: '2026-05-08T10:45:00', duration_seconds: 2700, }, ]); const wrapper = await mountView(); const rows = wrapper.findAll('[data-testid="recent-row"]'); expect(rows).toHaveLength(1); expect(rows[0].text()).toContain('Двери Премиум'); // 2700 сек = 45 мин 0 сек expect(rows[0].text()).toContain('45 мин'); }); });