85 lines
3.5 KiB
TypeScript
85 lines
3.5 KiB
TypeScript
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 AdminBillingView from '../../resources/js/views/admin/AdminBillingView.vue';
|
|
import { ADMIN_BILLING_TENANTS, ADMIN_BILLING_SUMMARY } 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,
|
|
listAdminBilling: vi.fn(),
|
|
};
|
|
});
|
|
|
|
const adminApi = await import('../../resources/js/api/admin');
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
vi.mocked(adminApi.listAdminBilling).mockResolvedValue({
|
|
tenants: ADMIN_BILLING_TENANTS.map((r) => ({
|
|
id: r.id,
|
|
subdomain: `tenant${r.id}`,
|
|
organization_name: r.name,
|
|
contact_email: `t${r.id}@test.io`,
|
|
status: r.status === 'overdue' ? 'active' : r.status,
|
|
balance_rub: String(r.balance_rub),
|
|
tariff_id: 1,
|
|
tariff_name: { start: 'Старт', basic: 'Базовый', pro: 'Команда', enterprise: 'Enterprise' }[r.tariff] ?? r.tariff,
|
|
mrr_rub: String(r.mrr_rub),
|
|
monthly_topups_rub: String(r.monthly_topups_rub),
|
|
monthly_charges_rub: String(r.monthly_charges_rub),
|
|
last_payment_at: r.last_payment_at,
|
|
chargeback_unrecovered_rub: r.status === 'overdue' ? '1.00' : '0.00',
|
|
})),
|
|
summary: {
|
|
total_mrr_rub: String(ADMIN_BILLING_SUMMARY.total_mrr_rub),
|
|
monthly_revenue_rub: String(ADMIN_BILLING_SUMMARY.monthly_revenue_rub),
|
|
overdue_count: ADMIN_BILLING_SUMMARY.overdue_count,
|
|
refunds_count_30d: ADMIN_BILLING_SUMMARY.refunds_count_30d,
|
|
},
|
|
});
|
|
});
|
|
|
|
const mountView = async () => {
|
|
const router = createRouter({
|
|
history: createMemoryHistory(),
|
|
routes: [{ path: '/admin/billing', component: AdminBillingView }],
|
|
});
|
|
await router.push('/admin/billing');
|
|
await router.isReady();
|
|
const wrapper = mount(AdminBillingView, {
|
|
global: { plugins: [createVuetify(), router] },
|
|
});
|
|
await flushPromises();
|
|
return wrapper;
|
|
};
|
|
|
|
describe('AdminBillingView.vue', () => {
|
|
it('монтируется и содержит заголовок «Биллинг»', async () => {
|
|
const wrapper = await mountView();
|
|
expect(wrapper.text()).toContain('Биллинг');
|
|
});
|
|
|
|
it('содержит 4 stats: MRR / Выручка / Просрочка / Возвраты', async () => {
|
|
const wrapper = await mountView();
|
|
const text = wrapper.text();
|
|
expect(text).toContain('MRR');
|
|
expect(text).toContain('Выручка за месяц');
|
|
expect(text).toContain('Просрочка');
|
|
expect(text).toContain('Возвраты за 30 дн');
|
|
});
|
|
|
|
it('содержит таблицу тенантов с tariff/balance/MRR/status', async () => {
|
|
const wrapper = await mountView();
|
|
const text = wrapper.text();
|
|
expect(text).toContain('Окна Москва');
|
|
expect(text).toContain('BigCorp');
|
|
expect(text).toContain('Команда');
|
|
expect(text).toContain('Активен');
|
|
expect(text).toContain('Просрочка');
|
|
expect(text).toContain('Заблокирован');
|
|
});
|
|
});
|