feat: add brocker account list

This commit is contained in:
2026-08-13 20:57:01 +03:00
parent 18d7cfcf9f
commit c0a4a93880
7 changed files with 272 additions and 8 deletions
@@ -0,0 +1,105 @@
import { BadRequestException, ConflictException } from '@nestjs/common';
import { ServiceUnavailableException } from '@nestjs/common';
jest.mock('../prisma/prisma.service', () => ({
PrismaService: class PrismaService {},
}));
import { BrokerageAccountsService } from './brokerage-accounts.service';
import { TbankCrypto } from './tbank.crypto';
describe('BrokerageAccountsService', () => {
const encryptionKey = 'MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=';
const prisma = { tbankConnection: { findUnique: jest.fn() } };
const config = { getOrThrow: jest.fn(() => encryptionKey) };
const tbank = { getOpenAccounts: jest.fn() };
const service = new BrokerageAccountsService(
prisma as never,
config as never,
tbank as never,
);
const crypto = TbankCrypto.fromBase64(encryptionKey);
beforeEach(() => jest.clearAllMocks());
it('does not call T-Bank without a connection', async () => {
prisma.tbankConnection.findUnique.mockResolvedValue(null);
await expect(service.list('user-1')).rejects.toEqual(
expect.any(ConflictException),
);
expect(tbank.getOpenAccounts).not.toHaveBeenCalled();
});
it('normalizes supported accounts and ignores unsupported ones', async () => {
prisma.tbankConnection.findUnique.mockResolvedValue({
encryptedToken: crypto.encrypt('token'),
});
tbank.getOpenAccounts.mockResolvedValue([
{
id: 'brokerage',
type: 'ACCOUNT_TYPE_TINKOFF',
name: ' Основной ',
openedDate: { seconds: '1723507200' },
},
{
id: 'debit',
type: 'ACCOUNT_TYPE_DEBIT',
name: 'Дебетовый',
},
{
id: 'iis',
type: 'ACCOUNT_TYPE_TINKOFF_IIS',
name: ' ',
},
]);
await expect(service.list('user-1')).resolves.toEqual([
{
id: 'brokerage',
type: 'BROKERAGE',
name: 'Основной',
openedOn: '2024-08-13',
},
{
id: 'iis',
type: 'INDIVIDUAL_INVESTMENT',
name: 'ИИС',
openedOn: null,
},
]);
});
it('retains the connection when T-Bank rejects its token', async () => {
prisma.tbankConnection.findUnique.mockResolvedValue({
encryptedToken: crypto.encrypt('token'),
});
tbank.getOpenAccounts.mockRejectedValue(new Error('INVALID_TBANK_TOKEN'));
await expect(service.list('user-1')).rejects.toEqual(
expect.any(BadRequestException),
);
});
it('returns an empty list from T-Bank unchanged', async () => {
prisma.tbankConnection.findUnique.mockResolvedValue({
encryptedToken: crypto.encrypt('token'),
});
tbank.getOpenAccounts.mockResolvedValue([]);
await expect(service.list('user-1')).resolves.toEqual([]);
});
it('propagates an unavailable T-Bank response', async () => {
prisma.tbankConnection.findUnique.mockResolvedValue({
encryptedToken: crypto.encrypt('token'),
});
tbank.getOpenAccounts.mockRejectedValue(
new ServiceUnavailableException({ code: 'TBANK_UNAVAILABLE' }),
);
await expect(service.list('user-1')).rejects.toEqual(
expect.any(ServiceUnavailableException),
);
});
});