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

103 lines
4.7 KiB
TypeScript
Raw Normal View History

import { describe, it, expect } from 'vitest';
import { mount } from '@vue/test-utils';
import { createVuetify } from 'vuetify';
import { createRouter, createMemoryHistory } from 'vue-router';
import ErrorView from '../../resources/js/views/errors/ErrorView.vue';
// ErrorView читает route.meta.errorCode для конфигурации экрана.
const mountErrorView = async (errorCode: '404' | '403' | '500') => {
const router = createRouter({
history: createMemoryHistory(),
routes: [
{ path: '/error', component: ErrorView, meta: { errorCode } },
{ path: '/dashboard', component: { template: '<div>dashboard stub</div>' } },
],
});
await router.push('/error');
await router.isReady();
return mount(ErrorView, {
global: {
plugins: [createVuetify(), router],
// ErrorView содержит v-app + v-main — те же layout-проблемы что у DealDetailDrawer.
// Stub'им VApp/VMain как passthrough.
stubs: {
VApp: { template: '<div class="v-app-stub"><slot /></div>' },
VMain: { template: '<div class="v-main-stub"><slot /></div>' },
},
},
});
};
describe('ErrorView.vue', () => {
it('по умолчанию (errorCode=404) показывает «404 / Страница не найдена»', async () => {
const wrapper = await mountErrorView('404');
const text = wrapper.text();
expect(wrapper.find('.err-code').text()).toBe('404');
expect(text).toContain('Страница не найдена');
expect(text).toContain('Все рабочие экраны Лидерра доступны через дашборд');
});
it('errorCode=403 показывает «403 / У вас нет доступа» + RequestId', async () => {
const wrapper = await mountErrorView('403');
const text = wrapper.text();
expect(wrapper.find('.err-code').text()).toBe('403');
expect(text).toContain('У вас нет доступа');
expect(text).toContain('REQ-3F8A2-0007');
expect(text).toContain('Запрос');
});
it('errorCode=500 показывает «500 / Что-то пошло не так» + IncidentId + status-list', async () => {
const wrapper = await mountErrorView('500');
const text = wrapper.text();
expect(wrapper.find('.err-code').text()).toBe('500');
expect(text).toContain('Что-то пошло не так');
expect(text).toContain('INC-2026-0507-0034');
expect(text).toContain('Инцидент');
// status-list только на 500.
expect(text).toContain('API · OK');
expect(text).toContain('Telegram · деградация');
});
it('404 содержит «На дашборд» primary + «Назад» secondary', async () => {
const wrapper = await mountErrorView('404');
const text = wrapper.text();
expect(text).toContain('На дашборд');
expect(text).toContain('Назад');
});
it('403 содержит «На дашборд» + «Написать в поддержку» (mailto)', async () => {
const wrapper = await mountErrorView('403');
const text = wrapper.text();
expect(text).toContain('На дашборд');
expect(text).toContain('Написать в поддержку');
const mailtoLink = wrapper.find('a[href^="mailto:"]');
expect(mailtoLink.exists()).toBe(true);
expect(mailtoLink.attributes('href')).toBe('mailto:support@liderra.app');
});
it('500 содержит «Попробовать снова» + «Статус сервиса» (external link)', async () => {
const wrapper = await mountErrorView('500');
const text = wrapper.text();
expect(text).toContain('Попробовать снова');
expect(text).toContain('Статус сервиса');
const statusLink = wrapper.find('a[href^="https://status."]');
expect(statusLink.exists()).toBe(true);
});
it('содержит брендовый блок «Лидерра.» в шапке', async () => {
const wrapper = await mountErrorView('404');
const brand = wrapper.find('.top-brand');
expect(brand.exists()).toBe(true);
expect(brand.text()).toContain('Лидерра');
});
it('404 НЕ содержит RequestId или status-list', async () => {
const wrapper = await mountErrorView('404');
const text = wrapper.text();
expect(text).not.toContain('REQ-');
expect(text).not.toContain('INC-');
expect(text).not.toContain('API · OK');
});
});