Files
portal/app/tests/Frontend/AdminIncidentsView.spec.ts
T

115 lines
4.8 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, vi, beforeEach } from 'vitest';
import { mount, flushPromises } from '@vue/test-utils';
import { createVuetify } from 'vuetify';
import { createRouter, createMemoryHistory } from 'vue-router';
import AdminIncidentsView from '../../resources/js/views/admin/AdminIncidentsView.vue';
import { ADMIN_INCIDENTS } from '../../resources/js/composables/mockAdmin';
vi.mock('../../resources/js/api/admin', async (importOriginal) => {
const orig = await importOriginal<typeof import('../../resources/js/api/admin')>();
return {
...orig,
listAdminIncidents: vi.fn(),
};
});
const adminApi = await import('../../resources/js/api/admin');
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(adminApi.listAdminIncidents).mockResolvedValue({
incidents: ADMIN_INCIDENTS.map((r) => ({
id: r.id,
incident_id: r.incident_id,
type: r.category as string,
severity: r.severity,
summary: r.title,
started_at: r.detected_at,
detected_at: r.detected_at,
resolved_at: null,
status: (r.status === 'closed' ? 'resolved' : r.status) as 'open' | 'investigating' | 'resolved',
affected_tenants_count: r.affected_tenants,
affected_users_count: null,
rkn_notified: r.rkn_notified,
rkn_notified_at: null,
rkn_deadline_at: r.rkn_deadline_at,
})),
total: ADMIN_INCIDENTS.length,
limit: 100,
offset: 0,
summary: {
open: ADMIN_INCIDENTS.filter((r) => r.status === 'open').length,
investigating: ADMIN_INCIDENTS.filter((r) => r.status === 'investigating').length,
rkn_pending: ADMIN_INCIDENTS.filter(
(r) => ['pdn_breach', 'data_breach'].includes(r.category) && !r.rkn_notified,
).length,
total_unresolved: ADMIN_INCIDENTS.filter((r) => r.status !== 'resolved' && r.status !== 'closed').length,
},
});
});
const mountView = async () => {
const router = createRouter({
history: createMemoryHistory(),
routes: [
{ path: '/admin/incidents', name: 'admin-incidents', component: AdminIncidentsView },
{ path: '/admin/incidents/:id', name: 'admin-incident-detail', component: { template: '<div />' } },
],
});
await router.push('/admin/incidents');
await router.isReady();
const wrapper = mount(AdminIncidentsView, { global: { plugins: [createVuetify(), router] } });
await flushPromises();
return { wrapper, router };
};
describe('AdminIncidentsView.vue', () => {
it('монтируется и содержит заголовок «Инциденты»', async () => {
const { wrapper } = await mountView();
expect(wrapper.text()).toContain('Инциденты');
});
it('содержит 3 stats: Открыто / Расследуется / РКН-уведомлений', async () => {
const { wrapper } = await mountView();
const text = wrapper.text();
expect(text).toContain('Открыто');
expect(text).toContain('Расследуется');
expect(text).toContain('РКН-уведомлений');
});
it('содержит фильтр-toggle по статусам (5 значений)', async () => {
const { wrapper } = await mountView();
const text = wrapper.text();
expect(text).toContain('Все');
expect(text).toContain('Открыты');
expect(text).toContain('Решены');
expect(text).toContain('Закрыты');
});
it('показывает PDN-breach с РКН pending chip', async () => {
const { wrapper } = await mountView();
const text = wrapper.text();
expect(text).toContain('Утечка ПДн');
expect(text).toContain('РКН pending');
});
it('содержит incident_id в формате INC-YYYY-MMDD-NNNN', async () => {
const { wrapper } = await mountView();
const text = wrapper.text();
expect(text).toContain('INC-2026-0507-0034');
expect(text).toContain('INC-2026-0506-0028');
});
it('клик по строке инцидента вызывает router.push на admin-incident-detail', async () => {
const { wrapper, router } = await mountView();
const pushSpy = vi.spyOn(router, 'push');
// get first row — populated via API mock
const vm = wrapper.vm as unknown as { rowsState: Array<{ id: number }> };
const firstId = vm.rowsState[0].id;
const row = wrapper.find(`[data-testid="incident-row-${firstId}"]`);
expect(row.exists()).toBe(true);
await row.trigger('click');
expect(pushSpy).toHaveBeenCalledWith({ name: 'admin-incident-detail', params: { id: firstId } });
});
});