175 lines
4.6 KiB
TypeScript
175 lines
4.6 KiB
TypeScript
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();
|
||
});
|
||
});
|