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

136 lines
4.0 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 { NotFoundException } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { SharesService } from './shares.service';
import { MoexClientService } from '../moex-client/moex-client.service';
import { CacheService } from '../cache/cache.service';
describe('SharesService', () => {
let service: SharesService;
let moexClient: Pick<MoexClientService, 'getSecurityDescription' | 'getShareMarketData'>;
let cache: Pick<CacheService, 'getOrFetch'>;
beforeEach(async () => {
moexClient = {
getSecurityDescription: vi.fn(),
getShareMarketData: 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: [
SharesService,
{ provide: MoexClientService, useValue: moexClient },
{ provide: CacheService, useValue: cache },
],
}).compile();
service = module.get<SharesService>(SharesService);
});
it('returns normalized SBER share spec and market data without live MOEX dependency', async () => {
vi.mocked(moexClient.getSecurityDescription).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,
});
vi.mocked(moexClient.getShareMarketData).mockResolvedValue({
secid: 'SBER',
boardid: 'TQBR',
shortName: 'Сбербанк',
bid: 320,
offer: 321,
open: 318,
low: 317,
high: 325,
last: 323,
lastChange: 4,
lastChangePrcnt: 1.25,
volume: 1500000,
value: 480000000,
waprice: 321,
numtrades: 4200,
issueCapitalization: 6900000000000,
tradingStatus: 'T',
updateTime: '18:45:00',
});
const result = await service.getShare('SBER');
expect(moexClient.getSecurityDescription).toHaveBeenCalledWith('SBER');
expect(cache.getOrFetch).toHaveBeenCalledWith(
'marketdata',
['shares', 'SBER'],
expect.any(Function),
'marketDataTtl',
);
expect(moexClient.getShareMarketData).toHaveBeenCalledWith('SBER');
expect(result).toMatchObject({
secid: 'SBER',
isin: 'RU0009029540',
name: 'Сбербанк России ПАО ао',
shortName: 'Сбербанк',
latName: 'Sberbank',
listLevel: 1,
issueSize: 21586948000,
faceValue: 3,
faceUnit: 'RUB',
type: 'common_share',
marketData: {
price: 323,
change: 4,
changePercent: 1.25,
open: 318,
high: 325,
low: 317,
volume: 1500000,
value: 480000000,
issueCapitalization: 6900000000000,
},
});
expect(result.marketData.updatedAt).toMatch(/T18:45:00$/);
});
it('throws NotFoundException for non-share security', async () => {
vi.mocked(moexClient.getSecurityDescription).mockResolvedValue({
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,
});
await expect(service.getShare('SU26238RMFS5')).rejects.toBeInstanceOf(NotFoundException);
expect(cache.getOrFetch).not.toHaveBeenCalled();
});
});