moex-vibe/apps/backend/src/modules/securities/securities.service.spec.ts

175 lines
4.6 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 { Test, TestingModule } from '@nestjs/testing';
import { SecuritiesService } from './securities.service';
import { MoexClientService } from '../moex-client/moex-client.service';
import { CacheService } from '../cache/cache.service';
import { SecurityType } from './dto/search-query.dto';
describe('SecuritiesService', () => {
let service: SecuritiesService;
let moexClient: Pick<MoexClientService, 'searchSecurities'>;
let cache: Pick<CacheService, 'getOrFetch'>;
beforeEach(async () => {
moexClient = {
searchSecurities: vi.fn(),
};
cache = {
getOrFetch: vi.fn(async (_keyPrefix, _keyParts, fetchFn) => ({
data: await fetchFn(),
fromCache: false,
cachedAt: '2026-06-15T00:00:00.000Z',
})),
};
const module: TestingModule = await Test.createTestingModule({
providers: [
SecuritiesService,
{ provide: MoexClientService, useValue: moexClient },
{ provide: CacheService, useValue: cache },
],
}).compile();
service = module.get<SecuritiesService>(SecuritiesService);
});
it('returns supported securities only and normalizes SUR currency to RUB', async () => {
vi.mocked(moexClient.searchSecurities).mockResolvedValue([
{
secid: 'SBER',
isin: 'RU0009029540',
name: 'Сбербанк России ПАО ао',
shortName: 'Сбербанк',
latName: 'Sberbank',
listLevel: 1,
issueSize: 21586948000,
faceValue: 3,
faceUnit: 'SUR',
issueDate: '2007-07-20',
typeName: 'Акция обыкновенная',
group: 'stock_shares',
type: 'common_share',
isQualifiedInvestors: false,
morningSession: true,
eveningSession: true,
},
{
secid: 'SU26238RMFS5',
isin: 'RU000A1038V6',
name: 'ОФЗ 26238',
shortName: 'ОФЗ 26238',
latName: null,
listLevel: 1,
issueSize: 100000000,
faceValue: 1000,
faceUnit: 'RUB',
issueDate: '2021-06-23',
typeName: 'Государственная облигация',
group: 'stock_bonds',
type: 'ofz_bond',
isQualifiedInvestors: false,
morningSession: false,
eveningSession: false,
},
{
secid: 'SiM6',
isin: '',
name: 'USD/RUB Futures',
shortName: 'SiM6',
latName: null,
listLevel: 0,
issueSize: 0,
faceValue: 0,
faceUnit: '',
issueDate: '',
typeName: 'Фьючерс',
group: 'futures',
type: 'futures',
isQualifiedInvestors: false,
morningSession: false,
eveningSession: true,
},
]);
const results = await service.search('SbEr', SecurityType.ALL, 10);
expect(results).toEqual([
{
secid: 'SBER',
isin: 'RU0009029540',
shortName: 'Сбербанк',
type: 'share',
listLevel: 1,
currency: 'RUB',
price: null,
},
{
secid: 'SU26238RMFS5',
isin: 'RU000A1038V6',
shortName: 'ОФЗ 26238',
type: 'bond',
listLevel: 1,
currency: 'RUB',
price: null,
},
]);
expect(cache.getOrFetch).toHaveBeenCalledWith(
'search',
['sber'],
expect.any(Function),
'searchTtl',
);
expect(moexClient.searchSecurities).toHaveBeenCalledWith('SbEr');
});
it('filters by type and applies limit without live MOEX dependency', async () => {
vi.mocked(cache.getOrFetch).mockResolvedValue({
data: [
{
secid: 'SBER',
isin: 'RU0009029540',
shortName: 'Сбербанк',
type: 'share',
listLevel: 1,
currency: 'RUB',
price: null,
},
{
secid: 'GAZP',
isin: 'RU0007661625',
shortName: 'Газпром',
type: 'share',
listLevel: 1,
currency: 'RUB',
price: null,
},
{
secid: 'SU26238RMFS5',
isin: 'RU000A1038V6',
shortName: 'ОФЗ 26238',
type: 'bond',
listLevel: 1,
currency: 'RUB',
price: null,
},
],
fromCache: true,
cachedAt: null,
});
const results = await service.search('ru', SecurityType.SHARE, 1);
expect(results).toEqual([
{
secid: 'SBER',
isin: 'RU0009029540',
shortName: 'Сбербанк',
type: 'share',
listLevel: 1,
currency: 'RUB',
price: null,
},
]);
expect(moexClient.searchSecurities).not.toHaveBeenCalled();
});
});