|
|
|
@ -1,7 +1,9 @@ |
|
|
|
import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; |
|
|
|
import { AssetProfileSplitService } from '@ghostfolio/api/services/asset-profile-split/asset-profile-split.service'; |
|
|
|
import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; |
|
|
|
|
|
|
|
import { NotFoundException } from '@nestjs/common'; |
|
|
|
import { EventEmitter2 } from '@nestjs/event-emitter'; |
|
|
|
import { AssetProfileSplit, DataSource } from '@prisma/client'; |
|
|
|
|
|
|
|
import { AssetProfilesService } from './asset-profiles.service'; |
|
|
|
@ -9,11 +11,15 @@ import { AssetProfilesService } from './asset-profiles.service'; |
|
|
|
describe('AssetProfilesService', () => { |
|
|
|
let assetProfilesService: AssetProfilesService; |
|
|
|
let deleteById: jest.Mock; |
|
|
|
let emit: jest.Mock; |
|
|
|
let findMany: jest.Mock; |
|
|
|
let gatherSymbol: jest.Mock; |
|
|
|
let upsert: jest.Mock; |
|
|
|
|
|
|
|
beforeEach(() => { |
|
|
|
deleteById = jest.fn(); |
|
|
|
emit = jest.fn(); |
|
|
|
findMany = jest.fn().mockResolvedValue([]); |
|
|
|
gatherSymbol = jest.fn(); |
|
|
|
upsert = jest.fn(); |
|
|
|
|
|
|
|
@ -28,8 +34,9 @@ describe('AssetProfilesService', () => { |
|
|
|
null, |
|
|
|
null, |
|
|
|
null, |
|
|
|
{ order: { findMany } } as never, |
|
|
|
null, |
|
|
|
null |
|
|
|
{ emit } as unknown as EventEmitter2 |
|
|
|
); |
|
|
|
}); |
|
|
|
|
|
|
|
@ -60,6 +67,48 @@ describe('AssetProfilesService', () => { |
|
|
|
}); |
|
|
|
expect(result).toBe(split); |
|
|
|
}); |
|
|
|
|
|
|
|
it('invalidates portfolio snapshots for users holding the asset', async () => { |
|
|
|
const split = {} as AssetProfileSplit; |
|
|
|
upsert.mockResolvedValue(split); |
|
|
|
findMany.mockResolvedValue([{ userId: 'user-1' }, { userId: 'user-2' }]); |
|
|
|
|
|
|
|
assetProfilesService = new AssetProfilesService( |
|
|
|
null, |
|
|
|
{ |
|
|
|
deleteById, |
|
|
|
upsert |
|
|
|
} as unknown as AssetProfileSplitService, |
|
|
|
null, |
|
|
|
{ gatherSymbol } as unknown as DataGatheringService, |
|
|
|
null, |
|
|
|
null, |
|
|
|
null, |
|
|
|
{ order: { findMany } } as never, |
|
|
|
null, |
|
|
|
{ emit } as unknown as EventEmitter2 |
|
|
|
); |
|
|
|
|
|
|
|
await assetProfilesService.createSplit({ |
|
|
|
dataSource: DataSource.YAHOO, |
|
|
|
date: new Date('2024-06-15T18:30:00.000Z'), |
|
|
|
denominator: 1, |
|
|
|
numerator: 2, |
|
|
|
symbol: 'AAPL', |
|
|
|
symbolProfileId: 'profile-id' |
|
|
|
}); |
|
|
|
|
|
|
|
expect(findMany).toHaveBeenCalledWith({ |
|
|
|
distinct: ['userId'], |
|
|
|
select: { userId: true }, |
|
|
|
where: { symbolProfileId: 'profile-id' } |
|
|
|
}); |
|
|
|
expect(emit.mock.calls.map(([, event]) => event.getUserId())).toEqual([ |
|
|
|
'user-1', |
|
|
|
'user-2' |
|
|
|
]); |
|
|
|
expect(emit.mock.calls[0][0]).toBe(PortfolioChangedEvent.getName()); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
describe('deleteSplit', () => { |
|
|
|
@ -72,10 +121,13 @@ describe('AssetProfilesService', () => { |
|
|
|
symbolProfileId: 'profile-id' |
|
|
|
}) |
|
|
|
).rejects.toBeInstanceOf(NotFoundException); |
|
|
|
|
|
|
|
expect(emit).not.toHaveBeenCalled(); |
|
|
|
}); |
|
|
|
|
|
|
|
it('deletes an existing split using its profile scope', async () => { |
|
|
|
deleteById.mockResolvedValue(true); |
|
|
|
findMany.mockResolvedValue([{ userId: 'user-1' }]); |
|
|
|
|
|
|
|
await expect( |
|
|
|
assetProfilesService.deleteSplit({ |
|
|
|
@ -88,6 +140,9 @@ describe('AssetProfilesService', () => { |
|
|
|
id: 'split-id', |
|
|
|
symbolProfileId: 'profile-id' |
|
|
|
}); |
|
|
|
expect(emit.mock.calls.map(([, event]) => event.getUserId())).toEqual([ |
|
|
|
'user-1' |
|
|
|
]); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|