e1601e7862
Spec C §3.6/§6.2. Бэкенд: GET /api/billing/balance-status (frozen + capacity + required + дефицит ₽/leads), Pest 6. Фронт: BalanceFrozenBanner (в AppLayout, глобально), BalanceCapacityIndicator (в BillingView под балансом), ProjectLimitOverloadDialog (409-перехват в NewProjectDialog: save-blocked/set-zero), tenantStore + api getBalanceStatus. Vitest +18. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
49 lines
2.2 KiB
TypeScript
49 lines
2.2 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { mount } from '@vue/test-utils';
|
|
import { createVuetify } from 'vuetify';
|
|
import BalanceFrozenBanner from '../../resources/js/components/billing/BalanceFrozenBanner.vue';
|
|
|
|
// Billing v2 Spec C Task 1.10 — красный баннер заморозки (§3.6). Показывается
|
|
// на всех страницах, когда tenant.frozen_by_balance_at !== null.
|
|
|
|
const routerLinkStub = {
|
|
RouterLink: {
|
|
props: ['to'],
|
|
inheritAttrs: false,
|
|
template: '<a v-bind="$attrs" :href="to"><slot /></a>',
|
|
},
|
|
};
|
|
|
|
const mountBanner = (props: { frozen: boolean; deficitRub?: string; deficitLeads?: number }) =>
|
|
mount(BalanceFrozenBanner, {
|
|
props,
|
|
global: { plugins: [createVuetify()], stubs: routerLinkStub },
|
|
});
|
|
|
|
describe('BalanceFrozenBanner', () => {
|
|
it('не заморожен — баннер не рендерится', () => {
|
|
const w = mountBanner({ frozen: false });
|
|
expect(w.find('[data-testid="balance-frozen-banner"]').exists()).toBe(false);
|
|
});
|
|
|
|
it('заморожен — красный баннер с текстом «приостановлен»', () => {
|
|
const w = mountBanner({ frozen: true, deficitRub: '380.00', deficitLeads: 10 });
|
|
const banner = w.find('[data-testid="balance-frozen-banner"]');
|
|
expect(banner.exists()).toBe(true);
|
|
expect(banner.text()).toContain('приостановлен');
|
|
});
|
|
|
|
it('показывает дефицит в рублях и лидах', () => {
|
|
const w = mountBanner({ frozen: true, deficitRub: '380.00', deficitLeads: 10 });
|
|
const text = w.find('[data-testid="balance-frozen-banner"]').text();
|
|
expect(text).toContain('380');
|
|
expect(text).toContain('10');
|
|
});
|
|
|
|
it('две ссылки — на /billing и на /projects', () => {
|
|
const w = mountBanner({ frozen: true, deficitRub: '380.00', deficitLeads: 10 });
|
|
expect(w.find('[data-testid="banner-topup-link"]').attributes('href')).toBe('/billing');
|
|
expect(w.find('[data-testid="banner-projects-link"]').attributes('href')).toBe('/projects');
|
|
});
|
|
});
|