Files
finance/frontend/src/test/system-account-picker.test.tsx
T

135 lines
4.4 KiB
TypeScript

import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'
import userEvent from '@testing-library/user-event'
import { within } from '@testing-library/react'
import { api } from '@/api/endpoints'
import type { Account, BudgetCategory, Page, Operation } from '@/api/types'
import { ImportsPage } from '@/pages/ImportsPage'
import { OperationsPage } from '@/pages/OperationsPage'
import { renderWithProviders } from './helpers'
vi.mock('@/api/endpoints', () => ({
api: {
accounts: {
list: vi.fn(),
create: vi.fn(),
archive: vi.fn(),
adjustBalance: vi.fn(),
},
operations: {
list: vi.fn(),
create: vi.fn(),
void: vi.fn(),
categorize: vi.fn(),
savingsTransfer: vi.fn(),
savingsTransferRevert: vi.fn(),
},
budget: {
summary: vi.fn(),
categories: vi.fn(),
updatePlan: vi.fn(),
fund: vi.fn(),
close: vi.fn(),
reopen: vi.fn(),
copyPrevious: vi.fn(),
categoryDefinitions: vi.fn(),
createCategory: vi.fn(),
updateCategoryDefinition: vi.fn(),
},
imports: {
list: vi.fn(),
get: vi.fn(),
upload: vi.fn(),
saveRowDecision: vi.fn(),
resolveHold: vi.fn(),
confirm: vi.fn(),
reparse: vi.fn(),
revert: vi.fn(),
},
},
}))
const listAccountsMock = vi.mocked(api.accounts.list)
const operationsListMock = vi.mocked(api.operations.list)
const budgetCategoriesMock = vi.mocked(api.budget.categories)
const importsListMock = vi.mocked(api.imports.list)
function account(overrides: Partial<Account> = {}): Account {
return {
id: 'a1',
name: 'Alfa Card',
type: 'debit',
status: 'active',
bankCode: null,
maskedNumber: null,
openedOn: '2026-01-15',
currency: 'RUB',
systemKey: null,
nameKey: null,
balanceKopecks: 123456,
...overrides,
}
}
describe('system savings account picker exclusion', () => {
beforeEach(() => {
listAccountsMock.mockResolvedValue([
account(),
account({ id: 'a2', name: 'Cash wallet', type: 'cash' }),
account({
id: 'a-sys',
name: 'Накопления',
nameKey: 'account.savings',
type: 'savings',
systemKey: 'savings',
balanceKopecks: 0,
}),
])
operationsListMock.mockResolvedValue({ items: [], nextCursor: null } as Page<Operation>)
budgetCategoriesMock.mockResolvedValue([] as BudgetCategory[])
importsListMock.mockResolvedValue([])
})
afterEach(() => {
vi.clearAllMocks()
})
it('hides the savings account in the expense form but keeps it in the transfer form and filters', async () => {
const screen = renderWithProviders(<OperationsPage />)
await userEvent.click(
await screen.findByRole('button', { name: '+ New operation' }),
)
const dialog = await screen.findByRole('dialog', { name: 'New operation' })
const expenseSelect = within(dialog).getByLabelText('Account') as HTMLSelectElement
const expenseOptions = Array.from(expenseSelect.options).map((option) => option.textContent)
expect(expenseOptions).toContain('Alfa Card')
expect(expenseOptions).not.toContain('Savings')
await userEvent.click(within(dialog).getByRole('button', { name: 'Transfer' }))
const transferSelects = within(dialog)
.getAllByRole('combobox')
.filter((select) => (select as HTMLSelectElement).options.length > 2) as HTMLSelectElement[]
const transferOptions = transferSelects.flatMap((select) =>
Array.from(select.options).map((option) => option.textContent),
)
expect(transferOptions).toContain('Savings')
const filterSelect = screen.getByLabelText('Account') as HTMLSelectElement
const filterOptions = Array.from(filterSelect.options).map((option) => option.textContent)
expect(filterOptions).toContain('Savings')
})
it('hides the savings account in the statement upload target selector', async () => {
const screen = renderWithProviders(<ImportsPage />)
await userEvent.click(await screen.findByRole('button', { name: '+ Upload statement' }))
const dialog = await screen.findByRole('dialog', { name: 'New import' })
const select = within(dialog).getByLabelText('Target account') as HTMLSelectElement
const options = Array.from(select.options).map((option) => option.textContent)
expect(options).toContain('Alfa Card')
expect(options).toContain('Cash wallet')
expect(options).not.toContain('Savings')
})
})