Files
portal/app/tests/Frontend/BillingView.spec.ts
T
Дмитрий c8012896e3 phase2(billing): BillingView - финансовый экран биллинга и тарифов
- BillingView (/billing): page-head со stats (кошелёк/лиды/runway-дни) + pending
  banner v-alert info («1 платёж в обработке через ЮKassa, auto-cancel 30 мин»)
  + 3 wallet-cards (Кошелёк ₽ primary card теало-нуар + LIVE; Баланс лидов
  ГЦК; Тариф «Команда» 990₽/мес + 3 фичи) + transactions panel (4 tabs +
  v-data-table 5 колонок: Дата/Операция/ID/Статус-chip/Сумма ± JBM tnum) +
  invoices list (PDF + 1С 8.3 XML).
- composables/mockBilling.ts соответствует схеме v8.7 §4.4-4.5: 8 mock
  транзакций (types: topup/lead_charge/refund/tariff_charge; statuses:
  pending/completed/rejected) + 4 invoices (pdf/xml_1c83) + pending payment.
- Маршрут /billing (meta.layout=app) в router + web.php.

Format helpers: «+ N ₽» / «− N ₽» / «— 0 ₽» rejected; Intl.NumberFormat ru-RU.

Vitest +11 (всего 90/90 за 7.96s):
- заголовок + page-stats nbsp regex + pending banner + 3 wallet-cards + 3 фичи
  тарифа + 4 tabs + дефолт «Все» 8 строк + format «+/−» + rejected «— 0 ₽» +
  4 invoice rows + PDF/1С 8.3 XML labels.

Регресс: lint+type+format OK; vitest 90/90; vite build (BillingView lazy-chunk;
VDataTable вынесен в общий chunk 79.84KB - shared с DealsView); story:build
16/23 за 32.16s; Pest 48/48 за 4.89s.

CLAUDE.md v1.26->v1.27, реестр Открытых_вопросов v1.35->v1.36.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 18:39:49 +03:00

95 lines
3.9 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 } from 'vitest';
import { mount } from '@vue/test-utils';
import { createVuetify } from 'vuetify';
import BillingView from '../../resources/js/views/BillingView.vue';
import { MOCK_INVOICES, MOCK_TRANSACTIONS } from '../../resources/js/composables/mockBilling';
describe('BillingView.vue', () => {
const factory = () =>
mount(BillingView, {
global: { plugins: [createVuetify()] },
});
it('монтируется и содержит заголовок «Биллинг и тарифы»', () => {
const wrapper = factory();
expect(wrapper.find('h1').text()).toBe('Биллинг и тарифы');
});
it('содержит page-stats с кошельком, лидами, runway-днями', () => {
const wrapper = factory();
const text = wrapper.text();
expect(text).toMatch(/14\s+250\s*₽/); // кошелёк ₽
expect(text).toContain('285');
expect(text).toContain('лидов запас');
expect(text).toContain('4 дня');
});
it('показывает pending banner («1 платёж в обработке»)', () => {
const wrapper = factory();
const text = wrapper.text();
expect(text).toContain('1 платёж в обработке');
expect(text).toMatch(/5\s+000\s*₽/);
expect(text).toContain('ЮKassa');
});
it('содержит 3 wallet-cards (₽ / лиды / тариф)', () => {
const wrapper = factory();
const text = wrapper.text();
expect(text).toContain('Кошелёк ₽');
expect(text).toContain('LIVE');
expect(text).toContain('Баланс лидов (ГЦК)');
expect(text).toContain('Тариф');
expect(text).toContain('Команда');
expect(text).toContain('990 ₽/мес');
});
it('содержит 3 фичи тарифа', () => {
const wrapper = factory();
const text = wrapper.text();
expect(text).toContain('до 10 проектов');
expect(text).toContain('4 менеджера');
expect(text).toContain('Канбан, Webhook, API');
});
it('содержит 4 tab-кнопки в transactions panel', () => {
const wrapper = factory();
const text = wrapper.text();
expect(text).toContain('Все');
expect(text).toContain('Пополнения');
expect(text).toContain('Списания');
expect(text).toContain('Возвраты');
});
it('таблица транзакций по умолчанию (Все) содержит все mock-строки', () => {
const wrapper = factory();
const rows = wrapper.findAll('tbody tr');
expect(rows.length).toBe(MOCK_TRANSACTIONS.length);
});
it('форматирует положительную сумму как «+ N ₽» и отрицательную как «− N ₽»', () => {
const wrapper = factory();
const text = wrapper.text();
expect(text).toMatch(/\+\s+5\s+000\s*₽/); // +5000 топап
expect(text).toMatch(/\s+6\s+600\s*₽/); // -6600 списание
});
it('rejected-транзакция показывает «— 0 ₽»', () => {
const wrapper = factory();
expect(wrapper.text()).toContain('— 0 ₽');
});
it('содержит invoices section с 4 строками', () => {
const wrapper = factory();
expect(wrapper.text()).toContain('Счета и УПД');
const rows = wrapper.findAll('.inv-row');
expect(rows.length).toBe(MOCK_INVOICES.length);
});
it('invoice показывает PDF или 1С 8.3 XML формат', () => {
const wrapper = factory();
const text = wrapper.text();
expect(text).toContain('PDF');
expect(text).toContain('1С 8.3 XML');
});
});