You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

176 lines
5.3 KiB

import { PortfolioCalculator } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator';
import {
activityDummyData,
symbolProfileDummyData,
userDummyData
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
import { DEFAULT_CURRENCY } from '@ghostfolio/common/config';
import { Activity } from '@ghostfolio/common/interfaces';
import { RequestWithUser } from '@ghostfolio/common/types';
import { Type as ActivityType } from '@prisma/client';
import { Big } from 'big.js';
import { PortfolioService } from './portfolio.service';
describe('PortfolioService', () => {
describe('getSummary', () => {
beforeEach(() => {
jest.useFakeTimers().setSystemTime(new Date('2023-07-10'));
});
afterEach(() => {
jest.useRealTimers();
jest.restoreAllMocks();
});
it('returns annualizedDividendYield from the calculator snapshot', async () => {
const activities: Activity[] = [
{
...activityDummyData,
currency: 'USD',
date: new Date('2023-06-01'),
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 2,
SymbolProfile: {
...symbolProfileDummyData,
currency: 'USD',
dataSource: 'YAHOO',
name: 'Microsoft Inc.',
symbol: 'MSFT'
},
type: ActivityType.BUY,
unitPrice: 50,
unitPriceInAssetProfileCurrency: 50,
value: 100,
valueInBaseCurrency: 100
},
{
...activityDummyData,
currency: 'USD',
date: new Date('2023-06-02'),
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
currency: 'USD',
dataSource: 'YAHOO',
name: 'Microsoft Inc.',
symbol: 'MSFT'
},
type: ActivityType.SELL,
unitPrice: 40,
unitPriceInAssetProfileCurrency: 40,
value: 40,
valueInBaseCurrency: 40
}
];
const exchangeRateDataService = {
toCurrency: jest.fn((value: number) => value)
};
const orderService = {
getOrders: jest.fn().mockResolvedValue({ activities })
};
const userService = {
user: jest.fn().mockResolvedValue({
id: userDummyData.id,
settings: {
settings: {
baseCurrency: DEFAULT_CURRENCY,
emergencyFund: 0
}
}
})
};
const accountService = {
getCashDetails: jest.fn().mockResolvedValue({
balanceInBaseCurrency: 1000
})
};
const impersonationService = {
validateImpersonationId: jest.fn().mockResolvedValue(undefined)
};
const request = {
user: {
id: userDummyData.id,
settings: { settings: { baseCurrency: DEFAULT_CURRENCY } }
}
} as RequestWithUser;
const portfolioCalculator = {
getDividendInBaseCurrency: jest.fn().mockResolvedValue(new Big(12)),
getFeesInBaseCurrency: jest.fn().mockResolvedValue(new Big(4)),
getInterestInBaseCurrency: jest.fn().mockResolvedValue(new Big(1)),
getLiabilitiesInBaseCurrency: jest.fn().mockResolvedValue(new Big(6)),
getSnapshot: jest.fn().mockResolvedValue({
annualizedDividendYield: 0.0123,
currentValueInBaseCurrency: new Big(500),
totalInvestment: new Big(400)
}),
getStartDate: jest.fn().mockReturnValue(new Date('2023-01-01'))
} as unknown as PortfolioCalculator;
const service = new PortfolioService(
{} as any,
accountService as any,
{} as any,
{} as any,
{} as any,
exchangeRateDataService as any,
{} as any,
impersonationService as any,
orderService as any,
request,
{} as any,
{} as any,
userService as any
);
jest.spyOn(service, 'getPerformance').mockResolvedValue({
performance: {
netPerformance: 20,
netPerformancePercentage: 0.05,
netPerformancePercentageWithCurrencyEffect: 0.05,
netPerformanceWithCurrencyEffect: 20
}
} as any);
const summary = await (service as any).getSummary({
balanceInBaseCurrency: 1000,
emergencyFundHoldingsValueInBaseCurrency: 0,
filteredValueInBaseCurrency: new Big(200),
impersonationId: userDummyData.id,
portfolioCalculator,
userCurrency: DEFAULT_CURRENCY,
userId: userDummyData.id
});
expect(portfolioCalculator.getSnapshot).toHaveBeenCalledTimes(1);
expect(summary).toMatchObject({
annualizedDividendYield: 0.0123,
cash: 1000,
committedFunds: 60,
dividendInBaseCurrency: 12,
fees: 4,
grossPerformance: 24,
grossPerformanceWithCurrencyEffect: 24,
interestInBaseCurrency: 1,
liabilitiesInBaseCurrency: 6,
totalBuy: 100,
totalInvestment: 400,
totalSell: 40,
totalValueInBaseCurrency: 1494
});
expect(summary.activityCount).toBe(2);
expect(summary.dateOfFirstActivity).toEqual(new Date('2023-01-01'));
});
});
});