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

101 lines
4.4 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 TransactionsTable from '../../resources/js/components/billing/TransactionsTable.vue';
import * as billingApi from '../../resources/js/api/billing';
import type { BillingTransaction, TransactionsPage } from '../../resources/js/api/billing';
vi.mock('../../resources/js/api/billing');
const vuetify = createVuetify();
function txn(over: Partial<BillingTransaction> = {}): BillingTransaction {
return {
id: 1,
code: 'TX-1',
type: 'topup',
description: 'Пополнение баланса',
amount_rub: '5000.00',
amount_leads: 0,
balance_rub_after: '5000.00',
display_amount_rub: '5000.00',
created_at: '2026-05-10T14:21:00Z',
...over,
};
}
function makePage(txns: BillingTransaction[]): TransactionsPage {
return { data: txns, meta: { current_page: 1, last_page: 1, total: txns.length, per_page: 20 } };
}
describe('TransactionsTable.vue', () => {
beforeEach(() => {
vi.mocked(billingApi.getTransactions).mockResolvedValue(makePage([txn()]));
});
it('загружает транзакции при монтировании', async () => {
const wrapper = mount(TransactionsTable, { global: { plugins: [vuetify] } });
await flushPromises();
expect(billingApi.getTransactions).toHaveBeenCalled();
expect((wrapper.vm as unknown as { total: number }).total).toBe(1);
});
it('смена таба «Пополнения» шлёт type=topup', async () => {
const wrapper = mount(TransactionsTable, { global: { plugins: [vuetify] } });
await flushPromises();
await (wrapper.vm as unknown as { changeTab: (id: string) => Promise<void> }).changeTab('topup');
expect(billingApi.getTransactions).toHaveBeenLastCalledWith(
expect.objectContaining({ type: 'topup' }),
);
});
it('таб «Все» не шлёт type', async () => {
const wrapper = mount(TransactionsTable, { global: { plugins: [vuetify] } });
await flushPromises();
await (wrapper.vm as unknown as { changeTab: (id: string) => Promise<void> }).changeTab('all');
const lastCall = vi.mocked(billingApi.getTransactions).mock.calls.at(-1)?.[0];
expect(lastCall).not.toHaveProperty('type');
});
it('показывает error-alert при сбое', async () => {
vi.mocked(billingApi.getTransactions).mockRejectedValue(new Error('fail'));
const wrapper = mount(TransactionsTable, { global: { plugins: [vuetify] } });
await flushPromises();
expect(wrapper.text()).toContain('Не удалось загрузить транзакции');
});
it('does NOT render «Возвраты» tab', async () => {
const wrapper = mount(TransactionsTable, { global: { plugins: [vuetify] } });
await flushPromises();
expect(wrapper.text()).not.toContain('Возвраты');
});
it('uses display_amount_rub for amount column on historic prepaid rows', async () => {
// historic prepaid row: amount_rub='0.00', amount_leads=null, display_amount_rub='0.00'
vi.mocked(billingApi.getTransactions).mockResolvedValue(
makePage([
txn({
type: 'historical_import',
amount_rub: '0.00',
amount_leads: null,
display_amount_rub: '0.00',
}),
]),
);
const wrapper = mount(TransactionsTable, { global: { plugins: [vuetify] } });
await flushPromises();
// Old code would have shown ' 1 лид.' for amount_leads=-1; new code uses display_amount_rub
// With display_amount_rub='0.00' we expect '0' somewhere in the amount cell (formatted as 0 ₽)
expect(wrapper.text()).not.toContain('лид.');
});
it('formats date with 2-digit year', async () => {
const wrapper = mount(TransactionsTable, { global: { plugins: [vuetify] } });
await flushPromises();
// Date '2026-05-10T14:21:00Z' formatted as ru-RU with year:'2-digit' → includes '26'
// Pattern: DD.MM.YY, HH:MM (ru-RU locale with 2-digit year)
const text = wrapper.text();
expect(text).toMatch(/\d{2}\.\d{2}\.\d{2}/);
});
});