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

111 lines
2.8 KiB
TypeScript

import { Test, TestingModule } from '@nestjs/testing';
import { ScreenerService } from './screener.service';
import { MoexClientService } from '../moex-client/moex-client.service';
import { CacheService } from '../cache/cache.service';
import { ScreenerType } from './dto/screener-query.dto';
describe('ScreenerService', () => {
let service: ScreenerService;
let cache: CacheService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ScreenerService,
{
provide: MoexClientService,
useValue: {
getShareMarketDataBatch: vi.fn(),
getBondPositionDataBatch: vi.fn(),
},
},
{
provide: CacheService,
useValue: {
getOrFetch: vi.fn(),
},
},
],
}).compile();
service = module.get<ScreenerService>(ScreenerService);
cache = module.get<CacheService>(CacheService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('screen', () => {
it('should filter and sort shares', async () => {
const mockShares = [
{
secid: 'SBER',
shortName: 'Sberbank',
price: 250,
volume: 1000000,
changePercent: 1,
type: 'share',
},
{
secid: 'GAZP',
shortName: 'Gazprom',
price: 150,
volume: 500000,
changePercent: -1,
type: 'share',
},
{
secid: 'LKOH',
shortName: 'Lukoil',
price: 5000,
volume: 100000,
changePercent: 0.5,
type: 'share',
},
];
vi.mocked(cache.getOrFetch).mockImplementation(async () => ({
data: mockShares,
fromCache: false,
cachedAt: null,
}));
const result = await service.screen({
type: ScreenerType.SHARE,
priceMax: 300,
sortOrder: 'desc',
sortBy: 'price',
});
expect(result.items).toHaveLength(2);
expect(result.items[0].secid).toBe('SBER'); // 250
expect(result.items[1].secid).toBe('GAZP'); // 150
expect(result.total).toBe(2);
});
it('should paginate results', async () => {
const mockShares = Array.from({ length: 50 }, (_, i) => ({
secid: `TICKER${i}`,
last: i,
}));
vi.mocked(cache.getOrFetch).mockImplementation(async () => ({
data: mockShares,
fromCache: false,
cachedAt: null,
}));
const result = await service.screen({
type: ScreenerType.SHARE,
page: 2,
pageSize: 10,
});
expect(result.items).toHaveLength(10);
expect(result.page).toBe(2);
expect(result.totalPages).toBe(5);
});
});
});