feat: add operations list
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
NotFoundException,
|
||||
ServiceUnavailableException,
|
||||
} from '@nestjs/common';
|
||||
|
||||
jest.mock('../prisma/prisma.service', () => ({
|
||||
PrismaService: class PrismaService {},
|
||||
}));
|
||||
|
||||
import { BrokerageOperationsService } from './brokerage-operations.service';
|
||||
import { TbankCrypto } from './tbank.crypto';
|
||||
|
||||
describe('BrokerageOperationsService', () => {
|
||||
const key = 'MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=';
|
||||
const prisma = { tbankConnection: { findUnique: jest.fn() } };
|
||||
const config = { getOrThrow: jest.fn(() => key) };
|
||||
const tbank = {
|
||||
getOpenAccounts: jest.fn(),
|
||||
getOperationsByCursor: jest.fn(),
|
||||
};
|
||||
const service = new BrokerageOperationsService(
|
||||
prisma as never,
|
||||
config as never,
|
||||
tbank as never,
|
||||
);
|
||||
const crypto = TbankCrypto.fromBase64(key);
|
||||
let operationsRequest: unknown;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
prisma.tbankConnection.findUnique.mockResolvedValue({
|
||||
encryptedToken: crypto.encrypt('token'),
|
||||
});
|
||||
tbank.getOpenAccounts.mockResolvedValue([
|
||||
{ id: 'account', type: 'ACCOUNT_TYPE_TINKOFF' },
|
||||
]);
|
||||
tbank.getOperationsByCursor.mockImplementation(
|
||||
(_token: string, request: unknown) => {
|
||||
operationsRequest = request;
|
||||
return Promise.resolve({ items: [] });
|
||||
},
|
||||
);
|
||||
(service as unknown as { pages: Map<string, unknown> }).pages.clear();
|
||||
});
|
||||
|
||||
it('uses the current UTC year by default and asks only for executed operations', async () => {
|
||||
await service.get('user', 'account', {});
|
||||
|
||||
const request = operationsRequest as {
|
||||
state: string;
|
||||
from: { seconds: string };
|
||||
};
|
||||
expect(request.state).toBe('OPERATION_STATE_EXECUTED');
|
||||
expect(request.from.seconds).toBe(
|
||||
String(Math.floor(Date.UTC(new Date().getUTCFullYear(), 0, 1) / 1000)),
|
||||
);
|
||||
});
|
||||
|
||||
it('uses inclusive date boundaries, filters categories, and preserves cursors', async () => {
|
||||
tbank.getOperationsByCursor.mockResolvedValue({
|
||||
hasNext: true,
|
||||
nextCursor: 'next',
|
||||
items: [
|
||||
{ id: 'income', date: { seconds: '1' }, type: 'OPERATION_TYPE_COUPON' },
|
||||
{
|
||||
id: 'fee',
|
||||
date: { seconds: '2' },
|
||||
type: 'OPERATION_TYPE_BROKER_FEE',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await expect(
|
||||
service.get('user', 'account', {
|
||||
from: '2025-01-01',
|
||||
to: '2025-01-31',
|
||||
categories: ['income'],
|
||||
cursor: 'previous',
|
||||
limit: 10,
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
items: [{ id: 'income' }],
|
||||
nextCursor: 'next',
|
||||
hasNext: true,
|
||||
});
|
||||
expect(tbank.getOperationsByCursor).toHaveBeenCalledWith(
|
||||
'token',
|
||||
expect.objectContaining({
|
||||
from: { seconds: '1735689600' },
|
||||
to: { seconds: '1738367999', nanos: 999_999_999 },
|
||||
cursor: 'previous',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('returns an empty page without calling T-Bank when the period starts in the future', async () => {
|
||||
await expect(
|
||||
service.get('user', 'account', { from: '2999-01-01T00:00:00.000Z' }),
|
||||
).resolves.toMatchObject({
|
||||
accountId: 'account',
|
||||
items: [],
|
||||
nextCursor: null,
|
||||
hasNext: false,
|
||||
});
|
||||
expect(tbank.getOperationsByCursor).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('rejects inaccessible accounts before reading operations', async () => {
|
||||
tbank.getOpenAccounts.mockResolvedValue([]);
|
||||
|
||||
await expect(service.get('user', 'account', {})).rejects.toEqual(
|
||||
expect.any(NotFoundException),
|
||||
);
|
||||
expect(tbank.getOperationsByCursor).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('retains existing T-Bank error semantics', async () => {
|
||||
tbank.getOpenAccounts.mockRejectedValueOnce(
|
||||
new Error('INVALID_TBANK_TOKEN'),
|
||||
);
|
||||
await expect(service.get('user', 'account', {})).rejects.toEqual(
|
||||
expect.any(BadRequestException),
|
||||
);
|
||||
tbank.getOpenAccounts.mockResolvedValueOnce([
|
||||
{ id: 'account', type: 'ACCOUNT_TYPE_TINKOFF' },
|
||||
]);
|
||||
tbank.getOperationsByCursor.mockRejectedValueOnce(
|
||||
new ServiceUnavailableException({ code: 'TBANK_UNAVAILABLE' }),
|
||||
);
|
||||
await expect(service.get('user', 'account', {})).rejects.toEqual(
|
||||
expect.any(ServiceUnavailableException),
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user